Refactor generation of boosters with a special uncommon/rare slot (e.g. WAR planeswalker slot)

This commit is contained in:
Alex W. Jackson 2021-11-11 08:48:50 -05:00
parent 387acbdbe9
commit 379550689f
7 changed files with 99 additions and 25 deletions

View file

@ -31,7 +31,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet {
this.numBoosterCommon = 10;
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.maxCardNumberInBooster = 275;
this.maxCardNumberInBooster = 281;
cards.add(new SetCardInfo("+2 Mace", 1, Rarity.COMMON, mage.cards.p.Plus2Mace.class));
cards.add(new SetCardInfo("Aberrant Mind Sorcerer", 44, Rarity.UNCOMMON, mage.cards.a.AberrantMindSorcerer.class));

View file

@ -4,8 +4,6 @@ import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType;
import java.util.List;
/**
* https://scryfall.com/sets/akr
*/

View file

@ -1,15 +1,20 @@
package mage.sets;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.collation.BoosterCollator;
import mage.collation.BoosterStructure;
import mage.collation.CardRun;
import mage.collation.RarityConfiguration;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.SetType;
import mage.constants.SuperType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -32,7 +37,9 @@ public final class Dominaria extends ExpansionSet {
this.numBoosterCommon = 10;
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
this.ratioBoosterMythic = 10;
this.ratioBoosterSpecialRare = 4;
this.ratioBoosterSpecialMythic = 5;
this.maxCardNumberInBooster = 269;
cards.add(new SetCardInfo("Academy Drake", 40, Rarity.COMMON, mage.cards.a.AcademyDrake.class));
@ -317,10 +324,22 @@ public final class Dominaria extends ExpansionSet {
cards.add(new SetCardInfo("Zhalfirin Void", 249, Rarity.UNCOMMON, mage.cards.z.ZhalfirinVoid.class));
}
// for sheet math reasons, four rare legendary creatures are collated as normal rares
// (a booster containing one of them will always contain an uncommon legend as well)
private static final List<String> nonSpecialLegends = Arrays.asList("Darigaaz Reincarnated", "Josu Vess, Lich Knight", "Muldrotha, the Gravetide", "Shalai, Voice of Plenty");
@Override
protected boolean boosterIsValid(List<Card> booster) {
return super.boosterIsValid(booster)
&& booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature());
protected List<CardInfo> findSpecialCardsByRarity(Rarity rarity) {
List<CardInfo> cardInfos = super.findSpecialCardsByRarity(rarity);
cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria()
.setCodes(this.code)
.rarities(rarity)
.supertypes(SuperType.LEGENDARY)
.types(CardType.CREATURE)));
cardInfos.removeIf(cardInfo -> (
cardInfo.getCardNumberAsInt() > maxCardNumberInBooster
|| nonSpecialLegends.contains(cardInfo.getName())));
return cardInfos;
}
@Override
@ -339,7 +358,6 @@ class DominariaCollator implements BoosterCollator {
private final CardRun uncommonA = new CardRun(true, "235", "119", "179", "145", "99", "38", "219", "175", "243", "33", "116", "210", "70", "160", "152", "81", "23", "235", "186", "242", "14", "130", "210", "54", "159", "121", "90", "38", "219", "180", "245", "23", "145", "179", "65", "186", "116", "82", "75", "121", "175", "99", "14", "119", "235", "70", "159", "130", "81", "54", "243", "160", "33", "82", "152", "210", "65", "180", "145", "90", "75", "242", "159", "99", "245", "116", "219", "70", "175", "119", "81", "65", "243", "186", "82", "38", "130", "235", "75", "160", "33", "121", "70", "152", "179", "90", "23", "145", "180", "54", "159", "116", "14", "65", "242", "179", "99", "38", "119", "210", "245", "180", "152", "23", "54", "243", "175", "90", "14", "130", "219", "242", "160", "121", "82", "75", "245", "186", "81", "33");
private final CardRun uncommonB = new CardRun(true, "231", "103", "188", "31", "64", "222", "249", "161", "28", "185", "150", "213", "97", "8", "181", "49", "220", "246", "188", "228", "56", "123", "218", "93", "185", "30", "74", "231", "244", "181", "31", "64", "128", "222", "107", "161", "137", "51", "213", "249", "103", "28", "49", "150", "220", "97", "188", "123", "56", "228", "137", "246", "30", "64", "244", "218", "107", "161", "128", "74", "213", "249", "93", "31", "51", "150", "222", "103", "185", "123", "56", "231", "97", "8", "220", "74", "137", "228", "107", "181", "150", "49", "218", "244", "93", "28", "51", "128", "213", "188", "8", "137", "64", "222", "246", "97", "30", "56", "31", "231", "103", "28", "123", "74", "220", "249", "161", "107", "246", "51", "228", "185", "8", "128", "49", "218", "244", "93", "30", "181");
private final CardRun uncommonLegend = new CardRun(true, "203", "109", "204", "66", "191", "4", "205", "111", "206", "12", "196", "165", "202", "69", "203", "113", "190", "109", "208", "25", "194", "148", "196", "12", "204", "66", "208", "111", "191", "165", "202", "4", "205", "113", "194", "148", "206", "25", "190", "69");
// Shalai (35), Josu Vess (95), Darigaaz (193) and Muldrotha (199) are on the non-legend sheet; boosters containing one of them will also contain an uncommon legend
private final CardRun rare = new CardRun(false, "6", "13", "18", "35", "39", "42", "55", "57", "61", "68", "88", "95", "98", "102", "114", "122", "129", "131", "133", "143", "147", "166", "173", "182", "183", "184", "187", "200", "201", "211", "214", "215", "217", "223", "233", "238", "239", "240", "241", "247", "248", "6", "13", "18", "35", "39", "42", "55", "57", "61", "68", "88", "95", "98", "102", "114", "122", "129", "131", "133", "143", "147", "166", "173", "182", "183", "184", "187", "200", "201", "211", "214", "215", "217", "223", "233", "238", "239", "240", "241", "247", "248", "1", "21", "100", "132", "193", "199", "207", "224", "237");
private final CardRun rareLegend = new CardRun(false, "16", "36", "58", "76", "96", "108", "146", "172", "192", "195", "198", "234", "16", "36", "58", "76", "96", "108", "146", "172", "192", "195", "198", "234", "26", "59", "86", "149", "174", "197");
private final CardRun land = new CardRun(false, "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269");

View file

@ -1,9 +1,12 @@
package mage.sets;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType;
import java.util.List;
/**
* @author TheElk801
*/
@ -25,7 +28,10 @@ public final class InnistradCrimsonVow extends ExpansionSet {
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
this.ratioBoosterSpecialRare = 5.5;
this.ratioBoosterSpecialMythic = 5.4; // 5 mythic DFCs, 11 rare DFCs
this.numBoosterDoubleFaced = 1;
this.maxCardNumberInBooster = 277;
cards.add(new SetCardInfo("Abrade", 139, Rarity.COMMON, mage.cards.a.Abrade.class));
cards.add(new SetCardInfo("Adamant Will", 1, Rarity.COMMON, mage.cards.a.AdamantWill.class));
@ -339,4 +345,10 @@ public final class InnistradCrimsonVow extends ExpansionSet {
cards.add(new SetCardInfo("Wrathful Jailbreaker", 184, Rarity.COMMON, mage.cards.w.WrathfulJailbreaker.class));
cards.add(new SetCardInfo("Wretched Throng", 91, Rarity.COMMON, mage.cards.w.WretchedThrong.class));
}
// add common double faced card to booster
@Override
protected void addDoubleFace(List<Card> booster) {
addToBooster(booster, getSpecialCardsByRarity(Rarity.COMMON));
}
}

View file

@ -1,5 +1,6 @@
package mage.sets;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.collation.BoosterCollator;
import mage.collation.BoosterStructure;
@ -32,7 +33,10 @@ public final class InnistradMidnightHunt extends ExpansionSet {
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
this.ratioBoosterSpecialRare = 5.5;
this.ratioBoosterSpecialMythic = 5.4; // 5 mythic DFCs, 11 rare DFCs
this.numBoosterDoubleFaced = 1;
this.maxCardNumberInBooster = 277;
cards.add(new SetCardInfo("Abandon the Post", 127, Rarity.COMMON, mage.cards.a.AbandonThePost.class));
cards.add(new SetCardInfo("Adeline, Resplendent Cathar", 1, Rarity.RARE, mage.cards.a.AdelineResplendentCathar.class, NON_FULL_USE_VARIOUS));
@ -506,6 +510,12 @@ public final class InnistradMidnightHunt extends ExpansionSet {
cards.add(new SetCardInfo("Wrenn and Seven", 278, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS));
}
// add common double faced card to booster
@Override
protected void addDoubleFace(List<Card> booster) {
addToBooster(booster, getSpecialCardsByRarity(Rarity.COMMON));
}
@Override
public BoosterCollator createCollator() {
return new InnistradMidnightHuntCollator();

View file

@ -1,12 +1,14 @@
package mage.sets;
import mage.MageObject;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.collation.BoosterCollator;
import mage.collation.BoosterStructure;
import mage.collation.CardRun;
import mage.collation.RarityConfiguration;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.SetType;
@ -29,7 +31,9 @@ public final class WarOfTheSpark extends ExpansionSet {
this.numBoosterCommon = 10;
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
this.ratioBoosterMythic = (40 + 40 + 12) / 12.0; // non-planeswalkers: 40 rares, 12 mythics
this.ratioBoosterSpecialRare = 4;
this.ratioBoosterSpecialMythic = (13 + 13 + 3) / 3.0; // planeswalkers: 13 rares, 3 mythics
this.maxCardNumberInBooster = 264;
cards.add(new SetCardInfo("Ahn-Crop Invader", 113, Rarity.COMMON, mage.cards.a.AhnCropInvader.class));
@ -346,9 +350,14 @@ public final class WarOfTheSpark extends ExpansionSet {
}
@Override
protected boolean boosterIsValid(List<Card> booster) {
return super.boosterIsValid(booster)
&& booster.stream().filter(MageObject::isPlaneswalker).count() == 1;
protected List<CardInfo> findSpecialCardsByRarity(Rarity rarity) {
List<CardInfo> cardInfos = super.findSpecialCardsByRarity(rarity);
cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria()
.setCodes(this.code)
.rarities(rarity)
.types(CardType.PLANESWALKER)));
cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > maxCardNumberInBooster);
return cardInfos;
}
@Override

View file

@ -115,9 +115,21 @@ public abstract class ExpansionSet implements Serializable {
protected int numBoosterSpecial;
protected int numBoosterLands;
protected int ratioBoosterSpecialLand = 0; // if > 0 basic lands are replaced with special land with probability ratioBoosterSpecialLandNumerator / ratioBoosterSpecialLand
// if ratioBoosterSpecialLand > 0, one basic land may be replaced with a special card
// with probability ratioBoosterSpecialLandNumerator / ratioBoosterSpecialLand
protected int ratioBoosterSpecialLand = 0;
protected int ratioBoosterSpecialLandNumerator = 1;
protected int ratioBoosterSpecialCommon = 0; // if > 0 one common is replaced with special card with probability 1 / ratioBoosterSpecialCommon
// if ratioBoosterSpecialCommon > 0, one common may be replaced with a special card
// with probability 1 / ratioBoosterSpecialCommon
protected int ratioBoosterSpecialCommon = 0;
// if ratioBoosterSpecialRare > 0, one uncommon or rare is always replaced with a special card
// probability that a rare rather than an uncommon is replaced is 1 / ratioBoosterSpecialRare
// probability that the replacement card for a rare is a mythic is 1 / ratioBoosterSpecialMythic
protected double ratioBoosterSpecialRare = 0;
protected double ratioBoosterSpecialMythic;
protected int numBoosterCommon;
protected int numBoosterUncommon;
@ -368,6 +380,10 @@ public abstract class ExpansionSet implements Serializable {
return ratioBoosterMythic > 0 && ratioBoosterMythic * RandomUtil.nextDouble() <= 1;
}
protected boolean checkSpecialMythic() {
return ratioBoosterSpecialMythic > 0 && ratioBoosterSpecialMythic * RandomUtil.nextDouble() <= 1;
}
public List<Card> tryBooster() {
List<Card> booster = new ArrayList<>();
if (!hasBoosters) {
@ -398,18 +414,29 @@ public abstract class ExpansionSet implements Serializable {
addToBooster(booster, commons);
}
int numUncommonsToGenerate = numBoosterUncommon;
int numRaresToGenerate = numBoosterRare;
if (ratioBoosterSpecialRare > 0) {
Rarity specialRarity = Rarity.UNCOMMON;
if (ratioBoosterSpecialRare * RandomUtil.nextDouble() <= 1) {
specialRarity = (checkSpecialMythic() ? Rarity.MYTHIC : Rarity.RARE);
--numRaresToGenerate;
} else {
--numUncommonsToGenerate;
}
addToBooster(booster, getSpecialCardsByRarity(specialRarity));
}
List<CardInfo> uncommons = getCardsByRarity(Rarity.UNCOMMON);
for (int i = 0; i < numBoosterUncommon; i++) {
for (int i = 0; i < numUncommonsToGenerate; i++) {
addToBooster(booster, uncommons);
}
List<CardInfo> rares = getCardsByRarity(Rarity.RARE);
List<CardInfo> mythics = getCardsByRarity(Rarity.MYTHIC);
for (int i = 0; i < numBoosterRare; i++) {
if (checkMythic()) {
addToBooster(booster, mythics);
} else {
addToBooster(booster, rares);
if (numRaresToGenerate > 0) {
List<CardInfo> rares = getCardsByRarity(Rarity.RARE);
List<CardInfo> mythics = getCardsByRarity(Rarity.MYTHIC);
for (int i = 0; i < numRaresToGenerate; i++) {
addToBooster(booster, checkMythic() ? mythics : rares);
}
}