From 98fa689c664dd9dd103bc740dd904cb0f5a020f4 Mon Sep 17 00:00:00 2001 From: mcrawford620 Date: Sun, 8 Jul 2012 05:21:45 +0000 Subject: [PATCH] - Refactor Booster Deck building to separate class. - SVar for creatures that are sacrificed at end of combat. --- .gitattributes | 2 + .project | 11 + res/cardsfolder/c/crumbling_colossus.txt | 1 + res/cardsfolder/f/fog_elemental.txt | 1 + res/cardsfolder/k/keldon_battlewagon.txt | 1 + res/cardsfolder/s/stoic_ephemera.txt | 1 + .../card/cardfactory/CardFactoryUtil.java | 4 + .../java/forge/game/limited/BoosterDeck.java | 327 +++++++++++++++ .../forge/game/limited/BoosterDraftAI.java | 374 +----------------- .../game/limited/CreatureComparator.java | 52 +++ 10 files changed, 405 insertions(+), 369 deletions(-) create mode 100644 src/main/java/forge/game/limited/BoosterDeck.java create mode 100644 src/main/java/forge/game/limited/CreatureComparator.java diff --git a/.gitattributes b/.gitattributes index 879be5bbaa4..b60dd68aac0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12037,11 +12037,13 @@ src/main/java/forge/game/GamePlayerRating.java -text src/main/java/forge/game/GameState.java -text src/main/java/forge/game/GameSummary.java svneol=native#text/plain src/main/java/forge/game/GameType.java -text +src/main/java/forge/game/limited/BoosterDeck.java -text src/main/java/forge/game/limited/BoosterDraft.java svneol=native#text/plain src/main/java/forge/game/limited/BoosterDraftAI.java svneol=native#text/plain src/main/java/forge/game/limited/CCnt.java svneol=native#text/plain src/main/java/forge/game/limited/CardPoolLimitation.java -text src/main/java/forge/game/limited/CardRatings.java -text +src/main/java/forge/game/limited/CreatureComparator.java -text src/main/java/forge/game/limited/CustomLimited.java svneol=native#text/plain src/main/java/forge/game/limited/DeckColors.java svneol=native#text/plain src/main/java/forge/game/limited/IBoosterDraft.java svneol=native#text/plain diff --git a/.project b/.project index 5af90efe210..30f1a3c91f4 100644 --- a/.project +++ b/.project @@ -20,10 +20,21 @@ + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature net.sf.eclipsecs.core.CheckstyleNature + org.eclipse.pde.PluginNature diff --git a/res/cardsfolder/c/crumbling_colossus.txt b/res/cardsfolder/c/crumbling_colossus.txt index ea92de7ce88..44ea7668856 100644 --- a/res/cardsfolder/c/crumbling_colossus.txt +++ b/res/cardsfolder/c/crumbling_colossus.txt @@ -7,6 +7,7 @@ K:Trample T:Mode$ Attacks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | TriggerDescription$ When CARDNAME attacks, sacrifice it at end of combat. SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigSacrifice | TriggerDescription$ Sacrifice CARDNAME at end of combat. SVar:TrigSacrifice:AB$ Sacrifice | Cost$ 0 | Defined$ Self +SVar:SacrificeEndCombat:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/crumbling_colossus.jpg SetInfo:M12|Uncommon|http://magiccards.info/scans/en/m12/204.jpg diff --git a/res/cardsfolder/f/fog_elemental.txt b/res/cardsfolder/f/fog_elemental.txt index 15864be011c..dcac1d059c7 100644 --- a/res/cardsfolder/f/fog_elemental.txt +++ b/res/cardsfolder/f/fog_elemental.txt @@ -8,6 +8,7 @@ T:Mode$ Attacks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | TriggerDescri T:Mode$ Blocks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or blocks, sacrifice it at end of combat. SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigSacrifice | TriggerDescription$ Sacrifice CARDNAME at end of combat. SVar:TrigSacrifice:AB$Sacrifice | Cost$ 0 | Defined$ Self +SVar:SacrificeEndCombat:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/fog_elemental.jpg SetInfo:WTH|Common|http://magiccards.info/scans/en/wl/40.jpg diff --git a/res/cardsfolder/k/keldon_battlewagon.txt b/res/cardsfolder/k/keldon_battlewagon.txt index fd18178fa7f..ea69d3dd312 100644 --- a/res/cardsfolder/k/keldon_battlewagon.txt +++ b/res/cardsfolder/k/keldon_battlewagon.txt @@ -8,6 +8,7 @@ K:CARDNAME can't block. T:Mode$ Attacks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | TriggerDescription$ When CARDNAME attacks, sacrifice it at end of combat. SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigSacrifice | TriggerDescription$ Sacrifice CARDNAME at end of combat. SVar:TrigSacrifice:AB$Sacrifice | Cost$ 0 | Defined$ Self +SVar:SacrificeEndCombat:True A:AB$ Pump | Cost$ tapXType<1/Creature> | NumAtt$ +X | References$ X | SpellDescription$ CARDNAME gets +X/+0 until end of turn, where X is the power of the creature tapped this way. SVar:X:Tapped$CardPower SVar:RemAIDeck:True diff --git a/res/cardsfolder/s/stoic_ephemera.txt b/res/cardsfolder/s/stoic_ephemera.txt index eafada04c79..480949af507 100644 --- a/res/cardsfolder/s/stoic_ephemera.txt +++ b/res/cardsfolder/s/stoic_ephemera.txt @@ -8,6 +8,7 @@ K:Flying T:Mode$ Blocks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | TriggerDescription$ When CARDNAME blocks, sacrifice it at end of combat. SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Opponent | Execute$ TrigSacrifice | TriggerDescription$ Sacrifice CARDNAME at end of combat. SVar:TrigSacrifice:AB$Sacrifice | Cost$ 0 | Defined$ Self +SVar:SacrificeEndCombat:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/stoic_ephemera.jpg SetInfo:DIS|Uncommon|http://magiccards.info/scans/en/di/19.jpg diff --git a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java index e5d04562396..5f179c0ebea 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java @@ -595,6 +595,10 @@ public class CardFactoryUtil { if (c.getSVar("Targeting").equals("Dies")) { value -= 25; } + if (c.getSVar("SacrificeEndCombat").equals("True")) { + value -= 40; + } + for (final SpellAbility sa : c.getSpellAbilities()) { if (sa.isAbility()) { diff --git a/src/main/java/forge/game/limited/BoosterDeck.java b/src/main/java/forge/game/limited/BoosterDeck.java new file mode 100644 index 00000000000..f7455467076 --- /dev/null +++ b/src/main/java/forge/game/limited/BoosterDeck.java @@ -0,0 +1,327 @@ +package forge.game.limited; + +import forge.AllZone; +import forge.Card; +import forge.CardList; +import forge.CardListFilter; +import forge.CardListUtil; +import forge.Constant; +import forge.card.CardColor; +import forge.card.CardManaCost; +import forge.card.mana.ManaCostShard; +import forge.deck.Deck; +import forge.util.MyRandom; + +/** + * Deck built from a Booster Draft. + * + */ +public class BoosterDeck extends Deck { + + private static final long serialVersionUID = -7818685851099321964L; + + private int cardsNeeded = 22; + private int landsNeeded = 18; + private DeckColors colors; + private CardList draftedList; + + private CardList aiPlayables; + + private CardList deckList = new CardList(); + + public BoosterDeck(CardList dList, DeckColors pClrs) { + super(""); + this.draftedList = dList; + this.colors = pClrs; + buildDeck(); + } + + /** + *

+ * buildDeck. + *

+ * + * @param draftedList + * a {@link forge.CardList} object. + * @param colors + * a {@link forge.game.limited.DeckColors} object. + * @return a {@link forge.deck.Deck} object. + */ + private void buildDeck() { + + aiPlayables = draftedList.filter(new CardListFilter() { + @Override + public boolean addCard(final Card c) { + return !(c.getSVar("RemAIDeck").equals("True") || c.getSVar("RemRandomDeck").equals("True")); + } + }); + for (int i = 0; i < aiPlayables.size(); i++) { + draftedList.remove(aiPlayables.get(i)); + } + + + // 1. Add best 15 on-color creatures + addBestCreatures(15); + + // 2.Try to fill up to 22 with on-color non-creature cards + addNonCreatures(cardsNeeded - deckList.size()); + + // 3.Try to fill up to 22 with on-color creatures cards (if more than 15 + // are present) + addBestCreatures(cardsNeeded - deckList.size()); + + CardList nonLands = aiPlayables.getNotType("Land").getOnly2Colors(colors.getColor1(), colors.getColor2()); + + // 4. If there are still on-color cards and the average cmc is low add a + // 23rd card. + if (cardsNeeded == 0 && CardListUtil.getAverageCMC(deckList) < 3 && !nonLands.isEmpty()) { + Card c = nonLands.get(0); + deckList.add(c); + aiPlayables.remove(0); + landsNeeded--; + } + + // 5. If there are still less than 22 non-land cards add off-color + // cards. + addRandomCards(cardsNeeded - deckList.size()); + + // 6. If it's not a mono color deck, add non-basic lands that were drafted. + addNonBasicLands(); + + final CCnt[] clrCnts = calculateLandNeeds(); + + if (landsNeeded > 0) { + addLands(clrCnts); + } + + while (deckList.size() > 40) { + final Card c = deckList.get(MyRandom.getRandom().nextInt(deckList.size() - 1)); + deckList.remove(c); + aiPlayables.add(c); + } + + while (deckList.size() < 40) { + if (aiPlayables.size() > 1) { + final Card c = aiPlayables.get(MyRandom.getRandom().nextInt(aiPlayables.size() - 1)); + deckList.add(c); + aiPlayables.remove(c); + } else if (aiPlayables.size() == 1) { + final Card c = aiPlayables.get(0); + deckList.add(c); + aiPlayables.remove(c); + } else { + // if no playable cards remain fill up with basic lands + for (int i = 0; i < 5; i++) { + if (clrCnts[i].getCount() > 0) { + final Card c = AllZone.getCardFactory().getCard(clrCnts[i].getColor(), + AllZone.getComputerPlayer()); + c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); + deckList.add(c); + break; + } + } + } + } + if (deckList.size() == 40) { + this.getMain().add(deckList); + this.getSideboard().add(aiPlayables); + this.getSideboard().add(draftedList); + } else { + throw new RuntimeException("BoosterDraftAI : buildDeck() error, decksize not 40"); + } + } + + /** + * Add lands to fulfill the given color counts. + * @param clrCnts + */ + private void addLands(final CCnt[] clrCnts) { + + // total of all ClrCnts + int totalColor = 0; + for (int i = 0; i < 5; i++) { + totalColor += clrCnts[i].getCount(); + // tmpDeck += ClrCnts[i].Color + ":" + ClrCnts[i].Count + "\n"; + } + + // tmpDeck += "totalColor:" + totalColor + "\n"; + + for (int i = 0; i < 5; i++) { + if (clrCnts[i].getCount() > 0) { // calculate number of lands + // for + // each color + final float p = (float) clrCnts[i].getCount() / (float) totalColor; + final int nLand = (int) (landsNeeded * p) + 1; + // tmpDeck += "nLand-" + ClrCnts[i].Color + ":" + nLand + + // "\n"; + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("Basics[" + clrCnts[i].getColor() + "]:" + nLand); + } + + // just to prevent a null exception by the deck size fixing + // code + // CardCounts.put(ClrCnts[i].Color, nLand); + + for (int j = 0; j <= nLand; j++) { + final Card c = AllZone.getCardFactory().getCard(clrCnts[i].getColor(), + AllZone.getComputerPlayer()); + c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); + deckList.add(c); + landsNeeded--; + } + } + } + int n = 0; + while (landsNeeded > 0) { + if (clrCnts[n].getCount() > 0) { + final Card c = AllZone.getCardFactory().getCard(clrCnts[n].getColor(), AllZone.getComputerPlayer()); + c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); + deckList.add(c); + landsNeeded--; + + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("AddBasics: " + c.getName()); + } + } + if (++n > 4) { + n = 0; + } + } + } + + /** + * attempt to optimize basic land counts according to color representation + * @return CCnt + */ + private CCnt[] calculateLandNeeds() { + 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 < deckList.size(); i++) { + final CardManaCost mc = deckList.get(i).getManaCost(); + + // count each mana symbol in the mana cost + for (ManaCostShard shard : mc.getShards()) { + byte mask = shard.getColorMask(); + + if ((mask & CardColor.WHITE) > 0) { + clrCnts[0].setCount(clrCnts[0].getCount() + 1); + } + if ((mask & CardColor.BLUE) > 0) { + clrCnts[1].setCount(clrCnts[1].getCount() + 1); + } + if ((mask & CardColor.BLACK) > 0) { + clrCnts[2].setCount(clrCnts[2].getCount() + 1); + } + if ((mask & CardColor.RED) > 0) { + clrCnts[3].setCount(clrCnts[3].getCount() + 1); + } + if ((mask & CardColor.GREEN) > 0) { + clrCnts[4].setCount(clrCnts[4].getCount() + 1); + } + } + } + return clrCnts; + } + + /** + * Add non-basic lands to the deck. + */ + private void addNonBasicLands() { + CardList lands = aiPlayables.getType("Land"); + while (!colors.getColor1().equals(colors.getColor2()) && landsNeeded > 0 && lands.size() > 0) { + final Card c = lands.get(0); + + deckList.add(c); + landsNeeded--; + aiPlayables.remove(c); + + lands = aiPlayables.getType("Land"); + + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("Land:" + c.getName()); + } + } + } + + /** + * Add random cards to the deck. + * @param nCards + */ + private void addRandomCards(int nCards) { + CardList z = aiPlayables.getNotType("Land"); + int ii = 0; + while ((nCards > 0) && (z.size() > 1)) { + + final Card c = z.get(MyRandom.getRandom().nextInt(z.size() - 1)); + + deckList.add(c); + cardsNeeded--; + nCards--; + aiPlayables.remove(c); + z.remove(c); + + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("NonLands[" + ii++ + "]:" + c.getName() + "(" + c.getManaCost() + ")"); + } + } + } + + /** + * Add non creatures to the deck. + * @param nCards + */ + private void addNonCreatures(int nCards) { + CardList others = aiPlayables.getNotType("Creature").getNotType("Land") + .getOnly2Colors(colors.getColor1(), colors.getColor2()); + + int ii = 0; + while (nCards > 0 && others.size() > 0) { + int index = 0; + if (others.size() > 1) { + index = MyRandom.getRandom().nextInt(others.size() - 1); + } + final Card c = others.get(index); + + deckList.add(c); + cardsNeeded--; + nCards--; + aiPlayables.remove(c); + others.remove(c); + + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("Others[" + ii++ + "]:" + c.getName() + " (" + c.getManaCost() + ")"); + } + } + } + + /** + * Add the best creatures to the deck. + * + * @param nCreatures + */ + private void addBestCreatures(int nCreatures) { + CardList creatures = aiPlayables.getType("Creature").getOnly2Colors(colors.getColor1(), colors.getColor2()); + creatures.sort(new CreatureComparator()); + + int i = 0; + while (nCreatures > 0 && creatures.size() > 0) { + final Card c = creatures.get(0); + + deckList.add(c); + cardsNeeded--; + nCreatures--; + aiPlayables.remove(c); + creatures.remove(c); + + if (Constant.Runtime.DEV_MODE[0]) { + System.out.println("Creature[" + i + "]:" + c.getName() + " (" + c.getManaCost() + ")"); + } + + i++; + } + } + +} diff --git a/src/main/java/forge/game/limited/BoosterDraftAI.java b/src/main/java/forge/game/limited/BoosterDraftAI.java index cf874215eb7..1ab8fdfe9a9 100644 --- a/src/main/java/forge/game/limited/BoosterDraftAI.java +++ b/src/main/java/forge/game/limited/BoosterDraftAI.java @@ -18,23 +18,18 @@ package forge.game.limited; import java.util.ArrayList; -import java.util.Comparator; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import forge.AllZone; import forge.Card; import forge.CardList; import forge.CardListFilter; import forge.CardListUtil; import forge.Constant; -import forge.card.CardColor; -import forge.card.CardManaCost; import forge.card.cardfactory.CardFactoryUtil; -import forge.card.mana.ManaCostShard; import forge.card.spellability.AbilityMana; import forge.deck.Deck; import forge.util.MyRandom; @@ -116,7 +111,7 @@ public class BoosterDraftAI { if (!hasPicked) { final CardList creatures = aiPlayables.getType("Creature"); - creatures.sort(this.bestCreature); + creatures.sort(new CreatureComparator()); debugCreatures(creatures); if (creatures.size() > 0) { @@ -156,7 +151,7 @@ public class BoosterDraftAI { if (!hasPicked) { final CardList creatures = aiPlayables.getType("Creature").getMonoColored(true); - creatures.sort(this.bestCreature); + creatures.sort(new CreatureComparator()); debugCreatures(creatures); if (creatures.size() > 0) { @@ -186,7 +181,7 @@ public class BoosterDraftAI { // list, and 1 non-creature. typeList = colorList.getType("Creature"); if (typeList.size() > 0) { - typeList.sort(this.bestCreature); + typeList.sort(new CreatureComparator()); wouldPick.add(typeList.get(0)); if (typeList.size() > 1) { wouldPick.add(typeList.get(1)); @@ -353,328 +348,11 @@ public class BoosterDraftAI { System.out.println("Deck[" + i + "]"); } - out[i] = this.buildDeck(this.deck[i], this.playerColors.get(i)); + out[i] = new BoosterDeck(this.deck[i], this.playerColors.get(i)); } return out; } // getDecks() - - /** - *

- * buildDeck. - *

- * - * @param dList - * a {@link forge.CardList} object. - * @param pClrs - * a {@link forge.game.limited.DeckColors} object. - * @return a {@link forge.deck.Deck} object. - */ - private Deck buildDeck(final CardList dList, final DeckColors pClrs) { - - final CardList outList = new CardList(); - int cardsNeeded = 22; - int landsNeeded = 18; - - final CardList aiPlayables = dList.filter(new CardListFilter() { - @Override - public boolean addCard(final Card c) { - return !(c.getSVar("RemAIDeck").equals("True") || c.getSVar("RemRandomDeck").equals("True")); - } - }); - for (int i = 0; i < aiPlayables.size(); i++) { - dList.remove(aiPlayables.get(i)); - } - - final CardList creatures = aiPlayables.getType("Creature").getOnly2Colors(pClrs.getColor1(), pClrs.getColor2()); - - int nCreatures = 15; - - creatures.sort(this.bestCreature); - - // 1.Add up to 15 on-color creatures - int i = 0; - while (nCreatures > 0 && creatures.size() > 0) { - final Card c = creatures.get(0); - - outList.add(c); - cardsNeeded--; - nCreatures--; - aiPlayables.remove(c); - creatures.remove(c); - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("Creature[" + i + "]:" + c.getName() + " (" + c.getManaCost() + ")"); - } - - i++; - } - - /* - * CardList otherCreatures = aiPlayables.getType("Creature"); while - * ((nCreatures > 1) && (otherCreatures.size() > 1)) { final Card c = - * otherCreatures.get(MyRandom.getRandom().nextInt(otherCreatures.size() - * - 1)); outList.add(c); cardsNeeded--; nCreatures--; - * aiPlayables.remove(c); - * - * otherCreatures = aiPlayables.getType("Creature"); - * - * if (Constant.Runtime.DEV_MODE[0]) { - * System.out.println("AddCreature: " + c.getName() + " (" + - * c.getManaCost() + ")"); } } - */ - - CardList others = aiPlayables.getNotType("Creature").getNotType("Land") - .getOnly2Colors(pClrs.getColor1(), pClrs.getColor2()); - - // 2.Try to fill up to 22 with on-color non-creature cards - int ii = 0; - while (cardsNeeded > 0 && others.size() > 0) { - int index = 0; - if (others.size() > 1) { - index = MyRandom.getRandom().nextInt(others.size() - 1); - } - final Card c = others.get(index); - - // out.addMain(c.getName()); - outList.add(c); - cardsNeeded--; - aiPlayables.remove(c); - - others = aiPlayables.getNotType("Creature").getNotType("Land") - .getOnly2Colors(pClrs.getColor1(), pClrs.getColor2()); - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("Others[" + ii++ + "]:" + c.getName() + " (" + c.getManaCost() + ")"); - } - } - - i = 0; - // 3.Try to fill up to 22 with on-color creatures cards (if more than 15 - // are present) - while (cardsNeeded > 0 && (0 < creatures.size())) { - final Card c = creatures.get(0); - - outList.add(c); - cardsNeeded--; - aiPlayables.remove(c); - creatures.remove(c); - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("Creature[" + i + "]:" + c.getName() + " (" + c.getManaCost() + ")"); - } - - i++; - } - - CardList nonLands = aiPlayables.getNotType("Land").getOnly2Colors(pClrs.getColor1(), pClrs.getColor2()); - - // 4. If there are still on-color cards and the average cmc is low add a - // 23rd card. - if (cardsNeeded == 0 && CardListUtil.getAverageCMC(outList) < 3 && !nonLands.isEmpty()) { - Card c = nonLands.get(0); - outList.add(c); - aiPlayables.remove(0); - landsNeeded--; - } - - // 5. If there are still less than 22 non-land cards add off-color - // cards. - ii = 0; - CardList z = aiPlayables.getNotType("Land"); - while ((cardsNeeded > 0) && (z.size() > 1)) { - - // if (z.size() < 1) - // throw new - // RuntimeException("BoosterDraftAI : buildDeck() error, deck does not have enough non-lands"); - final Card c = z.get(MyRandom.getRandom().nextInt(z.size() - 1)); - - // out.addMain(c.getName()); - outList.add(c); - cardsNeeded--; - aiPlayables.remove(c); - - z = aiPlayables.getNotType("Land"); - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("NonLands[" + ii++ + "]:" + c.getName() + "(" + c.getManaCost() + ")"); - } - } - - // 6. If it's not a mono color deck, add non-basic lands. - CardList lands = aiPlayables.getType("Land"); - while (!pClrs.getColor1().equals(pClrs.getColor2()) && landsNeeded > 0 && lands.size() > 0) { - final Card c = lands.get(0); - - outList.add(c); - landsNeeded--; - aiPlayables.remove(c); - - lands = aiPlayables.getType("Land"); - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("Land:" + c.getName()); - } - } - - // 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 (i = 0; i < outList.size(); i++) { - final CardManaCost mc = outList.get(i).getManaCost(); - - // count each mana symbol in the mana cost - for (ManaCostShard shard : mc.getShards()) { - byte mask = shard.getColorMask(); - - if ((mask & CardColor.WHITE) > 0) { - clrCnts[0].setCount(clrCnts[0].getCount() + 1); - } - if ((mask & CardColor.BLUE) > 0) { - clrCnts[1].setCount(clrCnts[1].getCount() + 1); - } - if ((mask & CardColor.BLACK) > 0) { - clrCnts[2].setCount(clrCnts[2].getCount() + 1); - } - if ((mask & CardColor.RED) > 0) { - clrCnts[3].setCount(clrCnts[3].getCount() + 1); - } - if ((mask & CardColor.GREEN) > 0) { - clrCnts[4].setCount(clrCnts[4].getCount() + 1); - } - } - } - - if (landsNeeded > 0) { - // total of all ClrCnts - int totalColor = 0; - for (i = 0; i < 5; i++) { - totalColor += clrCnts[i].getCount(); - // tmpDeck += ClrCnts[i].Color + ":" + ClrCnts[i].Count + "\n"; - } - - // tmpDeck += "totalColor:" + totalColor + "\n"; - - for (i = 0; i < 5; i++) { - if (clrCnts[i].getCount() > 0) { // calculate number of lands - // for - // each color - final float p = (float) clrCnts[i].getCount() / (float) totalColor; - final int nLand = (int) (landsNeeded * p) + 1; - // tmpDeck += "nLand-" + ClrCnts[i].Color + ":" + nLand + - // "\n"; - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("Basics[" + clrCnts[i].getColor() + "]:" + nLand); - } - - // just to prevent a null exception by the deck size fixing - // code - // CardCounts.put(ClrCnts[i].Color, nLand); - - for (int j = 0; j <= nLand; j++) { - final Card c = AllZone.getCardFactory().getCard(clrCnts[i].getColor(), - AllZone.getComputerPlayer()); - c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); - outList.add(c); - landsNeeded--; - } - } - } - int n = 0; - while (landsNeeded > 0) { - if (clrCnts[n].getCount() > 0) { - final Card c = AllZone.getCardFactory().getCard(clrCnts[n].getColor(), AllZone.getComputerPlayer()); - c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); - outList.add(c); - landsNeeded--; - - if (Constant.Runtime.DEV_MODE[0]) { - System.out.println("AddBasics: " + c.getName()); - } - } - if (++n > 4) { - n = 0; - } - } - } - - while (outList.size() > 40) { - final Card c = outList.get(MyRandom.getRandom().nextInt(outList.size() - 1)); - outList.remove(c); - aiPlayables.add(c); - } - - while (outList.size() < 40) { - if (aiPlayables.size() > 1) { - final Card c = aiPlayables.get(MyRandom.getRandom().nextInt(aiPlayables.size() - 1)); - outList.add(c); - aiPlayables.remove(c); - } else if (aiPlayables.size() == 1) { - final Card c = aiPlayables.get(0); - outList.add(c); - aiPlayables.remove(c); - } else { - // if no playable cards remain fill up with basic lands - for (i = 0; i < 5; i++) { - if (clrCnts[i].getCount() > 0) { - final Card c = AllZone.getCardFactory().getCard(clrCnts[i].getColor(), - AllZone.getComputerPlayer()); - c.setCurSetCode(IBoosterDraft.LAND_SET_CODE[0]); - outList.add(c); - break; - } - } - } - } - if (outList.size() == 40) { - final Deck out = new Deck(); - out.getMain().add(outList); - out.getSideboard().add(aiPlayables); - out.getSideboard().add(dList); - return out; - } - throw new RuntimeException("BoosterDraftAI : buildDeck() error, decksize not 40"); - } - - /* - * private Deck getDeck(CardList list) { Deck out = new - * Deck(GameType.Draft); for(int i = 0; i < list.size(); i++) - * out.addMain(list.get(i).getName()); - * - * return out; }//getDeck() - * - * //add Land to list argument private void addLand(CardList list, String[] - * color) { Card land; for(int i = 0; i < 9; i++) { land = - * AllZone.getCardFactory().getCard(colorToLand.get(color[0]).toString(), - * AllZone.getComputerPlayer()); - * - * land.setCurSetCode(land.getMostRecentSet()); - * land.setImageFilename(CardUtil.buildFilename(land)); - * - * list.add(land); - * - * land = - * AllZone.getCardFactory().getCard(colorToLand.get(color[1]).toString(), - * AllZone.getComputerPlayer()); - * - * land.setCurSetCode(land.getMostRecentSet()); - * land.setImageFilename(CardUtil.buildFilename(land)); - * - * list.add(land); } - * - * //if(list.getType("Land").size() != 18) //throw new RuntimeException( - * "BoosterDraftAI : addLand() error, deck does not have 18 lands - " - * +list.getType("Land").size()); - * - * //if(list.size() != 40) //throw new - * RuntimeException("BoosterDraftAI : addLand() error, deck is not 40 cards - " - * +list.size()); }//addLand() - */ - + // returns 7 different ints, within the range of 0-9 /** @@ -758,48 +436,6 @@ public class BoosterDraftAI { { Constant.Color.RED, Constant.Color.WHITE } }; - private final Comparator bestCreature = new Comparator() { - @Override - public int compare(final Card a, final Card b) { - int cmcA = a.getCMC(); - cmcA *= 30; // average creature from evaluateCreature comes out to 30 * CMC - - int cmcB = b.getCMC(); - cmcB *= 30; - - int evalA = CardFactoryUtil.evaluateCreature(a) - 100; // evaluateCreature starts at 100 - int evalB = CardFactoryUtil.evaluateCreature(b) - 100; - - int rarA = 0; - int rarB = 0; - - if (a.getCurSetRarity().equals("Common")) { - rarA = 1; - } else if (a.getCurSetRarity().equals("Uncommon")) { - rarA = 2; - } else if (a.getCurSetRarity().equals("Rare")) { - rarA = 4; - } else if (a.getCurSetRarity().equals("Mythic")) { - rarA = 8; - } - - if (b.getCurSetRarity().equals("Common")) { - rarB = 1; - } else if (b.getCurSetRarity().equals("Uncommon")) { - rarB = 2; - } else if (b.getCurSetRarity().equals("Rare")) { - rarB = 4; - } else if (b.getCurSetRarity().equals("Mythic")) { - rarB = 8; - } - - final int scoreA = evalA - cmcA + rarA; - final int scoreB = evalB - cmcB + rarB; - - return scoreB - scoreA; - } - }; - private static void debugCreatures(CardList creatures) { if (Constant.Runtime.DEV_MODE[0]) { for (Card c : creatures) { diff --git a/src/main/java/forge/game/limited/CreatureComparator.java b/src/main/java/forge/game/limited/CreatureComparator.java new file mode 100644 index 00000000000..c7b30b43b5d --- /dev/null +++ b/src/main/java/forge/game/limited/CreatureComparator.java @@ -0,0 +1,52 @@ +package forge.game.limited; + +import java.util.Comparator; + +import forge.Card; +import forge.card.cardfactory.CardFactoryUtil; + +/** + * Sorts creatures, best first. + * + */ +public class CreatureComparator implements Comparator { + public int compare(final Card a, final Card b) { + int cmcA = a.getCMC(); + cmcA *= 30; // average creature from evaluateCreature is about 30 * CMC + + int cmcB = b.getCMC(); + cmcB *= 30; + + // evaluateCreature starts at 100 + int evalA = CardFactoryUtil.evaluateCreature(a) - 100; + int evalB = CardFactoryUtil.evaluateCreature(b) - 100; + + int rarA = 0; + int rarB = 0; + + if (a.getCurSetRarity().equals("Common")) { + rarA = 1; + } else if (a.getCurSetRarity().equals("Uncommon")) { + rarA = 2; + } else if (a.getCurSetRarity().equals("Rare")) { + rarA = 4; + } else if (a.getCurSetRarity().equals("Mythic")) { + rarA = 8; + } + + if (b.getCurSetRarity().equals("Common")) { + rarB = 1; + } else if (b.getCurSetRarity().equals("Uncommon")) { + rarB = 2; + } else if (b.getCurSetRarity().equals("Rare")) { + rarB = 4; + } else if (b.getCurSetRarity().equals("Mythic")) { + rarB = 8; + } + + final int scoreA = evalA - cmcA + rarA; + final int scoreB = evalB - cmcB + rarB; + + return scoreB - scoreA; + } +}