diff --git a/.gitattributes b/.gitattributes index 0286cc96caf..f882ef5b3f9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11623,9 +11623,11 @@ src/main/java/forge/deck/DeckBase.java -text src/main/java/forge/deck/DeckGroup.java -text src/main/java/forge/deck/DeckRecognizer.java -text src/main/java/forge/deck/DeckSection.java -text +src/main/java/forge/deck/generate/CCnt.java -text src/main/java/forge/deck/generate/Generate2ColorDeck.java svneol=native#text/plain src/main/java/forge/deck/generate/Generate3ColorDeck.java svneol=native#text/plain src/main/java/forge/deck/generate/Generate5ColorDeck.java svneol=native#text/plain +src/main/java/forge/deck/generate/GenerateColoredDeckBase.java -text src/main/java/forge/deck/generate/GenerateDeckUtil.java -text src/main/java/forge/deck/generate/GenerateThemeDeck.java svneol=native#text/plain src/main/java/forge/deck/generate/package-info.java svneol=native#text/plain diff --git a/src/main/java/forge/card/CardColor.java b/src/main/java/forge/card/CardColor.java index b0a7e6b85dd..ba04c90d2e4 100644 --- a/src/main/java/forge/card/CardColor.java +++ b/src/main/java/forge/card/CardColor.java @@ -29,19 +29,10 @@ import forge.Constant; */ public final class CardColor implements Comparable { - /** The Constant WHITE. */ public static final byte WHITE = 1 << 1; - - /** The Constant BLUE. */ public static final byte BLUE = 1 << 2; - - /** The Constant BLACK. */ public static final byte BLACK = 1 << 3; - - /** The Constant RED. */ public static final byte RED = 1 << 4; - - /** The Constant GREEN. */ public static final byte GREEN = 1 << 5; private final byte myColor; @@ -56,8 +47,34 @@ public final class CardColor implements Comparable { * the mana */ public CardColor(final CardManaCost mana) { - this.myColor = mana.getColorProfile(); + this(mana.getColorProfile()); + } + + private CardColor(final byte mask) { + this.myColor = mask; this.orderWeight = this.getOrderWeight(); + + } + + public static CardColor fromMask(int mask) { + return new CardColor((byte)mask); + } + + public static CardColor fromNames(String... colors) { + byte mask = 0; + for(String s : colors) { + if ( s.equalsIgnoreCase(Constant.Color.WHITE) || s.equalsIgnoreCase("w")) + mask |= WHITE; + if ( s.equalsIgnoreCase(Constant.Color.BLUE) || s.equalsIgnoreCase("u")) + mask |= BLUE; + if ( s.equalsIgnoreCase(Constant.Color.BLACK) || s.equalsIgnoreCase("b")) + mask |= BLACK; + if ( s.equalsIgnoreCase(Constant.Color.RED) || s.equalsIgnoreCase("r")) + mask |= RED; + if ( s.equalsIgnoreCase(Constant.Color.GREEN) || s.equalsIgnoreCase("g")) + mask |= GREEN; + } + return fromMask(mask); } private CardColor() { @@ -66,7 +83,7 @@ public final class CardColor implements Comparable { } /** The null color. */ - private static CardColor nullColor = new CardColor(); + private static final CardColor nullColor = new CardColor(); /** * Checks for any color. @@ -75,7 +92,7 @@ public final class CardColor implements Comparable { * the colormask * @return true, if successful */ - public boolean hasAnyColor(final byte colormask) { + public boolean hasAnyColor(final int colormask) { return (this.myColor & colormask) != 0; } @@ -86,10 +103,21 @@ public final class CardColor implements Comparable { * the colormask * @return true, if successful */ - public boolean hasAllColors(final byte colormask) { + public boolean hasAllColors(final int colormask) { return (this.myColor & colormask) == colormask; } + /** this has no other colors except defined by operand */ + public boolean hasNoColorsExcept(final int colormask) { + return (this.myColor & ~colormask) == 0; + } + + + /** Operand has no other colors except defined by this */ + public boolean containsAllColorsFrom(int colorProfile) { + return (~this.myColor & colorProfile) == 0; + } + /** * Count colors. * @@ -254,6 +282,12 @@ public final class CardColor implements Comparable { return this.isEqual(CardColor.GREEN); } + public CardColor inverse() { + byte mask = this.myColor; + mask ^= ( WHITE | BLUE | BLACK | GREEN | RED ); + return fromMask(mask); + } + /* * (non-Javadoc) * @@ -291,16 +325,6 @@ public final class CardColor implements Comparable { return CardColor.nullColor; } - /** - * Sets the null color. - * - * @param nullColor0 - * the nullColor to set - */ - public static void setNullColor(final CardColor nullColor0) { - CardColor.nullColor = nullColor0; - } - /** * Shares color with. * @@ -308,27 +332,6 @@ public final class CardColor implements Comparable { * @return true, if successful */ public boolean sharesColorWith(CardColor ccOther) { - - if (this.isWhite() && ccOther.isWhite()) { - return true; - } - - if (this.isBlue() && ccOther.isBlue()) { - return true; - } - - if (this.isBlack() && ccOther.isBlack()) { - return true; - } - - if (this.isRed() && ccOther.isRed()) { - return true; - } - - if (this.isGreen() && ccOther.isGreen()) { - return true; - } - - return false; + return ( this.myColor & ccOther.myColor ) != 0; } } diff --git a/src/main/java/forge/card/CardManaCost.java b/src/main/java/forge/card/CardManaCost.java index cca77136ce3..d44c1ef5b23 100644 --- a/src/main/java/forge/card/CardManaCost.java +++ b/src/main/java/forge/card/CardManaCost.java @@ -22,6 +22,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import forge.card.cost.CostMana; + /** *

* CardManaCost class. @@ -40,14 +42,16 @@ public final class CardManaCost implements Comparable { private Float compareWeight = null; /** The Constant empty. */ - public static final CardManaCost EMPTY = new CardManaCost(); + public static final CardManaCost EMPTY = new CardManaCost(-1); + public static final CardManaCost ZERO = new CardManaCost(0); + public static final CardManaCost ONE = new CardManaCost(1); // pass mana cost parser here - private CardManaCost() { - this.hasNoCost = true; - this.genericCost = 0; - this.stringValue = ""; + private CardManaCost(int cmc) { + this.hasNoCost = cmc < 0; + this.genericCost = cmc < 0 ? 0 : cmc; this.shards = Collections.unmodifiableList(new ArrayList()); + this.stringValue = this.getSimpleString(); } // public ctor, should give it a mana parser @@ -208,4 +212,29 @@ public final class CardManaCost implements Comparable { int getTotalColorlessCost(); } + /** + * TODO: Write javadoc for this method. + * @return + */ + public boolean hasPhyrexian() { + for(CardManaCostShard shard : shards) { + if ( shard.isPhyrexian() ) + return true; + } + return false; + } + + /** + * TODO: Write javadoc for this method. + * @return + */ + public int countX() { + int iX = 0; + for(CardManaCostShard shard : shards) { + if ( shard == CardManaCostShard.X ) + iX++; + } + return iX; + } + } diff --git a/src/main/java/forge/card/CardManaCostShard.java b/src/main/java/forge/card/CardManaCostShard.java index 41876ad13de..2ab99cb8c27 100644 --- a/src/main/java/forge/card/CardManaCostShard.java +++ b/src/main/java/forge/card/CardManaCostShard.java @@ -317,4 +317,12 @@ public class CardManaCostShard { public String getImageKey() { return this.imageKey; } + + /** + * TODO: Write javadoc for this method. + * @return + */ + public boolean isPhyrexian() { + return (this.shard & Atom.OR_2_LIFE) != 0; + } } diff --git a/src/main/java/forge/card/CardRules.java b/src/main/java/forge/card/CardRules.java index 06a004015dd..8679ca61207 100644 --- a/src/main/java/forge/card/CardRules.java +++ b/src/main/java/forge/card/CardRules.java @@ -18,13 +18,12 @@ package forge.card; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; - - import org.apache.commons.lang3.StringUtils; import forge.util.Predicate; @@ -809,6 +808,12 @@ public final class CardRules { public static final Predicate IS_NON_CREATURE_SPELL = Predicate.compose(Presets.IS_CREATURE, PredicatesOp.NOR, Presets.IS_LAND); + @SuppressWarnings("unchecked") + public static final Predicate isNonCreatureSpellForGenerator = Predicate.or( Arrays.asList( + Presets.IS_SORCERY, Presets.IS_INSTANT, Presets.IS_PLANESWALKER, Presets.IS_ENCHANTMENT, + Predicate.compose(Presets.IS_ARTIFACT, PredicatesOp.GT, Presets.IS_CREATURE )) + ); + /** The Constant isWhite. */ public static final Predicate IS_WHITE = Predicates.isColor(CardColor.WHITE); diff --git a/src/main/java/forge/deck/generate/CCnt.java b/src/main/java/forge/deck/generate/CCnt.java new file mode 100644 index 00000000000..b80c5603d11 --- /dev/null +++ b/src/main/java/forge/deck/generate/CCnt.java @@ -0,0 +1,83 @@ +package forge.deck.generate; + +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + *

+ * CCnt class. + *

+ * + * @author Forge + * @version $Id: CCnt.java 12850 2011-12-26 14:55:09Z slapshot5 $ + */ +public class CCnt { + + /** The Color. */ + public final String Color; + + /** The Count. */ + private int count; + + /** + *

+ * Constructor for CCnt. + *

+ * + * @param clr + * a {@link java.lang.String} object. + * @param cnt + * a int. + */ + /** + *

+ * deckColors class. + *

+ * + * @param clr + * a {@link java.lang.String} object. + * @param cnt + * a int. + */ + public CCnt(final String clr, final int cnt) { + Color = clr; + this.setCount(cnt); + } + + /** + * Gets the count. + * + * @return the count + */ + public int getCount() { + return this.count; + } + + /** + * Sets the count. + * + * @param count0 + * the count to set + */ + public void setCount(final int count0) { + this.count = count0; + } + + public void increment() { this.count++; } + public void increment(int amount) { this.count += amount; } +} diff --git a/src/main/java/forge/deck/generate/Generate2ColorDeck.java b/src/main/java/forge/deck/generate/Generate2ColorDeck.java index 68494c20df7..433163cb9d1 100644 --- a/src/main/java/forge/deck/generate/Generate2ColorDeck.java +++ b/src/main/java/forge/deck/generate/Generate2ColorDeck.java @@ -17,23 +17,17 @@ */ package forge.deck.generate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import forge.AllZone; -import forge.Card; -import forge.CardList; -import forge.CardListFilter; -import forge.Constant; +import java.util.Arrays; +import java.util.List; import forge.PlayerType; -import forge.Singletons; +import forge.card.CardColor; +import forge.card.CardRules; +import forge.deck.generate.GenerateDeckUtil.FilterCMC; import forge.error.ErrorViewer; -import forge.properties.ForgePreferences.FPref; +import forge.item.CardPrinted; +import forge.item.ItemPool; +import forge.item.ItemPoolView; import forge.properties.ForgeProps; -import forge.util.MyRandom; -import forge.util.Predicate; /** *

@@ -43,15 +37,24 @@ import forge.util.Predicate; * @author Forge * @version $Id$ */ -public class Generate2ColorDeck { - private String color1 = ""; - private String color2 = ""; - private Random r = null; - private Map clrMap = null; - private ArrayList notColors = null; - private ArrayList dL = null; - private Map cardCounts = null; - private int maxDuplicates = 4; +public class Generate2ColorDeck extends GenerateColoredDeckBase { + final float landsPercentage = 0.42f; + final float creatPercentage = 0.34f; + final float spellPercentage = 0.24f; + + final List cmcLevels = Arrays.asList( + new GenerateDeckUtil.FilterCMC(0, 2), + new GenerateDeckUtil.FilterCMC(3, 4), + new GenerateDeckUtil.FilterCMC(5, 6), + new GenerateDeckUtil.FilterCMC(7, 20)); + final int[] cmcAmounts = {10, 8, 6, 2}; + + // mana curve of the card pool + // 20x 0 - 2 + // 16x 3 - 4 + // 12x 5 - 6 + // 4x 7 - 20 + // = 52x - card pool (before further random filtering) /** *

@@ -64,361 +67,58 @@ public class Generate2ColorDeck { * a {@link java.lang.String} object. */ public Generate2ColorDeck(final String clr1, final String clr2) { - this.r = MyRandom.getRandom(); - - this.cardCounts = new HashMap(); - - this.clrMap = new HashMap(); - this.clrMap.put("white", "W"); - this.clrMap.put("blue", "U"); - this.clrMap.put("black", "B"); - this.clrMap.put("red", "R"); - this.clrMap.put("green", "G"); - - this.notColors = new ArrayList(); - this.notColors.add("white"); - this.notColors.add("blue"); - this.notColors.add("black"); - this.notColors.add("red"); - this.notColors.add("green"); - - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) { - this.maxDuplicates = 1; - } - + if (clr1.equals("AI")) { - // choose first color - this.color1 = this.notColors.get(this.r.nextInt(5)); - - // choose second color - String c2 = this.notColors.get(this.r.nextInt(5)); - while (c2.equals(this.color1)) { - c2 = this.notColors.get(this.r.nextInt(5)); - } - this.color2 = c2; + int color1 = r.nextInt(5); + int color2 = ( color1 + 1 + r.nextInt(4) ) % 5 ; + colors = CardColor.fromMask(CardColor.WHITE << color1 | CardColor.WHITE << color2); } else { - this.color1 = clr1; - this.color2 = clr2; + colors = CardColor.fromNames(clr1, clr2); } - - this.notColors.remove(this.color1); - this.notColors.remove(this.color2); - - this.dL = GenerateDeckUtil.getDualLandList(this.clrMap.get(this.color1) + this.clrMap.get(this.color2)); - - for (int i = 0; i < this.dL.size(); i++) { - this.cardCounts.put(this.dL.get(i), 0); - } - } - /** - *

- * get2ColorDeck. - *

- * - * @param size - * a int. - * @param pt - * the pt - * @return a {@link forge.CardList} object. - */ - public final CardList get2ColorDeck(final int size, final PlayerType pt) { - int lc = 0; // loop counter to prevent infinite card selection loops - String tmpDeck = ""; - final CardList tDeck = new CardList(); - - final int landsPercentage = 42; - final int creatPercentage = 34; - final int spellPercentage = 24; - - // start with all cards - // remove cards that generated decks don't like - - Predicate toUse = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay; - CardList allCards = new CardList(toUse.select(AllZone.getCardFactory())); - - // reduce to cards that match the colors - CardList cl1 = allCards.getColor(this.color1); - if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) { - cl1.addAll(allCards.getColor(Constant.Color.COLORLESS)); - } - CardList cl2 = allCards.getColor(this.color2); - - // remove multicolor cards that don't match the colors - final CardListFilter clrF = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - for (int i = 0; i < Generate2ColorDeck.this.notColors.size(); i++) { - if (c.getManaCost().contains( - Generate2ColorDeck.this.clrMap.get(Generate2ColorDeck.this.notColors.get(i)))) { - return false; - } - } - return true; - } - }; - cl1 = cl1.filter(clrF); - cl2 = cl2.filter(clrF); + public final ItemPoolView get2ColorDeck(final int size, final PlayerType pt) { + List cards = selectCardsOfMatchingColorForPlayer(pt); // build subsets based on type - final CardList cr1 = cl1.getType("Creature"); - final CardList cr2 = cl2.getType("Creature"); + final List creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES); + final List spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES); - final String[] ise = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" }; - final CardList sp1 = cl1.getValidCards(ise, null, null); - final CardList sp2 = cl2.getValidCards(ise, null, null); - - // final card pools - final CardList cr12 = new CardList(); - final CardList sp12 = new CardList(); - - // used for mana curve in the card pool - final int[] minCMC = { 0 }; - final int[] maxCMC = { 2 }; - final CardListFilter cmcF = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - final int cCMC = c.getCMC(); - return (cCMC >= minCMC[0]) && (cCMC <= maxCMC[0]); - } - }; - - // select cards to build card pools using a mana curve - for (int i = 4; i > 0; i--) { - - if (i == 1) { - maxCMC[0] = 20; //the last category is open ended - i = 0; // this reduces the number of cards in the last category to 4 - } - final CardList cr1CMC = cr1.filter(cmcF); - final CardList cr2CMC = cr2.filter(cmcF); - final CardList sp1CMC = sp1.filter(cmcF); - final CardList sp2CMC = sp2.filter(cmcF); - - for (int j = 0; j < i + 1; j++) { - Card c = cr1CMC.get(this.r.nextInt(cr1CMC.size())); - cr12.add(c); - this.cardCounts.put(c.getName(), 0); - - c = cr2CMC.get(this.r.nextInt(cr2CMC.size())); - cr12.add(c); - this.cardCounts.put(c.getName(), 0); - - c = sp1CMC.get(this.r.nextInt(sp1CMC.size())); - sp12.add(c); - this.cardCounts.put(c.getName(), 0); - - c = sp2CMC.get(this.r.nextInt(sp2CMC.size())); - sp12.add(c); - this.cardCounts.put(c.getName(), 0); - } - - minCMC[0] += 2; - if (i == 4) { - minCMC[0] = 3; - } - maxCMC[0] += 2; - // resulting mana curve of the card pool - // 20x 0 - 2 - // 16x 3 - 4 - // 12x 5 - 6 - // 4x 7 - 20 - // =52x - card pool - } - - // shuffle card pools - cr12.shuffle(); - sp12.shuffle(); - - // calculate card counts - float p = (float) (creatPercentage * .01); - final int creatCnt = (int) (p * size); - tmpDeck += "Creature Count:" + creatCnt + "\n"; - - p = (float) (spellPercentage * .01); - final int spellCnt = (int) (p * size); - tmpDeck += "Spell Count:" + spellCnt + "\n"; - - // build deck from the card pools - for (int i = 0; i < creatCnt; i++) { - Card c = cr12.get(this.r.nextInt(cr12.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) { - c = cr12.get(this.r.nextInt(cr12.size())); - lc++; - } - if (lc > 100) { - throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Cr12"); - } - - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += c.getName() + " " + c.getManaCost() + "\n"; - } - - for (int i = 0; i < spellCnt; i++) { - Card c = sp12.get(this.r.nextInt(sp12.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) { - c = sp12.get(this.r.nextInt(sp12.size())); - lc++; - } - if (lc > 100) { - throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Sp12"); - } - - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += c.getName() + " " + c.getManaCost() + "\n"; - } + + final ItemPool tDeck = new ItemPool(CardPrinted.class); + + final int creatCnt = (int) (creatPercentage * size); + tmpDeck.append( "Creature Count:" + creatCnt + "\n" ); + addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts); + + final int spellCnt = (int) (spellPercentage * size); + tmpDeck.append( "Spell Count:" + spellCnt + "\n" ); + addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts); // Add lands - int numLands = 0; - if (landsPercentage > 0) { - p = (float) (landsPercentage * .01); - numLands = (int) (p * size); + int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll(); + + tmpDeck.append( "numLands:" + numLands + "\n"); + + // Add dual lands + + List duals = GenerateDeckUtil.getDualLandList(colors); + for(String s : duals) { + this.cardCounts.put(s, 0); } - /* - * else { // otherwise, just fill in the rest of the deck with basic // - * lands numLands = size - tDeck.size(); } - */ + + int dblsAdded = addSomeStr(tDeck, (numLands / 6), duals); + numLands -= dblsAdded; - tmpDeck += "numLands:" + numLands + "\n"; + addBasicLand(tDeck, numLands); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); - final int nDLands = (numLands / 6); - for (int i = 0; i < nDLands; i++) { - String s = this.dL.get(this.r.nextInt(this.dL.size())); - - lc = 0; - while ((this.cardCounts.get(s) > 3) || (lc > 20)) { - s = this.dL.get(this.r.nextInt(this.dL.size())); - lc++; - } - if (lc > 20) { - throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- DL"); - } - - tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer())); - final int n = this.cardCounts.get(s); - this.cardCounts.put(s, n + 1); - tmpDeck += s + "\n"; - } - - numLands -= nDLands; - - if (numLands > 0) { - // attempt to optimize basic land counts according to - // color representation - final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0), - new CCnt("Mountain", 0), new CCnt("Forest", 0) }; - - // count each card color using mana costs - // TODO count hybrid mana differently? - for (int i = 0; i < tDeck.size(); i++) { - final String mc = tDeck.get(i).getManaCost(); - - // count each mana symbol in the mana cost - for (int j = 0; j < mc.length(); j++) { - final char c = mc.charAt(j); - - if (c == 'W') { - clrCnts[0].count++; - } else if (c == 'U') { - clrCnts[1].count++; - } else if (c == 'B') { - clrCnts[2].count++; - } else if (c == 'R') { - clrCnts[3].count++; - } else if (c == 'G') { - clrCnts[4].count++; - } - } - } - - // total of all ClrCnts - int totalColor = 0; - for (int i = 0; i < 5; i++) { - totalColor += clrCnts[i].count; - tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n"; - } - - tmpDeck += "totalColor:" + totalColor + "\n"; - - for (int i = 0; i < 5; i++) { - if (clrCnts[i].count > 0) { // calculate number of lands for - // each color - p = (float) clrCnts[i].count / (float) totalColor; - final int nLand = (int) (numLands * p); - tmpDeck += "nLand-" + clrCnts[i].color + ":" + nLand + "\n"; - - // just to prevent a null exception by the deck size fixing - // code - this.cardCounts.put(clrCnts[i].color, nLand); - - for (int j = 0; j <= nLand; j++) { - tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer())); - } - } - } - } - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; - - // fix under-sized or over-sized decks, due to integer arithmetic - if (tDeck.size() < size) { - final int diff = size - tDeck.size(); - - for (int i = 0; i < diff; i++) { - Card c = tDeck.get(this.r.nextInt(tDeck.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > 3) || (lc > size)) { - c = tDeck.get(this.r.nextInt(tDeck.size())); - lc++; - } - if (lc > size) { - throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- undersize"); - } - - final int n = this.cardCounts.get(c.getName()); - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += "Added:" + c.getName() + "\n"; - } - } else if (tDeck.size() > size) { - final int diff = tDeck.size() - size; - - for (int i = 0; i < diff; i++) { - Card c = tDeck.get(this.r.nextInt(tDeck.size())); - - while (c.isBasicLand()) { // don't remove basic lands - c = tDeck.get(this.r.nextInt(tDeck.size())); - } - - tDeck.remove(c); - tmpDeck += "Removed:" + c.getName() + "\n"; - } - } - - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; + adjustDeckSize(tDeck, size); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); if (ForgeProps.getProperty("showdeck/2color", "false").equals("true")) { - ErrorViewer.showError(tmpDeck); + ErrorViewer.showError(tmpDeck.toString()); } return tDeck; } - - private class CCnt { - private final String color; - private int count; - - public CCnt(final String clr, final int cnt) { - this.color = clr; - this.count = cnt; - } - } } diff --git a/src/main/java/forge/deck/generate/Generate3ColorDeck.java b/src/main/java/forge/deck/generate/Generate3ColorDeck.java index f30d641362b..5ae00c9cece 100644 --- a/src/main/java/forge/deck/generate/Generate3ColorDeck.java +++ b/src/main/java/forge/deck/generate/Generate3ColorDeck.java @@ -17,23 +17,17 @@ */ package forge.deck.generate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import forge.AllZone; -import forge.Card; -import forge.CardList; -import forge.CardListFilter; -import forge.Constant; +import java.util.Arrays; +import java.util.List; import forge.PlayerType; -import forge.Singletons; +import forge.card.CardColor; +import forge.card.CardRules; +import forge.deck.generate.GenerateDeckUtil.FilterCMC; import forge.error.ErrorViewer; -import forge.properties.ForgePreferences.FPref; +import forge.item.CardPrinted; +import forge.item.ItemPool; +import forge.item.ItemPoolView; import forge.properties.ForgeProps; -import forge.util.MyRandom; -import forge.util.Predicate; /** *

@@ -43,17 +37,17 @@ import forge.util.Predicate; * @author Forge * @version $Id$ */ -public class Generate3ColorDeck { - private String color1 = ""; - private String color2 = ""; - private String color3 = ""; - private Random r = null; - private Map crMap = null; - private ArrayList notColors = null; - private ArrayList dL = null; - private Map cardCounts = null; - private int maxDuplicates = 4; +public class Generate3ColorDeck extends GenerateColoredDeckBase { + private final float landsPercentage = .44f; + private final float creatPercentage = .34f; + private final float spellPercentage = .22f; + final List cmcLevels = Arrays.asList( + new GenerateDeckUtil.FilterCMC(0, 2), + new GenerateDeckUtil.FilterCMC(3, 5), + new GenerateDeckUtil.FilterCMC(6, 20) ); + final int[] cmcAmounts = {12, 9, 3}; + /** *

* Constructor for Generate3ColorDeck. @@ -67,61 +61,13 @@ public class Generate3ColorDeck { * a {@link java.lang.String} object. */ public Generate3ColorDeck(final String clr1, final String clr2, final String clr3) { - this.r = MyRandom.getRandom(); - - this.cardCounts = new HashMap(); - - this.crMap = new HashMap(); - this.crMap.put("white", "W"); - this.crMap.put("blue", "U"); - this.crMap.put("black", "B"); - this.crMap.put("red", "R"); - this.crMap.put("green", "G"); - - this.notColors = new ArrayList(); - this.notColors.add("white"); - this.notColors.add("blue"); - this.notColors.add("black"); - this.notColors.add("red"); - this.notColors.add("green"); - - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) { - this.maxDuplicates = 1; - } - if (clr1.equals("AI")) { - // choose first color - this.color1 = this.notColors.get(this.r.nextInt(5)); - - // choose second color - String c2 = this.notColors.get(this.r.nextInt(5)); - while (c2.equals(this.color1)) { - c2 = this.notColors.get(this.r.nextInt(5)); - } - this.color2 = c2; - - String c3 = this.notColors.get(this.r.nextInt(5)); - while (c3.equals(this.color1) || c3.equals(this.color2)) { - c3 = this.notColors.get(this.r.nextInt(5)); - } - this.color3 = c3; + int color1 = r.nextInt(5); + int color2 = ( color1 + 1 + r.nextInt(4) ) % 5 ; + colors = CardColor.fromMask(CardColor.WHITE << color1 | CardColor.WHITE << color2).inverse(); } else { - this.color1 = clr1; - this.color2 = clr2; - this.color3 = clr3; + colors = CardColor.fromNames(clr1, clr2, clr3); } - - this.notColors.remove(this.color1); - this.notColors.remove(this.color2); - this.notColors.remove(this.color3); - - this.dL = GenerateDeckUtil.getDualLandList(this.crMap.get(this.color1) + this.crMap.get(this.color2) - + this.crMap.get(this.color3)); - - for (int i = 0; i < this.dL.size(); i++) { - this.cardCounts.put(this.dL.get(i), 0); - } - } /** @@ -135,312 +81,46 @@ public class Generate3ColorDeck { * the pt * @return a {@link forge.CardList} object. */ - public final CardList get3ColorDeck(final int size, final PlayerType pt) { - int lc = 0; // loop counter to prevent infinite card selection loops - String tmpDeck = ""; - final CardList tDeck = new CardList(); - - final int landsPercentage = 44; - final int creatPercentage = 34; - final int spellPercentage = 22; - - // start with all cards - // remove cards that generated decks don't like - Predicate toUse = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay; - CardList allCards = new CardList(toUse.select(AllZone.getCardFactory())); - - // reduce to cards that match the colors - CardList cl1 = allCards.getColor(this.color1); - if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) { - cl1.addAll(allCards.getColor(Constant.Color.COLORLESS)); - } - CardList cl2 = allCards.getColor(this.color2); - CardList cl3 = allCards.getColor(this.color3); - - // remove multicolor cards that don't match the colors - final CardListFilter clrF = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - for (int i = 0; i < Generate3ColorDeck.this.notColors.size(); i++) { - if (c.getManaCost().contains( - Generate3ColorDeck.this.crMap.get(Generate3ColorDeck.this.notColors.get(i)))) { - return false; - } - } - return true; - } - }; - cl1 = cl1.filter(clrF); - cl2 = cl2.filter(clrF); - cl3 = cl3.filter(clrF); - + public final ItemPoolView get3ColorDeck(final int size, final PlayerType pt) { + List cards = selectCardsOfMatchingColorForPlayer(pt); // build subsets based on type - final CardList cr1 = cl1.getType("Creature"); - final CardList cr2 = cl2.getType("Creature"); - final CardList cr3 = cl3.getType("Creature"); + final List creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES); + final List spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES); - final String[] ise = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" }; - final CardList sp1 = cl1.getValidCards(ise, null, null); - final CardList sp2 = cl2.getValidCards(ise, null, null); - final CardList sp3 = cl3.getValidCards(ise, null, null); - - // final card pools - final CardList cr123 = new CardList(); - final CardList sp123 = new CardList(); - - // used for mana curve in the card pool - final int[] minCMC = { 0 }; - final int[] maxCMC = { 2 }; - final CardListFilter cmcF = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - final int cCMC = c.getCMC(); - return (cCMC >= minCMC[0]) && (cCMC <= maxCMC[0]); - } - }; - - // select cards to build card pools using a mana curve - for (int i = 3; i > 0; i--) { - if (i == 1) { - maxCMC[0] = 20; //the last category is open ended - i = 0; // this reduces the number of cards in the last category to 6 - } - final CardList cr1CMC = cr1.filter(cmcF); - final CardList cr2CMC = cr2.filter(cmcF); - final CardList cr3CMC = cr3.filter(cmcF); - - final CardList sp1CMC = sp1.filter(cmcF); - final CardList sp2CMC = sp2.filter(cmcF); - final CardList sp3CMC = sp3.filter(cmcF); - - for (int j = 0; j < i + 1; j++) { - Card c = cr1CMC.get(this.r.nextInt(cr1CMC.size())); - cr123.add(c); - this.cardCounts.put(c.getName(), 0); - - c = cr2CMC.get(this.r.nextInt(cr2CMC.size())); - cr123.add(c); - this.cardCounts.put(c.getName(), 0); - - c = cr3CMC.get(this.r.nextInt(cr3CMC.size())); - cr123.add(c); - this.cardCounts.put(c.getName(), 0); - - c = sp1CMC.get(this.r.nextInt(sp1CMC.size())); - sp123.add(c); - this.cardCounts.put(c.getName(), 0); - - c = sp2CMC.get(this.r.nextInt(sp2CMC.size())); - sp123.add(c); - this.cardCounts.put(c.getName(), 0); - - c = sp3CMC.get(this.r.nextInt(sp3CMC.size())); - sp123.add(c); - this.cardCounts.put(c.getName(), 0); - } - - minCMC[0] += 3; - maxCMC[0] += 3; - // resulting mana curve of the card pool - // 24x 0 - 2 - // 18x 3 - 5 - // 6x 6 - 20 - // =58x - card pool - } - - // shuffle card pools - cr123.shuffle(); - sp123.shuffle(); - - // calculate card counts - float p = (float) (creatPercentage * .01); - final int creatCnt = (int) (p * size); - tmpDeck += "Creature Count:" + creatCnt + "\n"; - - p = (float) (spellPercentage * .01); - final int spellCnt = (int) (p * size); - tmpDeck += "Spell Count:" + spellCnt + "\n"; - - // build deck from the card pools - for (int i = 0; i < creatCnt; i++) { - Card c = cr123.get(this.r.nextInt(cr123.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) { - c = cr123.get(this.r.nextInt(cr123.size())); - lc++; - } - if (lc > 100) { - throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- Cr123"); - } - - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += c.getName() + " " + c.getManaCost() + "\n"; - } - - for (int i = 0; i < spellCnt; i++) { - Card c = sp123.get(this.r.nextInt(sp123.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) { - c = sp123.get(this.r.nextInt(sp123.size())); - lc++; - } - if (lc > 100) { - throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- Sp123"); - } - - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += c.getName() + " " + c.getManaCost() + "\n"; - } + + final ItemPool tDeck = new ItemPool(CardPrinted.class); + + final int creatCnt = (int) (creatPercentage * size); + tmpDeck.append( "Creature Count:" + creatCnt + "\n" ); + addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts); + + final int spellCnt = (int) (spellPercentage * size); + tmpDeck.append( "Spell Count:" + spellCnt + "\n" ); + addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts); // Add lands - int numLands = 0; - if (landsPercentage > 0) { - p = (float) (landsPercentage * .01); - numLands = (int) (p * size); + int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll(); + + tmpDeck.append( "numLands:" + numLands + "\n"); + + // Add dual lands + + List duals = GenerateDeckUtil.getDualLandList(colors); + for(String s : duals) { + this.cardCounts.put(s, 0); } - /* - * else { // otherwise, just fill in the rest of the deck with basic - * lands numLands = size - tDeck.size(); } - */ + int dblsAdded = addSomeStr(tDeck, (numLands / 4), duals); + numLands -= dblsAdded; - tmpDeck += "numLands:" + numLands + "\n"; + addBasicLand(tDeck, numLands); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); - final int ndLands = (numLands / 4); - for (int i = 0; i < ndLands; i++) { - String s = this.dL.get(this.r.nextInt(this.dL.size())); - - lc = 0; - while ((this.cardCounts.get(s) > 3) || (lc > 20)) { - s = this.dL.get(this.r.nextInt(this.dL.size())); - lc++; - } - if (lc > 20) { - throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- dL"); - } - - tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer())); - final int n = this.cardCounts.get(s); - this.cardCounts.put(s, n + 1); - tmpDeck += s + "\n"; - } - - numLands -= ndLands; - - if (numLands > 0) { - // attempt to optimize basic land counts according to - // color representation - final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0), - new CCnt("Mountain", 0), new CCnt("Forest", 0) }; - - // count each card color using mana costs - // TODO count hybrid mana differently? - for (int i = 0; i < tDeck.size(); i++) { - final String mc = tDeck.get(i).getManaCost(); - - // count each mana symbol in the mana cost - for (int j = 0; j < mc.length(); j++) { - final char c = mc.charAt(j); - - if (c == 'W') { - clrCnts[0].count++; - } else if (c == 'U') { - clrCnts[1].count++; - } else if (c == 'B') { - clrCnts[2].count++; - } else if (c == 'R') { - clrCnts[3].count++; - } else if (c == 'G') { - clrCnts[4].count++; - } - } - } - - // total of all ClrCnts - int totalColor = 0; - for (int i = 0; i < 5; i++) { - totalColor += clrCnts[i].count; - tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n"; - } - - tmpDeck += "totalColor:" + totalColor + "\n"; - - for (int i = 0; i < 5; i++) { - if (clrCnts[i].count > 0) { // calculate number of lands for - // each color - p = (float) clrCnts[i].count / (float) totalColor; - final int nLand = (int) (numLands * p); - tmpDeck += "nLand-" + clrCnts[i].color + ":" + nLand + "\n"; - - // just to prevent a null exception by the deck size fixing - // code - this.cardCounts.put(clrCnts[i].color, nLand); - - for (int j = 0; j <= nLand; j++) { - tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer())); - } - } - } - } - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; - - // fix under-sized or over-sized decks, due to integer arithmetic - if (tDeck.size() < size) { - final int diff = size - tDeck.size(); - - for (int i = 0; i < diff; i++) { - Card c = tDeck.get(this.r.nextInt(tDeck.size())); - - lc = 0; - while ((this.cardCounts.get(c.getName()) > 3) || (lc > size)) { - c = tDeck.get(this.r.nextInt(tDeck.size())); - lc++; - } - if (lc > size) { - throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- undersize"); - } - - final int n = this.cardCounts.get(c.getName()); - tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - this.cardCounts.put(c.getName(), n + 1); - tmpDeck += "Added:" + c.getName() + "\n"; - } - } else if (tDeck.size() > size) { - final int diff = tDeck.size() - size; - - for (int i = 0; i < diff; i++) { - Card c = tDeck.get(this.r.nextInt(tDeck.size())); - - while (c.isBasicLand()) { - // don't remove basic lands - c = tDeck.get(this.r.nextInt(tDeck.size())); - } - - tDeck.remove(c); - tmpDeck += "Removed:" + c.getName() + "\n"; - } - } - - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; + adjustDeckSize(tDeck, size); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); if (ForgeProps.getProperty("showdeck/3color", "false").equals("true")) { - ErrorViewer.showError(tmpDeck); + ErrorViewer.showError(tmpDeck.toString()); } return tDeck; } - - private class CCnt { - private final String color; - private int count; - - public CCnt(final String clr, final int cnt) { - this.color = clr; - this.count = cnt; - } - } } diff --git a/src/main/java/forge/deck/generate/Generate5ColorDeck.java b/src/main/java/forge/deck/generate/Generate5ColorDeck.java index a6dfd74fc39..273b611dec6 100644 --- a/src/main/java/forge/deck/generate/Generate5ColorDeck.java +++ b/src/main/java/forge/deck/generate/Generate5ColorDeck.java @@ -17,23 +17,17 @@ */ package forge.deck.generate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import forge.AllZone; -import forge.Card; -import forge.CardList; -import forge.CardListFilter; -import forge.Constant; +import java.util.Arrays; +import java.util.List; import forge.PlayerType; -import forge.Singletons; +import forge.card.CardColor; +import forge.card.CardRules; +import forge.deck.generate.GenerateDeckUtil.FilterCMC; import forge.error.ErrorViewer; +import forge.item.CardPrinted; +import forge.item.ItemPool; +import forge.item.ItemPoolView; import forge.properties.ForgeProps; -import forge.properties.ForgePreferences.FPref; -import forge.util.MyRandom; -import forge.util.Predicate; /** *

@@ -43,83 +37,28 @@ import forge.util.Predicate; * @author Forge * @version $Id$ */ -public class Generate5ColorDeck { - private String color1 = "white"; - private String color2 = "blue"; - private String color3 = "black"; - private String color4 = "red"; - private String color5 = "green"; - private Random r = null; - private Map colorMap = null; - private ArrayList notColors = null; - private ArrayList dualLands = null; - private Map cardCounts = null; - private int maxDuplicates = 4; +public class Generate5ColorDeck extends GenerateColoredDeckBase { + private final float landsPercentage = .44f; + private final float creatPercentage = .34f; + private final float spellPercentage = .22f; + final List cmcLevels = Arrays.asList( + new GenerateDeckUtil.FilterCMC(0, 2), + new GenerateDeckUtil.FilterCMC(3, 5), + new GenerateDeckUtil.FilterCMC(6, 20) ); + final int[] cmcAmounts = {15, 10, 5}; + + // resulting mana curve of the card pool + // 30x 0 - 2 + // 20x 3 - 5 + // 10x 6 - 20 + // =60x - card pool + /** * Instantiates a new generate5 color deck. */ public Generate5ColorDeck() { - this("white", "blue", "black", "red", "green"); - } - - /** - *

- * Constructor for Generate5ColorDeck. - *

- * - * @param color1 - * a {@link java.lang.String} object. - * @param color2 - * a {@link java.lang.String} object. - * @param color3 - * a {@link java.lang.String} object. - * @param color4 - * a {@link java.lang.String} object. - * @param color5 - * a {@link java.lang.String} object. - */ - public Generate5ColorDeck(final String color1, final String color2, final String color3, final String color4, - final String color5) { - this.r = MyRandom.getRandom(); - - this.cardCounts = new HashMap(); - - this.colorMap = new HashMap(); - this.colorMap.put("white", "W"); - this.colorMap.put("blue", "U"); - this.colorMap.put("black", "B"); - this.colorMap.put("red", "R"); - this.colorMap.put("green", "G"); - - this.notColors = new ArrayList(); - this.notColors.add("white"); - this.notColors.add("blue"); - this.notColors.add("black"); - this.notColors.add("red"); - this.notColors.add("green"); - - this.color1 = color1; - this.color2 = color2; - this.color3 = color3; - this.color4 = color4; - this.color5 = color5; - - this.notColors.remove(this.color1); - this.notColors.remove(this.color2); - this.notColors.remove(this.color3); - this.notColors.remove(this.color4); - this.notColors.remove(this.color5); - - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) { - this.maxDuplicates = 1; - } - - this.dualLands = GenerateDeckUtil.getDualLandList("WUBRG"); - - for (int i = 0; i < this.dualLands.size(); i++) { - this.cardCounts.put(this.dualLands.get(i), 0); - } + colors = CardColor.fromMask(0).inverse(); } /** @@ -133,362 +72,46 @@ public class Generate5ColorDeck { * a PlayerType * @return a {@link forge.CardList} object. */ - public final CardList get5ColorDeck(final int deckSize, final PlayerType playerType) { - int loopCounter = 0; // loop counter to prevent infinite card selection loops - String tmpDeckErrorMessage = ""; - final CardList tempDeck = new CardList(); - - final int landsPercentage = 44; - final int creaturePercentage = 34; - final int spellPercentage = 22; - - // start with all cards - // remove cards that generated decks don't like - Predicate toUse = playerType == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay; - CardList allCards = new CardList(toUse.select(AllZone.getCardFactory())); - - // reduce to cards that match the colors - CardList cardList1 = allCards.getColor(this.color1); - if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) { - cardList1.addAll(allCards.getColor(Constant.Color.COLORLESS)); - } - CardList cardList2 = allCards.getColor(this.color2); - CardList cardList3 = allCards.getColor(this.color3); - CardList cardList4 = allCards.getColor(this.color4); - CardList cardList5 = allCards.getColor(this.color5); - - // remove multicolor cards that don't match the colors - final CardListFilter cardListFilter = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - for (int i = 0; i < Generate5ColorDeck.this.notColors.size(); i++) { - if (c.getManaCost().contains( - Generate5ColorDeck.this.colorMap.get(Generate5ColorDeck.this.notColors.get(i)))) { - return false; - } - } - return true; - } - }; - cardList1 = cardList1.filter(cardListFilter); - cardList2 = cardList2.filter(cardListFilter); - cardList3 = cardList3.filter(cardListFilter); - cardList4 = cardList4.filter(cardListFilter); - cardList5 = cardList5.filter(cardListFilter); - + public final ItemPoolView get5ColorDeck(final int size, final PlayerType pt) { + List cards = selectCardsOfMatchingColorForPlayer(pt); // build subsets based on type - final CardList creatureCardList1 = cardList1.getType("Creature"); - final CardList creatureCardList2 = cardList2.getType("Creature"); - final CardList creatureCardList3 = cardList3.getType("Creature"); - final CardList creatureCardList4 = cardList4.getType("Creature"); - final CardList creatureCardList5 = cardList5.getType("Creature"); + final List creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES); + final List spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES); - final String[] nonCreatureSpells = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" }; - final CardList spellCardList1 = cardList1.getValidCards(nonCreatureSpells, null, null); - final CardList spellCardList2 = cardList2.getValidCards(nonCreatureSpells, null, null); - final CardList spellCardList3 = cardList3.getValidCards(nonCreatureSpells, null, null); - final CardList spellCardList4 = cardList4.getValidCards(nonCreatureSpells, null, null); - final CardList spellCardList5 = cardList5.getValidCards(nonCreatureSpells, null, null); - - // final card pools - final CardList creatures12345 = new CardList(); - final CardList spells12345 = new CardList(); - - // used for mana curve in the card pool - final int[] minConvertedManaCost = { 0 }; - final int[] maxConvertedManaCost = { 2 }; - final CardListFilter convertedManaCostFilter = new CardListFilter() { - @Override - public boolean addCard(final Card c) { - final int cardConvertedManaCost = c.getCMC(); - return (cardConvertedManaCost >= minConvertedManaCost[0]) && (cardConvertedManaCost <= maxConvertedManaCost[0]); - } - }; - - // select cards to build card pools using a mana curve - for (int i = 3; i > 0; i--) { - if (i == 1) { - maxConvertedManaCost[0] = 20; //the last category is open ended - } - final CardList creature1ConvertedManaCost = creatureCardList1.filter(convertedManaCostFilter); - final CardList creature2ConvertedManaCost = creatureCardList2.filter(convertedManaCostFilter); - final CardList creature3ConvertedManaCost = creatureCardList3.filter(convertedManaCostFilter); - final CardList creature4ConvertedManaCost = creatureCardList4.filter(convertedManaCostFilter); - final CardList creature5ConvertedManaCost = creatureCardList5.filter(convertedManaCostFilter); - - final CardList spell1ConvertedManaCost = spellCardList1.filter(convertedManaCostFilter); - final CardList spell2ConvertedManaCost = spellCardList2.filter(convertedManaCostFilter); - final CardList spell3ConvertedManaCost = spellCardList3.filter(convertedManaCostFilter); - final CardList spell4ConvertedManaCost = spellCardList4.filter(convertedManaCostFilter); - final CardList spell5ConvertedManaCost = spellCardList5.filter(convertedManaCostFilter); - - for (int j = 0; j < i; j++) { - Card c = creature1ConvertedManaCost.get(this.r.nextInt(creature1ConvertedManaCost.size())); - creatures12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = creature2ConvertedManaCost.get(this.r.nextInt(creature2ConvertedManaCost.size())); - creatures12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = creature3ConvertedManaCost.get(this.r.nextInt(creature3ConvertedManaCost.size())); - creatures12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = creature4ConvertedManaCost.get(this.r.nextInt(creature4ConvertedManaCost.size())); - creatures12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = creature5ConvertedManaCost.get(this.r.nextInt(creature5ConvertedManaCost.size())); - creatures12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = spell1ConvertedManaCost.get(this.r.nextInt(spell1ConvertedManaCost.size())); - spells12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = spell2ConvertedManaCost.get(this.r.nextInt(spell2ConvertedManaCost.size())); - spells12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = spell3ConvertedManaCost.get(this.r.nextInt(spell3ConvertedManaCost.size())); - spells12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = spell4ConvertedManaCost.get(this.r.nextInt(spell4ConvertedManaCost.size())); - spells12345.add(c); - this.cardCounts.put(c.getName(), 0); - - c = spell5ConvertedManaCost.get(this.r.nextInt(spell5ConvertedManaCost.size())); - spells12345.add(c); - this.cardCounts.put(c.getName(), 0); - } - - minConvertedManaCost[0] += 2; - maxConvertedManaCost[0] += 2; - // resulting mana curve of the card pool - // 30x 0 - 2 - // 20x 3 - 5 - // 10x 6 - 20 - // =60x - card pool - } - - // shuffle card pools - creatures12345.shuffle(); - spells12345.shuffle(); - - // calculate card counts - float p = (float) (creaturePercentage * .01); - final int creatureCount = (int) (p * deckSize); - tmpDeckErrorMessage += "Creature Count:" + creatureCount + "\n"; - - p = (float) (spellPercentage * .01); - final int spellCount = (int) (p * deckSize); - tmpDeckErrorMessage += "Spell Count:" + spellCount + "\n"; - - // build deck from the card pools - for (int i = 0; i < creatureCount; i++) { - Card c = creatures12345.get(this.r.nextInt(creatures12345.size())); - - loopCounter = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (loopCounter > 100)) { - c = creatures12345.get(this.r.nextInt(creatures12345.size())); - loopCounter++; - } - if (loopCounter > 100) { - throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- Cr123"); - } - - tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeckErrorMessage += c.getName() + " " + c.getManaCost() + "\n"; - } - - for (int i = 0; i < spellCount; i++) { - Card c = spells12345.get(this.r.nextInt(spells12345.size())); - - loopCounter = 0; - while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (loopCounter > 100)) { - c = spells12345.get(this.r.nextInt(spells12345.size())); - loopCounter++; - } - if (loopCounter > 100) { - throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- Sp123"); - } - - tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - final int n = this.cardCounts.get(c.getName()); - this.cardCounts.put(c.getName(), n + 1); - tmpDeckErrorMessage += c.getName() + " " + c.getManaCost() + "\n"; - } + + final ItemPool tDeck = new ItemPool(CardPrinted.class); + + final int creatCnt = (int) (creatPercentage * size); + tmpDeck.append( "Creature Count:" + creatCnt + "\n" ); + addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts); + + final int spellCnt = (int) (spellPercentage * size); + tmpDeck.append( "Spell Count:" + spellCnt + "\n" ); + addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts); // Add lands - int numberOfLands = 0; - if (landsPercentage > 0) { - p = (float) (landsPercentage * .01); - numberOfLands = (int) (p * deckSize); + int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll(); + + tmpDeck.append( "numLands:" + numLands + "\n"); + + // Add dual lands + + List duals = GenerateDeckUtil.getDualLandList(colors); + for(String s : duals) { + this.cardCounts.put(s, 0); } - /* - * else { // otherwise, just fill in the rest of the deck with basic // - * lands numLands = size - tDeck.size(); } - */ + int dblsAdded = addSomeStr(tDeck, (numLands / 4), duals); + numLands -= dblsAdded; - tmpDeckErrorMessage += "numLands:" + numberOfLands + "\n"; + addBasicLand(tDeck, numLands); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); - final int numberOfDualLands = (numberOfLands / 4); - for (int i = 0; i < numberOfDualLands; i++) { - String s = this.dualLands.get(this.r.nextInt(this.dualLands.size())); - - loopCounter = 0; - while ((this.cardCounts.get(s) > 3) || (loopCounter > 20)) { - s = this.dualLands.get(this.r.nextInt(this.dualLands.size())); - loopCounter++; - } - if (loopCounter > 20) { - throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- DL"); - } - - tempDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer())); - final int n = this.cardCounts.get(s); - this.cardCounts.put(s, n + 1); - tmpDeckErrorMessage += s + "\n"; - } - - numberOfLands -= numberOfDualLands; - - if (numberOfLands > 0) { - // attempt to optimize basic land counts according to - // color representation - final ColorCount[] colorCounts = { new ColorCount("Plains", 0), new ColorCount("Island", 0), new ColorCount("Swamp", 0), - new ColorCount("Mountain", 0), new ColorCount("Forest", 0) }; - - // count each card color using mana costs - // TODO: count hybrid mana differently? - for (int i = 0; i < tempDeck.size(); i++) { - final String mc = tempDeck.get(i).getManaCost(); - - // count each mana symbol in the mana cost - for (int j = 0; j < mc.length(); j++) { - final char c = mc.charAt(j); - - if (c == 'W') { - colorCounts[0].setCount(colorCounts[0].getCount() + 1); - } else if (c == 'U') { - colorCounts[1].setCount(colorCounts[1].getCount() + 1); - } else if (c == 'B') { - colorCounts[2].setCount(colorCounts[2].getCount() + 1); - } else if (c == 'R') { - colorCounts[3].setCount(colorCounts[3].getCount() + 1); - } else if (c == 'G') { - colorCounts[4].setCount(colorCounts[4].getCount() + 1); - } - } - } - - // total of all ColorCounts - int totalColor = 0; - for (int i = 0; i < 5; i++) { - totalColor += colorCounts[i].getCount(); - tmpDeckErrorMessage += colorCounts[i].getColor() + ":" + colorCounts[i].getCount() + "\n"; - } - - tmpDeckErrorMessage += "totalColor:" + totalColor + "\n"; - - for (int i = 0; i < 5; i++) { - if (colorCounts[i].getCount() > 0) { // calculate number of lands - // for each color - p = (float) colorCounts[i].getCount() / (float) totalColor; - final int nLand = (int) (numberOfLands * p); - tmpDeckErrorMessage += "nLand-" + colorCounts[i].getColor() + ":" + nLand + "\n"; - - // just to prevent a null exception by the deck size fixing - // code - this.cardCounts.put(colorCounts[i].getColor(), nLand); - - for (int j = 0; j <= nLand; j++) { - tempDeck.add(AllZone.getCardFactory().getCard(colorCounts[i].getColor(), AllZone.getComputerPlayer())); - } - } - } - } - tmpDeckErrorMessage += "DeckSize:" + tempDeck.size() + "\n"; - - // fix under-sized or over-sized decks, due to integer arithmetic - if (tempDeck.size() < deckSize) { - final int diff = deckSize - tempDeck.size(); - - for (int i = 0; i < diff; i++) { - Card c = tempDeck.get(this.r.nextInt(tempDeck.size())); - - loopCounter = 0; - while ((this.cardCounts.get(c.getName()) > 3) || (loopCounter > deckSize)) { - c = tempDeck.get(this.r.nextInt(tempDeck.size())); - loopCounter++; - } - if (loopCounter > deckSize) { - throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- undersize"); - } - - final int n = this.cardCounts.get(c.getName()); - tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer())); - this.cardCounts.put(c.getName(), n + 1); - tmpDeckErrorMessage += "Added:" + c.getName() + "\n"; - } - } else if (tempDeck.size() > deckSize) { - final int diff = tempDeck.size() - deckSize; - - for (int i = 0; i < diff; i++) { - Card c = tempDeck.get(this.r.nextInt(tempDeck.size())); - - while (c.isBasicLand()) { // don't remove basic lands - c = tempDeck.get(this.r.nextInt(tempDeck.size())); - } - - tempDeck.remove(c); - tmpDeckErrorMessage += "Removed:" + c.getName() + "\n"; - } - } - - tmpDeckErrorMessage += "DeckSize:" + tempDeck.size() + "\n"; + adjustDeckSize(tDeck, size); + tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" ); if (ForgeProps.getProperty("showdeck/5color", "false").equals("true")) { - ErrorViewer.showError(tmpDeckErrorMessage); + ErrorViewer.showError(tmpDeck.toString()); } - return tempDeck; - } - - private class ColorCount { - private final String color; - private int count; - - public ColorCount(final String color, final int count) { - this.color = color; - this.count = count; - } - - /** - * - * @return - */ - public String getColor() { - return this.color; - } - - /** - * - * @return - */ - public int getCount() { - return this.count; - } - - /** - * - * @param color - */ - public void setCount(final int count) { - this.count = count; - } + return tDeck; } } diff --git a/src/main/java/forge/deck/generate/GenerateColoredDeckBase.java b/src/main/java/forge/deck/generate/GenerateColoredDeckBase.java new file mode 100644 index 00000000000..135b24c0a05 --- /dev/null +++ b/src/main/java/forge/deck/generate/GenerateColoredDeckBase.java @@ -0,0 +1,225 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.deck.generate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; + +import com.google.common.base.Predicates; + +import forge.PlayerType; +import forge.Singletons; +import forge.card.CardColor; +import forge.card.CardRules; +import forge.deck.generate.GenerateDeckUtil.FilterCMC; +import forge.item.CardDb; +import forge.item.CardPrinted; +import forge.item.ItemPool; +import forge.properties.ForgePreferences.FPref; +import forge.util.MyRandom; +import forge.util.Predicate; + +/** + *

+ * Generate2ColorDeck class. + *

+ * + * @author Forge + * @version $Id: Generate2ColorDeck.java 14959 2012-03-28 14:03:43Z Chris H. $ + */ +public abstract class GenerateColoredDeckBase { + protected final Random r = MyRandom.getRandom(); + protected final Map cardCounts = new HashMap(); + protected final int maxDuplicates; + + protected CardColor colors; + + StringBuilder tmpDeck = new StringBuilder(); + +// protected final float landsPercentage = 0.42f; +// protected float creatPercentage = 0.34f; +// protected float spellPercentage = 0.24f; + /** + *

+ * Constructor for Generate2ColorDeck. + *

+ * + * @param clr1 + * a {@link java.lang.String} object. + * @param clr2 + * a {@link java.lang.String} object. + */ + public GenerateColoredDeckBase() { + this.maxDuplicates = Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS) ? 1 : 4; + } + + + + protected void addSome(ItemPool tDeck, int cnt, List source) { + for (int i = 0; i < cnt; i++) { + CardPrinted c; + int lc = 0; + do { + c = source.get(this.r.nextInt(source.size())); + lc++; + } while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)); + + if (lc > 100) { + throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Cr12"); + } + + tDeck.add(c); + final int n = this.cardCounts.get(c.getName()); + this.cardCounts.put(c.getName(), n + 1); + tmpDeck.append(c.getName() + " " + c.getCard().getManaCost() + "\n"); + } + } + + protected int addSomeStr(ItemPool tDeck, int cnt, List source) { + int res = 0; + for (int i = 0; i < cnt; i++) { + String s; + int lc = 0; + do { + s = source.get(this.r.nextInt(source.size())); + lc++; + } while ((this.cardCounts.get(s) > (this.maxDuplicates - 1)) || (lc > 20)); + // not an error if looped too much - could play singleton mode, with 6 slots for 3 non-basic lands. + + tDeck.add(CardDb.instance().getCard(s)); + final int n = this.cardCounts.get(s); + this.cardCounts.put(s, n + 1); + tmpDeck.append(s + "\n"); + } + return res; + } + + protected void addBasicLand(ItemPool tDeck, int cnt) { + // attempt to optimize basic land counts according to colors of picked cards + final CCnt[] clrCnts = countLands(tDeck); + // total of all ClrCnts + int totalColor = 0; + for (int i = 0; i < 5; i++) { + totalColor += clrCnts[i].getCount(); + tmpDeck.append( clrCnts[i].Color + ":" + clrCnts[i].getCount() + "\n"); + } + + tmpDeck.append( "totalColor:" + totalColor + "\n"); + + for (int i = 0; i < 5; i++) { + if (clrCnts[i].getCount() <= 0) continue; + + // calculate number of lands for each color + float p = (float) clrCnts[i].getCount() / (float) totalColor; + final int nLand = (int) (cnt * p); + tmpDeck.append( "nLand-" + clrCnts[i].Color + ":" + nLand + "\n"); + + // just to prevent a null exception by the deck size fixing + // code + this.cardCounts.put(clrCnts[i].Color, nLand); + + for (int j = 0; j <= nLand; j++) { + tDeck.add(CardDb.instance().getCard(clrCnts[i].Color)); + } + } + } + + protected void adjustDeckSize(ItemPool tDeck, int targetSize) { + // fix under-sized or over-sized decks, due to integer arithmetic + int actualSize = tDeck.countAll(); + if (actualSize < targetSize) { + final int diff = targetSize - actualSize; + addSome(tDeck, diff, tDeck.toFlatList()); + } else if (actualSize > targetSize) { + + Predicate exceptBasicLand = Predicate.not(CardRules.Predicates.Presets.IS_BASIC_LAND); + + for( int i = 0; i < 3 && actualSize > targetSize; i++ ) { + List toRemove = exceptBasicLand.random(tDeck.toFlatList(), CardPrinted.FN_GET_RULES, actualSize - targetSize); + tDeck.removeAllFlat(toRemove); + + for(CardPrinted c: toRemove) + tmpDeck.append( "Removed:" + c.getName() + "\n" ); + + actualSize = tDeck.countAll(); + } + } + } + + + protected void addCmcAdjusted(ItemPool tDeck, List source, int cnt, List cmcLevels, int[] cmcAmounts) { + final List curved = new ArrayList(); + + + for(int i = 0; i < cmcAmounts.length; i++){ + curved.addAll(cmcLevels.get(i).random(source, CardPrinted.FN_GET_RULES, cmcAmounts[i])); + } + + for(CardPrinted c: curved) + this.cardCounts.put(c.getName(), 0); + + addSome(tDeck, cnt, curved); + } + + protected List selectCardsOfMatchingColorForPlayer(PlayerType pt) + { + // start with all cards + // remove cards that generated decks don't like + Predicate canPlay = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay; + Predicate hasColor = new GenerateDeckUtil.ContainsAllColorsFrom(colors); + + if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) { + hasColor = Predicate.or( hasColor, GenerateDeckUtil.colorlessCards ); + } + + return Predicate.and(canPlay, hasColor).select(CardDb.instance().getAllCards(), CardPrinted.FN_GET_RULES); + + } + + protected static CCnt[] countLands(ItemPool outList) { + // attempt to optimize basic land counts according + // to color representation + final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0), + new CCnt("Mountain", 0), new CCnt("Forest", 0) }; + + // count each card color using mana costs + // TODO: count hybrid mana differently? + for( Entry cpe : outList) + { + int profile = cpe.getKey().getCard().getManaCost().getColorProfile(); + + if ((profile & CardColor.WHITE) != 0 ) { + clrCnts[0].increment(cpe.getValue()); + } else if ((profile & CardColor.BLUE) != 0 ) { + clrCnts[1].increment(cpe.getValue()); + } else if ((profile & CardColor.BLACK) != 0 ) { + clrCnts[2].increment(cpe.getValue()); + } else if ((profile & CardColor.RED) != 0 ) { + clrCnts[3].increment(cpe.getValue()); + } else if ((profile & CardColor.GREEN) != 0 ) { + clrCnts[4].increment(cpe.getValue()); + } + + } + return clrCnts; + } +} diff --git a/src/main/java/forge/deck/generate/GenerateDeckUtil.java b/src/main/java/forge/deck/generate/GenerateDeckUtil.java index 8054a27ca7f..50791e2d7c1 100644 --- a/src/main/java/forge/deck/generate/GenerateDeckUtil.java +++ b/src/main/java/forge/deck/generate/GenerateDeckUtil.java @@ -18,8 +18,16 @@ package forge.deck.generate; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import forge.Card; +import forge.card.CardColor; +import forge.card.CardManaCost; +import forge.card.CardRules; +import forge.item.CardPrinted; import forge.util.Predicate; /** @@ -32,99 +40,91 @@ import forge.util.Predicate; */ public class GenerateDeckUtil { - public static final Predicate aiCanPlay = new Predicate() { + public static final Predicate aiCanPlay = new Predicate() { @Override - public boolean isTrue(Card c) { - return !c.getSVar("RemRandomDeck").equals("True") && !c.getSVar("RemAIDeck").equals("True"); + public boolean isTrue(CardRules c) { + return !c.getRemAIDecks() && c.getRemRandomDecks(); } }; - public static final Predicate humanCanPlay = new Predicate() { + public static final Predicate humanCanPlay = new Predicate() { @Override - public boolean isTrue(Card c) { - return !c.getSVar("RemRandomDeck").equals("True"); + public boolean isTrue(CardRules c) { + return !c.getRemRandomDecks(); } }; - /** - * - * Arrays of dual and tri-land cards. - * - * @param colors - * a String - * @return ArrayList - */ - public static ArrayList getDualLandList(final String colors) { - final ArrayList dLands = new ArrayList(); + public static final Predicate colorlessCards = new Predicate() { + @Override + public boolean isTrue(CardRules c) { + CardManaCost mc = c.getManaCost(); + return mc.getColorProfile() == 0 && !mc.isEmpty(); + } + }; + + public static class ContainsAllColorsFrom extends Predicate { + private final CardColor allowedColor; + public ContainsAllColorsFrom(CardColor color) { + allowedColor = color; + } - if (colors.length() > 3) { + @Override + public boolean isTrue(CardRules subject) { + return allowedColor.containsAllColorsFrom(subject.getManaCost().getColorProfile()); + } + } + + public static class FilterCMC extends Predicate { + private final int min; + private final int max; + + public FilterCMC(int from, int to) { + min = from; max = to; + } + + @Override + public boolean isTrue(CardRules c) { + CardManaCost mc = c.getManaCost(); + int cmc = mc.getCMC(); + return cmc >= min && cmc <= max && !mc.isEmpty(); + } + } + + private static Map dualLands = new HashMap(); + static { + dualLands.put(CardColor.WHITE | CardColor.BLUE, new String[]{"Tundra", "Hallowed Fountain", "Flooded Strand"}); + dualLands.put(CardColor.BLACK | CardColor.BLUE, new String[]{"Underground Sea", "Watery Grave", "Polluted Delta"}); + dualLands.put(CardColor.BLACK | CardColor.RED, new String[]{"Badlands", "Blood Crypt", "Bloodstained Mire"}); + dualLands.put(CardColor.GREEN | CardColor.RED, new String[]{"Taiga", "Stomping Ground", "Wooded Foothills"}); + dualLands.put(CardColor.GREEN | CardColor.WHITE, new String[]{"Savannah", "Temple Garden", "Windswept Heath"}); + + dualLands.put(CardColor.WHITE | CardColor.BLACK, new String[]{"Scrubland", "Godless Shrine", "Marsh Flats"}); + dualLands.put(CardColor.BLUE | CardColor.RED, new String[]{"Volcanic Island", "Steam Vents", "Scalding Tarn"}); + dualLands.put(CardColor.BLACK | CardColor.GREEN, new String[]{"Bayou", "Overgrown Tomb", "Verdant Catacombs"}); + dualLands.put(CardColor.WHITE | CardColor.RED, new String[]{"Plateau","Sacred Foundry","Arid Mesa"}); + dualLands.put(CardColor.GREEN | CardColor.BLUE, new String[]{"Tropical Island", "Breeding Pool", "Misty Rainforest"}); + } + + + + public static List getDualLandList(final CardColor color) { + + final List dLands = new ArrayList(); + + if (color.countColors() > 3) { dLands.add("Rupture Spire"); dLands.add("Undiscovered Paradise"); } - if (colors.length() > 2) { + if (color.countColors() > 2) { dLands.add("Evolving Wilds"); dLands.add("Terramorphic Expanse"); } - - if (colors.contains("W") && colors.contains("U")) { - dLands.add("Tundra"); - dLands.add("Hallowed Fountain"); - dLands.add("Flooded Strand"); - } - - if (colors.contains("U") && colors.contains("B")) { - dLands.add("Underground Sea"); - dLands.add("Watery Grave"); - dLands.add("Polluted Delta"); - } - - if (colors.contains("B") && colors.contains("R")) { - dLands.add("Badlands"); - dLands.add("Blood Crypt"); - dLands.add("Bloodstained Mire"); - } - - if (colors.contains("R") && colors.contains("G")) { - dLands.add("Taiga"); - dLands.add("Stomping Ground"); - dLands.add("Wooded Foothills"); - } - - if (colors.contains("G") && colors.contains("W")) { - dLands.add("Savannah"); - dLands.add("Temple Garden"); - dLands.add("Windswept Heath"); - } - - if (colors.contains("W") && colors.contains("B")) { - dLands.add("Scrubland"); - dLands.add("Godless Shrine"); - dLands.add("Marsh Flats"); - } - - if (colors.contains("U") && colors.contains("R")) { - dLands.add("Volcanic Island"); - dLands.add("Steam Vents"); - dLands.add("Scalding Tarn"); - } - - if (colors.contains("B") && colors.contains("G")) { - dLands.add("Bayou"); - dLands.add("Overgrown Tomb"); - dLands.add("Verdant Catacombs"); - } - - if (colors.contains("R") && colors.contains("W")) { - dLands.add("Plateau"); - dLands.add("Sacred Foundry"); - dLands.add("Arid Mesa"); - } - - if (colors.contains("G") && colors.contains("U")) { - dLands.add("Tropical Island"); - dLands.add("Breeding Pool"); - dLands.add("Misty Rainforest"); + for(Entry dual : dualLands.entrySet()) { + if( color.hasAllColors(dual.getKey()) ) { + for(String s : dual.getValue()) + dLands.add(s); + } } return dLands; diff --git a/src/main/java/forge/deck/generate/GenerateThemeDeck.java b/src/main/java/forge/deck/generate/GenerateThemeDeck.java index 8b5ac353748..46aab5286fb 100644 --- a/src/main/java/forge/deck/generate/GenerateThemeDeck.java +++ b/src/main/java/forge/deck/generate/GenerateThemeDeck.java @@ -26,10 +26,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; -import forge.AllZone; -import forge.Card; -import forge.CardList; import forge.error.ErrorViewer; +import forge.item.CardDb; +import forge.item.CardPrinted; +import forge.item.ItemPool; +import forge.item.ItemPoolView; import forge.util.MyRandom; /** @@ -40,7 +41,7 @@ import forge.util.MyRandom; * @author Forge * @version $Id$ */ -public class GenerateThemeDeck { +public class GenerateThemeDeck extends GenerateColoredDeckBase{ private BufferedReader in = null; /** @@ -95,8 +96,8 @@ public class GenerateThemeDeck { * a int. * @return a {@link forge.CardList} object. */ - public final CardList getThemeDeck(final String themeName, final int size) { - final CardList tDeck = new CardList(); + public final ItemPoolView getThemeDeck(final String themeName, final int size) { + final ItemPool tDeck = new ItemPool(CardPrinted.class); final ArrayList groups = new ArrayList(); @@ -197,7 +198,7 @@ public class GenerateThemeDeck { } final int n = cardCounts.get(s); - tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer())); + tDeck.add(CardDb.instance().getCard(s)); cardCounts.put(s, n + 1); tmpDeck += s + "\n"; @@ -210,94 +211,18 @@ public class GenerateThemeDeck { numBLands = (int) (p * size); } else { // otherwise, just fill in the rest of the deck with basic // lands - numBLands = size - tDeck.size(); + numBLands = size - tDeck.countAll(); } tmpDeck += "numBLands:" + numBLands + "\n"; - if (numBLands > 0) { - // attempt to optimize basic land counts according to - // color representation - final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0), - new CCnt("Mountain", 0), new CCnt("Forest", 0) }; + addBasicLand(tDeck, numBLands); + + tmpDeck += "DeckSize:" + tDeck.countAll() + "\n"; - // count each instance of a color in mana costs - // TODO count hybrid mana differently? - for (int i = 0; i < tDeck.size(); i++) { - final String mc = tDeck.get(i).getManaCost(); + adjustDeckSize(tDeck, size); - for (int j = 0; j < mc.length(); j++) { - final char c = mc.charAt(j); - - if (c == 'W') { - clrCnts[0].count++; - } else if (c == 'U') { - clrCnts[1].count++; - } else if (c == 'B') { - clrCnts[2].count++; - } else if (c == 'R') { - clrCnts[3].count++; - } else if (c == 'G') { - clrCnts[4].count++; - } - } - } - - int totalColor = 0; - for (int i = 0; i < 5; i++) { - totalColor += clrCnts[i].count; - tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n"; - } - - tmpDeck += "totalColor:" + totalColor + "\n"; - - for (int i = 0; i < 5; i++) { - if (clrCnts[i].count > 0) { // calculate number of lands for - // each color - final float p = (float) clrCnts[i].count / (float) totalColor; - final int nLand = (int) (numBLands * p); - tmpDeck += "numLand-" + clrCnts[i].color + ":" + nLand + "\n"; - - cardCounts.put(clrCnts[i].color, 2); - for (int j = 0; j < nLand; j++) { - tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer())); - } - } - } - } - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; - - if (tDeck.size() < size) { - final int diff = size - tDeck.size(); - - for (int i = 0; i < diff; i++) { - s = tDeck.get(r.nextInt(tDeck.size())).getName(); - - while (cardCounts.get(s) >= 4) { - s = tDeck.get(r.nextInt(tDeck.size())).getName(); - } - - final int n = cardCounts.get(s); - tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer())); - cardCounts.put(s, n + 1); - tmpDeck += "Added:" + s + "\n"; - } - } else if (tDeck.size() > size) { - final int diff = tDeck.size() - size; - - for (int i = 0; i < diff; i++) { - Card c = tDeck.get(r.nextInt(tDeck.size())); - - while (c.isBasicLand()) { - c = tDeck.get(r.nextInt(tDeck.size())); - } - - tDeck.remove(c); - tmpDeck += "Removed:" + s + "\n"; - } - } - - tmpDeck += "DeckSize:" + tDeck.size() + "\n"; + tmpDeck += "DeckSize:" + tDeck.countAll() + "\n"; if (testing) { ErrorViewer.showError(tmpDeck); } @@ -326,28 +251,6 @@ public class GenerateThemeDeck { } } // readLine(Card) - private class CCnt { - - /** The Color. */ - private final String color; - - /** The Count. */ - private int count; - - /** - * Instantiates a new c cnt. - * - * @param clr - * the clr - * @param cnt - * the cnt - */ - public CCnt(final String clr, final int cnt) { - this.color = clr; - this.count = cnt; - } - } - private class Grp { /** The Cardnames. */ diff --git a/src/main/java/forge/gui/deckeditor/MenuCommon.java b/src/main/java/forge/gui/deckeditor/MenuCommon.java index 498545b1430..b61f6f139d1 100644 --- a/src/main/java/forge/gui/deckeditor/MenuCommon.java +++ b/src/main/java/forge/gui/deckeditor/MenuCommon.java @@ -93,7 +93,7 @@ public final class MenuCommon extends MenuBase { } final Deck genConstructed = new Deck(); - genConstructed.getMain().add((new Generate2ColorDeck("AI", "AI")).get2ColorDeck(60, PlayerType.HUMAN)); + genConstructed.getMain().addAll((new Generate2ColorDeck("AI", "AI")).get2ColorDeck(60, PlayerType.HUMAN)); this.getController().setModel(genConstructed); } diff --git a/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java b/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java index cadcc33dd9f..5b198423fa4 100644 --- a/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java +++ b/src/main/java/forge/gui/home/sanctioned/CSubmenuConstructed.java @@ -39,6 +39,7 @@ import forge.gui.OverlayUtils; import forge.gui.home.ICSubmenu; import forge.gui.toolbox.FLabel; import forge.item.CardPrinted; +import forge.item.ItemPoolView; import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.quest.QuestController; @@ -372,7 +373,7 @@ public enum CSubmenuConstructed implements ICSubmenu { /** Generates deck from current list selection(s). */ private Deck generateDeck(final JList lst0, final PlayerType player0) { - CardList cards = null; + ItemPoolView cards = null; final String[] selection = Arrays.copyOf(lst0.getSelectedValues(), lst0.getSelectedValues().length, String[].class); @@ -406,7 +407,7 @@ public enum CSubmenuConstructed implements ICSubmenu { // After generating card lists, build deck. deck = new Deck(); - deck.getMain().add(cards); + deck.getMain().addAll(cards); } // Theme deck @@ -416,7 +417,7 @@ public enum CSubmenuConstructed implements ICSubmenu { // After generating card lists, build deck. deck = new Deck(); - deck.getMain().add(cards); + deck.getMain().addAll(cards); } else if (lst0.getName().equals(ESubmenuConstructedTypes.QUESTEVENTS.toString())) { deck = quest.getDuelsManager().getEvent(selection[0]).getEventDeck(); diff --git a/src/main/java/forge/item/ItemPool.java b/src/main/java/forge/item/ItemPool.java index 0b54ae19cf7..346cc2aba13 100644 --- a/src/main/java/forge/item/ItemPool.java +++ b/src/main/java/forge/item/ItemPool.java @@ -224,9 +224,16 @@ public class ItemPool extends ItemPoolView { for (final Entry e : map) { this.remove(e.getKey(), e.getValue()); } - this.setListInSync(false); + // need not set out-of-sync: either remove did set, or nothing was removed } + public void removeAllFlat(final Iterable flat) { + for (final T e : flat) { + this.remove(e); + } + // need not set out-of-sync: either remove did set, or nothing was removed + } + /** * * Clear. diff --git a/src/main/java/forge/util/Predicate.java b/src/main/java/forge/util/Predicate.java index 36e02f057a4..2735f608f9d 100644 --- a/src/main/java/forge/util/Predicate.java +++ b/src/main/java/forge/util/Predicate.java @@ -57,7 +57,9 @@ public abstract class Predicate { /** The NOR. */ NOR, /** The NAND. */ - NAND + NAND, + GT, + LT } /** @@ -1016,6 +1018,10 @@ class Node extends Predicate { switch (this.operator) { case AND: return this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card); + case GT: + return this.getFilter1().isTrue(card) && !this.getFilter2().isTrue(card); + case LT: + return !this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card); case NAND: return !(this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card)); case OR: diff --git a/src/test/java/forge/deck/generate/Generate2ColorDeckTest.java b/src/test/java/forge/deck/generate/Generate2ColorDeckTest.java index 50acf0cab0b..713faff083c 100644 --- a/src/test/java/forge/deck/generate/Generate2ColorDeckTest.java +++ b/src/test/java/forge/deck/generate/Generate2ColorDeckTest.java @@ -3,7 +3,8 @@ package forge.deck.generate; import org.testng.Assert; import org.testng.annotations.Test; -import forge.CardList; +import forge.item.CardPrinted; +import forge.item.ItemPoolView; /** * Created by IntelliJ IDEA. User: dhudson @@ -17,7 +18,7 @@ public class Generate2ColorDeckTest { @Test(enabled = false) public void generate2ColorDeckTest1() { final Generate2ColorDeck gen = new Generate2ColorDeck("white", "blue"); - final CardList cardList = gen.get2ColorDeck(60, null); + final ItemPoolView cardList = gen.get2ColorDeck(60, null); Assert.assertNotNull(cardList); } } diff --git a/src/test/java/forge/deck/generate/Generate3ColorDeckTest.java b/src/test/java/forge/deck/generate/Generate3ColorDeckTest.java index d57e64ab2ca..7d33f05b731 100644 --- a/src/test/java/forge/deck/generate/Generate3ColorDeckTest.java +++ b/src/test/java/forge/deck/generate/Generate3ColorDeckTest.java @@ -3,7 +3,8 @@ package forge.deck.generate; import org.testng.Assert; import org.testng.annotations.Test; -import forge.CardList; +import forge.item.CardPrinted; +import forge.item.ItemPoolView; /** * Created by IntelliJ IDEA. User: dhudson @@ -17,7 +18,7 @@ public class Generate3ColorDeckTest { @Test(timeOut = 1000, enabled = false) public void generate3ColorDeckTest1() { final Generate3ColorDeck gen = new Generate3ColorDeck("white", "blue", "black"); - final CardList cardList = gen.get3ColorDeck(60, null); + final ItemPoolView cardList = gen.get3ColorDeck(60, null); Assert.assertNotNull(cardList); } } diff --git a/src/test/java/forge/deck/generate/Generate5ColorDeckTest.java b/src/test/java/forge/deck/generate/Generate5ColorDeckTest.java index dcd03838e44..1e2a0708225 100644 --- a/src/test/java/forge/deck/generate/Generate5ColorDeckTest.java +++ b/src/test/java/forge/deck/generate/Generate5ColorDeckTest.java @@ -3,7 +3,8 @@ package forge.deck.generate; import org.testng.Assert; import org.testng.annotations.Test; -import forge.CardList; +import forge.item.CardPrinted; +import forge.item.ItemPoolView; /** * Created by IntelliJ IDEA. User: dhudson @@ -17,7 +18,7 @@ public class Generate5ColorDeckTest { @Test(timeOut = 1000, enabled = false) public void generate5ColorDeckTest1() { final Generate5ColorDeck gen = new Generate5ColorDeck(); - final CardList cardList = gen.get5ColorDeck(60, null); + final ItemPoolView cardList = gen.get5ColorDeck(60, null); Assert.assertNotNull(cardList); } }