Support generating proper Tiny Leaders decks

This commit is contained in:
drdev
2015-02-15 15:33:18 +00:00
parent e51a64242e
commit caf5817d0b
14 changed files with 127 additions and 55 deletions

View File

@@ -18,15 +18,18 @@
package forge.deck;
import forge.StaticData;
import forge.card.CardRules;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.deck.generation.DeckGenPool;
import forge.deck.generation.DeckGeneratorBase.FilterCMC;
import forge.deck.generation.IDeckGenPool;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.util.Aggregates;
import org.apache.commons.lang3.Range;
import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.base.Predicate;
@@ -45,7 +48,7 @@ public enum DeckFormat {
QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4),
Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
Commander ( Range.is(99), Range.between(0, 10), 1),
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<PaperCard>() {
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<CardRules>() {
private final HashSet<String> bannedCards = new HashSet<String>(Arrays.asList(
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
"Fastbond", "Flash", "Goblin Recruiter", "Hermit Druid", "Imperial Seal", "Jeweled Bird", "Karakas", "Library of Alexandria", "Mana Crypt", "Mana Drain", "Mana Vault", "Metalworker", "Mind Twist", "Mishra's Workshop", "Mox Emerald",
@@ -53,16 +56,32 @@ public enum DeckFormat {
"Timmerian Fiends", "Tolarian Academy", "Umezawa's Jitte", "Vampiric Tutor", "Wheel of Fortune", "Yawgmoth's Will"));
@Override
public boolean apply(PaperCard card) {
if (card.getRules().getManaCost().getCMC() > 3) {
public boolean apply(CardRules rules) {
if (rules.getManaCost().getCMC() > 3) {
return false; //only cards with CMC less than 3 are allowed
}
if (bannedCards.contains(card.getName())) {
if (bannedCards.contains(rules.getName())) {
return false;
}
return true;
}
}),
}) {
private final HashSet<String> bannedCommanders = new HashSet<String>(Arrays.asList(
"Derevi, Empyrial Tactician", "Erayo, Soratami Ascendant", "Rofellos, Llanowar Emissary"));
@Override
public boolean isLegalCommander(CardRules rules) {
return super.isLegalCommander(rules) && !bannedCommanders.contains(rules.getName());
}
@Override
public void adjustCMCLevels(List<ImmutablePair<FilterCMC, Integer>> cmcLevels) {
cmcLevels.clear();
cmcLevels.add(ImmutablePair.of(new FilterCMC(0, 1), 3));
cmcLevels.add(ImmutablePair.of(new FilterCMC(2, 2), 3));
cmcLevels.add(ImmutablePair.of(new FilterCMC(3, 3), 3));
}
},
PlanarConquest ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 1),
Vanguard ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
Planechase ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
@@ -71,12 +90,12 @@ public enum DeckFormat {
private final Range<Integer> mainRange;
private final Range<Integer> sideRange; // null => no check
private final int maxCardCopies;
private final Predicate<PaperCard> cardPoolFilter;
private final Predicate<CardRules> cardPoolFilter;
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0) {
this(mainRange0, sideRange0, maxCardCopies0, null);
}
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<PaperCard> cardPoolFilter0) {
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0) {
mainRange = mainRange0;
sideRange = sideRange0;
maxCardCopies = maxCardCopies0;
@@ -152,9 +171,8 @@ public enum DeckFormat {
if (cmd == null || cmd.isEmpty()) {
return "is missing a commander";
}
if (!cmd.get(0).getRules().getOracleText().contains("can be your commander")
&& (!cmd.get(0).getRules().getType().isLegendary() || !cmd.get(0).getRules().getType().isCreature())) {
return "has a commander that is not a legendary creature";
if (!isLegalCommander(cmd.get(0).getRules())) {
return "has an illegal commander";
}
ColorSet cmdCI = cmd.get(0).getRules().getColorIdentity();
@@ -187,12 +205,12 @@ public enum DeckFormat {
if (cardPoolFilter != null) {
List<PaperCard> erroneousCI = new ArrayList<PaperCard>();
for (Entry<PaperCard, Integer> cp : deck.getAllCardsInASinglePool()) {
if (!cardPoolFilter.apply(cp.getKey())) {
if (!cardPoolFilter.apply(cp.getKey().getRules())) {
erroneousCI.add(cp.getKey());
}
}
if (erroneousCI.size() > 0) {
StringBuilder sb = new StringBuilder("contains card that have CMC higher than 3:");
StringBuilder sb = new StringBuilder("contains the following illegal cards:\n");
for (PaperCard cp : erroneousCI) {
sb.append("\n").append(cp.getName());
@@ -275,11 +293,37 @@ public enum DeckFormat {
return null;
}
public IDeckGenPool getCardPool() {
IDeckGenPool pool = StaticData.instance().getCommonCards();
if (cardPoolFilter != null) {
pool = new DeckGenPool(pool.getAllCards(cardPoolFilter));
public IDeckGenPool getCardPool(IDeckGenPool basePool) {
if (cardPoolFilter == null) {
return basePool;
}
return pool;
DeckGenPool filteredPool = new DeckGenPool();
for (PaperCard pc : basePool.getAllCards()) {
if (cardPoolFilter.apply(pc.getRules())) {
filteredPool.add(pc);
}
}
return filteredPool;
}
public void adjustCMCLevels(List<ImmutablePair<FilterCMC, Integer>> cmcLevels) {
//not needed by default
}
public boolean isLegalCard(PaperCard pc) {
if (cardPoolFilter == null) {
return true;
}
return cardPoolFilter.apply(pc.getRules());
}
public boolean isLegalCommander(CardRules rules) {
if (cardPoolFilter != null && !cardPoolFilter.apply(rules)) {
return false;
}
if (rules.getType().isLegendary() && rules.getType().isCreature()) {
return true;
}
return rules.getOracleText().contains("can be your commander");
}
}

View File

@@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -42,7 +43,7 @@ public class DeckGenerator2Color extends DeckGeneratorBase {
@Override protected final float getSpellPercentage() { return 0.25f; }
@SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcRelativeWeights = Lists.newArrayList(
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
ImmutablePair.of(new FilterCMC(0, 2), 6),
ImmutablePair.of(new FilterCMC(3, 4), 4),
ImmutablePair.of(new FilterCMC(5, 6), 2),
@@ -56,11 +57,13 @@ public class DeckGenerator2Color extends DeckGeneratorBase {
// 4x 7 - 20
// = 52x - card pool (before further random filtering)
public DeckGenerator2Color(IDeckGenPool pool, final String clr1, final String clr2) {
super(pool);
public DeckGenerator2Color(IDeckGenPool pool0, DeckFormat format0, final String clr1, final String clr2) {
super(pool0, format0);
int c1 = MagicColor.fromName(clr1);
int c2 = MagicColor.fromName(clr2);
format0.adjustCMCLevels(cmcLevels);
if( c1 == 0 && c2 == 0) {
int color1 = r.nextInt(5);
int color2 = (color1 + 1 + r.nextInt(4)) % 5;
@@ -78,7 +81,7 @@ public class DeckGenerator2Color extends DeckGeneratorBase {
@Override
public final CardPool getDeck(final int size, final boolean forAi) {
addCreaturesAndSpells(size, cmcRelativeWeights, forAi);
addCreaturesAndSpells(size, cmcLevels, forAi);
// Add lands
int numLands = Math.round(size * getLandsPercentage());

View File

@@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import forge.util.MyRandom;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -44,8 +45,11 @@ public class DeckGenerator3Color extends DeckGeneratorBase {
ImmutablePair.of(new FilterCMC(6, 20), 3)
);
public DeckGenerator3Color(IDeckGenPool pool, final String clr1, final String clr2, final String clr3) {
super(pool);
public DeckGenerator3Color(IDeckGenPool pool0, DeckFormat format0, final String clr1, final String clr2, final String clr3) {
super(pool0, format0);
format0.adjustCMCLevels(cmcLevels);
int c1 = MagicColor.fromName(clr1);
int c2 = MagicColor.fromName(clr2);
int c3 = MagicColor.fromName(clr3);

View File

@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -51,8 +52,9 @@ public class DeckGenerator5Color extends DeckGeneratorBase {
/**
* Instantiates a new generate5 color deck.
*/
public DeckGenerator5Color(IDeckGenPool pool) {
super(pool);
public DeckGenerator5Color(IDeckGenPool pool0, DeckFormat format0) {
super(pool0, format0);
format0.adjustCMCLevels(cmcLevels);
colors = ColorSet.fromMask(0).inverse();
}

View File

@@ -21,13 +21,16 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.*;
import forge.card.mana.ManaCost;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.ItemPool;
import forge.util.MyRandom;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
@@ -50,6 +53,7 @@ public abstract class DeckGeneratorBase {
protected ColorSet colors;
protected final CardPool tDeck = new CardPool();
protected final IDeckGenPool pool;
protected final DeckFormat format;
// 2-colored deck generator has its own constants. The rest works fine with these ones
protected float getLandsPercentage() { return 0.44f; }
@@ -58,8 +62,9 @@ public abstract class DeckGeneratorBase {
StringBuilder tmpDeck = new StringBuilder();
public DeckGeneratorBase(IDeckGenPool pool0) {
pool = pool0;
public DeckGeneratorBase(IDeckGenPool pool0, DeckFormat format0) {
pool = format0.getCardPool(pool0);
format = format0;
}
public void setSingleton(boolean singleton){

View File

@@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -55,8 +56,8 @@ public class DeckGeneratorMonoColor extends DeckGeneratorBase {
// 4x 7 - 20
// = 52x - card pool (before further random filtering)
public DeckGeneratorMonoColor(IDeckGenPool pool, final String clr1) {
super(pool);
public DeckGeneratorMonoColor(IDeckGenPool pool0, DeckFormat format0, final String clr1) {
super(pool0, format0);
if (MagicColor.fromName(clr1) == 0) {
int color1 = r.nextInt(5);
colors = ColorSet.fromMask(MagicColor.WHITE << color1);

View File

@@ -11,6 +11,7 @@ import forge.card.CardRulesPredicates;
import forge.card.MagicColor;
import forge.deck.Deck;
import forge.deck.DeckBase;
import forge.deck.DeckFormat;
import forge.deck.generation.*;
import forge.gui.framework.ICDoc;
import forge.item.InventoryItem;
@@ -112,10 +113,10 @@ public enum CDeckgen implements ICDoc {
CardDb cardDb = FModel.getMagicDb().getCommonCards();
DeckGeneratorBase gen = null;
switch (colorCount0) {
case 1: gen = new DeckGeneratorMonoColor(cardDb, null); break;
case 2: gen = new DeckGenerator2Color(cardDb, null, null); break;
case 3: gen = new DeckGenerator3Color(cardDb, null, null, null); break;
case 5: gen = new DeckGenerator5Color(cardDb); break;
case 1: gen = new DeckGeneratorMonoColor(cardDb, DeckFormat.Constructed, null); break;
case 2: gen = new DeckGenerator2Color(cardDb, DeckFormat.Constructed, null, null); break;
case 3: gen = new DeckGenerator3Color(cardDb, DeckFormat.Constructed, null, null, null); break;
case 5: gen = new DeckGenerator5Color(cardDb, DeckFormat.Constructed); break;
}
if( null != gen ) {

View File

@@ -1,6 +1,7 @@
package forge.deck.generate;
import forge.card.CardDb;
import forge.deck.DeckFormat;
import forge.deck.generation.DeckGenerator2Color;
import forge.item.PaperCard;
import forge.model.FModel;
@@ -21,7 +22,7 @@ public class Generate2ColorDeckTest {
@Test(enabled = false)
public void generate2ColorDeckTest1() {
CardDb cardDb = FModel.getMagicDb().getCommonCards();
final DeckGenerator2Color gen = new DeckGenerator2Color(cardDb, "white", "blue");
final DeckGenerator2Color gen = new DeckGenerator2Color(cardDb, DeckFormat.Constructed, "white", "blue");
final ItemPool<PaperCard> cardList = gen.getDeck(60, false);
Assert.assertNotNull(cardList);
}

View File

@@ -2,6 +2,7 @@ package forge.deck.generate;
import forge.card.CardDb;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import forge.deck.generation.DeckGenerator3Color;
import forge.model.FModel;
@@ -20,7 +21,7 @@ public class Generate3ColorDeckTest {
@Test(timeOut = 1000, enabled = false)
public void generate3ColorDeckTest1() {
CardDb cardDb = FModel.getMagicDb().getCommonCards();
final DeckGenerator3Color gen = new DeckGenerator3Color(cardDb, "white", "blue", "black");
final DeckGenerator3Color gen = new DeckGenerator3Color(cardDb, DeckFormat.Constructed, "white", "blue", "black");
final CardPool cardList = gen.getDeck(60, false);
Assert.assertNotNull(cardList);
}

View File

@@ -2,6 +2,7 @@ package forge.deck.generate;
import forge.card.CardDb;
import forge.deck.CardPool;
import forge.deck.DeckFormat;
import forge.deck.generation.DeckGenerator5Color;
import forge.model.FModel;
@@ -20,7 +21,7 @@ public class Generate5ColorDeckTest {
@Test(timeOut = 1000, enabled = false)
public void generate5ColorDeckTest1() {
CardDb cardDb = FModel.getMagicDb().getCommonCards();
final DeckGenerator5Color gen = new DeckGenerator5Color(cardDb);
final DeckGenerator5Color gen = new DeckGenerator5Color(cardDb, DeckFormat.Constructed);
final CardPool cardList = gen.getDeck(60, false);
Assert.assertNotNull(cardList);
}

View File

@@ -47,8 +47,8 @@ public class DeckGeneratorTheme extends DeckGeneratorBase {
* Constructor for ThemeDeckGenerator.
* </p>
*/
public DeckGeneratorTheme(IDeckGenPool pool) {
super(pool);
public DeckGeneratorTheme(IDeckGenPool pool0) {
super(pool0, DeckFormat.Constructed);
this.maxDuplicates = 4;
}

View File

@@ -52,16 +52,16 @@ public class DeckgenUtil {
DeckGeneratorBase gen = null;
CardDb cardDb = FModel.getMagicDb().getCommonCards();
if (selection.size() == 1) {
gen = new DeckGeneratorMonoColor(cardDb, selection.get(0));
gen = new DeckGeneratorMonoColor(cardDb, DeckFormat.Constructed, selection.get(0));
}
else if (selection.size() == 2) {
gen = new DeckGenerator2Color(cardDb, selection.get(0), selection.get(1));
gen = new DeckGenerator2Color(cardDb, DeckFormat.Constructed, selection.get(0), selection.get(1));
}
else if (selection.size() == 3) {
gen = new DeckGenerator3Color(cardDb, selection.get(0), selection.get(1), selection.get(2));
gen = new DeckGenerator3Color(cardDb, DeckFormat.Constructed, selection.get(0), selection.get(1), selection.get(2));
}
else {
gen = new DeckGenerator5Color(cardDb);
gen = new DeckGenerator5Color(cardDb, DeckFormat.Constructed);
deckName = "5 colors";
}
gen.setSingleton(FModel.getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS));
@@ -278,16 +278,23 @@ public class DeckgenUtil {
/** Generate a 2-color Commander deck. */
public static Deck generateCommanderDeck(boolean forAi, GameType gameType) {
final Deck deck;
IDeckGenPool cardDb = gameType.getDeckFormat().getCardPool();
IDeckGenPool cardDb = FModel.getMagicDb().getCommonCards();
PaperCard commander;
ColorSet colorID;
// Get random multicolor Legendary creature
final DeckFormat format = gameType.getDeckFormat();
Predicate<CardRules> canPlay = forAi ? DeckGeneratorBase.AI_CAN_PLAY : DeckGeneratorBase.HUMAN_CAN_PLAY;
Iterable<PaperCard> legends = cardDb.getAllCards(Predicates.compose(Predicates.and
(CardRulesPredicates.Presets.IS_CREATURE, CardRulesPredicates.Presets.IS_LEGENDARY), PaperCard.FN_GET_RULES));
legends = Iterables.filter(legends, Predicates.compose(Predicates.and
(CardRulesPredicates.Presets.IS_MULTICOLOR, canPlay), PaperCard.FN_GET_RULES));
@SuppressWarnings("unchecked")
Iterable<PaperCard> legends = cardDb.getAllCards(Predicates.compose(Predicates.and(
new Predicate<CardRules>() {
@Override
public boolean apply(CardRules rules) {
return format.isLegalCommander(rules);
}
},
CardRulesPredicates.Presets.IS_MULTICOLOR,
canPlay), PaperCard.FN_GET_RULES));
do {
commander = Aggregates.random(legends);
@@ -302,7 +309,7 @@ public class DeckgenUtil {
if (colorID.hasGreen()) { comColors.add("Green"); }
DeckGeneratorBase gen = null;
gen = new DeckGenerator2Color(cardDb, comColors.get(0), comColors.get(1));
gen = new DeckGenerator2Color(cardDb, format, comColors.get(0), comColors.get(1));
gen.setSingleton(true);
gen.setUseArtifacts(!FModel.getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS));
CardPool cards = gen == null ? null : gen.getDeck(gameType.getDeckFormat().getMainRange().getMaximum(), forAi);

View File

@@ -10,6 +10,7 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckFormat;
import forge.deck.DeckSection;
import forge.deck.generation.DeckGeneratorBase;
import forge.item.IPaperCard;
@@ -54,7 +55,7 @@ public class LimitedDeckBuilder extends DeckGeneratorBase{
* Chosen colors.
*/
public LimitedDeckBuilder(List<PaperCard> dList, DeckColors pClrs) {
super(FModel.getMagicDb().getCommonCards());
super(FModel.getMagicDb().getCommonCards(), DeckFormat.Limited);
this.availableList = dList;
this.deckColors = pClrs;
this.colors = pClrs.getChosenColors();

View File

@@ -9,6 +9,7 @@ import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckFormat;
import forge.deck.DeckSection;
import forge.deck.generation.DeckGenerator2Color;
import forge.deck.generation.DeckGenerator3Color;
@@ -39,19 +40,19 @@ public class ConquestUtil {
DeckGeneratorBase gen;
switch (colors.size()) {
case 0:
gen = new DeckGeneratorMonoColor(pool, "");
gen = new DeckGeneratorMonoColor(pool, DeckFormat.PlanarConquest, "");
break;
case 1:
gen = new DeckGeneratorMonoColor(pool, colors.get(0));
gen = new DeckGeneratorMonoColor(pool, DeckFormat.PlanarConquest, colors.get(0));
break;
case 2:
gen = new DeckGenerator2Color(pool, colors.get(0), colors.get(1));
gen = new DeckGenerator2Color(pool, DeckFormat.PlanarConquest, colors.get(0), colors.get(1));
break;
case 3:
gen = new DeckGenerator3Color(pool, colors.get(0), colors.get(1), colors.get(2));
gen = new DeckGenerator3Color(pool, DeckFormat.PlanarConquest, colors.get(0), colors.get(1), colors.get(2));
break;
case 5:
gen = new DeckGenerator5Color(pool);
gen = new DeckGenerator5Color(pool, DeckFormat.PlanarConquest);
break;
default:
return null; //shouldn't happen