From 9d131f6bde483a44b13fa54267c35cbf24f32a3b Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Sat, 27 Jan 2018 13:19:03 +0400 Subject: [PATCH] Random generated decks improvements and fixes for AI: * added generation of only basic lands decks; * fixed wrong color cards selection; --- .../java/mage/player/ai/ComputerPlayer.java | 61 ++++++++++++++--- Mage/src/main/java/mage/cards/Sets.java | 67 +++++++++++++++++-- 2 files changed, 116 insertions(+), 12 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index f8b1bc543aa..048d7e89075 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1633,7 +1633,42 @@ public class ComputerPlayer extends PlayerImpl implements Player { } public static Deck buildDeck(List cardPool, final List colors) { + return buildDeck(cardPool, colors, false); + } + + public static Deck buildDeck(List cardPool, final List colors, boolean onlyBasicLands) { + if (onlyBasicLands) { + return buildDeckWithOnlyBasicLands(cardPool); + } else { + return buildDeckWithNormalCards(cardPool, colors); + } + } + + public static Deck buildDeckWithOnlyBasicLands(List cardPool) { + // random cards from card pool Deck deck = new Deck(); + final int DECK_SIZE = 40; + + List sortedCards = new ArrayList<>(cardPool); + if (sortedCards.size() > 0) { + while (deck.getCards().size() < DECK_SIZE) { + deck.getCards().add(sortedCards.get(RandomUtil.nextInt(sortedCards.size()))); + } + return deck; + } else { + addBasicLands(deck, "Forest", DECK_SIZE); + return deck; + } + } + + public static Deck buildDeckWithNormalCards(List cardPool, final List colors) { + // top 23 cards plus basic lands until 40 deck size + Deck deck = new Deck(); + final int DECK_SIZE = 40; + final int DECK_CARDS_COUNT = 23; + final int DECK_LANDS_COUNT = DECK_SIZE - DECK_CARDS_COUNT; + + // sort card pool by top score List sortedCards = new ArrayList<>(cardPool); Collections.sort(sortedCards, new Comparator() { @Override @@ -1643,8 +1678,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return score2.compareTo(score1); } }); + + // get top cards int cardNum = 0; - while (deck.getCards().size() < 23 && sortedCards.size() > cardNum) { + while (deck.getCards().size() < DECK_CARDS_COUNT && sortedCards.size() > cardNum) { Card card = sortedCards.get(cardNum); if (!card.isBasic()) { deck.getCards().add(card); @@ -1652,53 +1689,61 @@ public class ComputerPlayer extends PlayerImpl implements Player { } cardNum++; } - // add basic lands + + // add basic lands by color percent // TODO: compensate for non basic lands Mana mana = new Mana(); for (Card card : deck.getCards()) { mana.add(card.getManaCost().getMana()); } double total = mana.getBlack() + mana.getBlue() + mana.getGreen() + mana.getRed() + mana.getWhite(); + + // most frequent land is forest by defalt int mostLand = 0; String mostLandName = "Forest"; if (mana.getGreen() > 0) { - int number = (int) Math.round(mana.getGreen() / total * 17); + int number = (int) Math.round(mana.getGreen() / total * DECK_LANDS_COUNT); addBasicLands(deck, "Forest", number); mostLand = number; } + if (mana.getBlack() > 0) { - int number = (int) Math.round(mana.getBlack() / total * 17); + int number = (int) Math.round(mana.getBlack() / total * DECK_LANDS_COUNT); addBasicLands(deck, "Swamp", number); if (number > mostLand) { mostLand = number; mostLandName = "Swamp"; } } + if (mana.getBlue() > 0) { - int number = (int) Math.round(mana.getBlue() / total * 17); + int number = (int) Math.round(mana.getBlue() / total * DECK_LANDS_COUNT); addBasicLands(deck, "Island", number); if (number > mostLand) { mostLand = number; mostLandName = "Island"; } } + if (mana.getWhite() > 0) { - int number = (int) Math.round(mana.getWhite() / total * 17); + int number = (int) Math.round(mana.getWhite() / total * DECK_LANDS_COUNT); addBasicLands(deck, "Plains", number); if (number > mostLand) { mostLand = number; mostLandName = "Plains"; } } + if (mana.getRed() > 0) { - int number = (int) Math.round(mana.getRed() / total * 17); + int number = (int) Math.round(mana.getRed() / total * DECK_LANDS_COUNT); addBasicLands(deck, "Mountain", number); if (number > mostLand) { mostLandName = "Plains"; } } - addBasicLands(deck, mostLandName, 40 - deck.getCards().size()); + // adds remaining lands (most popular name) + addBasicLands(deck, mostLandName, DECK_SIZE - deck.getCards().size()); return deck; } diff --git a/Mage/src/main/java/mage/cards/Sets.java b/Mage/src/main/java/mage/cards/Sets.java index 32084e9731f..a973990ce62 100644 --- a/Mage/src/main/java/mage/cards/Sets.java +++ b/Mage/src/main/java/mage/cards/Sets.java @@ -27,6 +27,7 @@ */ package mage.cards; +import mage.Mana; import mage.cards.decks.DeckCardInfo; import mage.cards.decks.DeckCardLayout; import mage.cards.decks.DeckCardLists; @@ -35,9 +36,12 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.filter.FilterMana; import mage.util.ClassScanner; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import org.junit.Assert; import java.io.FileNotFoundException; import java.io.PrintWriter; @@ -45,7 +49,7 @@ import java.util.*; /** * - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class Sets extends HashMap { @@ -93,23 +97,50 @@ public class Sets extends HashMap { * @return */ public static List generateRandomCardPool(int cardsCount, List allowedColors) { + return generateRandomCardPool(cardsCount, allowedColors, false); + } + + public static List generateRandomCardPool(int cardsCount, List allowedColors, boolean onlyBasicLands) { CardCriteria criteria = new CardCriteria(); - criteria.notTypes(CardType.LAND); + + if (onlyBasicLands) { + // only lands + criteria.rarities(Rarity.LAND); + criteria.colorless(true); // basic lands is colorless + } else { + // any card, but not basic lands + criteria.notTypes(CardType.LAND); + + // clear colors + criteria.white(false); + criteria.blue(false); + criteria.black(false); + criteria.red(false); + criteria.green(false); + criteria.colorless(false); // colorless is not allowed for gen + } + + FilterMana manaNeed = new FilterMana(); for (ColoredManaSymbol color : allowedColors) { switch (color) { case W: + manaNeed.setWhite(true); criteria.white(true); break; case U: + manaNeed.setBlue(true); criteria.blue(true); break; case B: + manaNeed.setBlack(true); criteria.black(true); break; case R: + manaNeed.setRed(true); criteria.red(true); break; case G: + manaNeed.setGreen(true); criteria.green(true); break; } @@ -123,9 +154,37 @@ public class Sets extends HashMap { CardInfo cardInfo = cards.get(RandomUtil.nextInt(cards.size())); Card card = cardInfo != null ? cardInfo.getCard() : null; if (card != null) { - cardPool.add(card); - count++; + + FilterMana manaCard = card.getColorIdentity(); + boolean cardManaOK = true; + + if (onlyBasicLands) { + // lands is colorless + // discard not needed color by mana produce + Assert.assertEquals("only basic lands allow", 1, card.getMana().size()); + for (Mana manaLand : card.getMana()) { + if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { cardManaOK = false; } + if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { cardManaOK = false; } + if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { cardManaOK = false; } + if (manaLand.getRed() > 0 && !manaNeed.isRed()) { cardManaOK = false; } + if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { cardManaOK = false; } + } + } else { + // cards + // discard any card that have not needed color + if (manaCard.isWhite() && !manaNeed.isWhite()) { cardManaOK = false; } + if (manaCard.isBlue() && !manaNeed.isBlue()) { cardManaOK = false; } + if (manaCard.isBlack() && !manaNeed.isBlack()) { cardManaOK = false; } + if (manaCard.isRed() && !manaNeed.isRed()) { cardManaOK = false; } + if (manaCard.isGreen() && !manaNeed.isGreen()) { cardManaOK = false; } + } + + if (cardManaOK) { + cardPool.add(card); + count++; + } } + tries++; if (tries > 4096) { // to avoid infinite loop throw new IllegalStateException("Not enough cards for chosen colors to generate deck: " + allowedColors);