From 83d93c443677ca0efff5f26a29ccf41aa962e15c Mon Sep 17 00:00:00 2001 From: mcrawford620 Date: Mon, 11 Jul 2016 05:12:49 +0000 Subject: [PATCH] Use card ranker in BoosterDraftAI so pack cards are compared with existing cards in deck --- .../src/test/java/forge/CardRankerTest.java | 13 ++- .../java/forge/limited/BoosterDraftAI.java | 102 ++-------------- .../main/java/forge/limited/CardRanker.java | 110 +++++++++++++----- .../forge/limited/LimitedDeckBuilder.java | 13 +-- .../java/forge/limited/WinstonDraftAI.java | 8 +- 5 files changed, 108 insertions(+), 138 deletions(-) diff --git a/forge-gui-desktop/src/test/java/forge/CardRankerTest.java b/forge-gui-desktop/src/test/java/forge/CardRankerTest.java index bbfa4971209..d8ee7118f50 100644 --- a/forge-gui-desktop/src/test/java/forge/CardRankerTest.java +++ b/forge-gui-desktop/src/test/java/forge/CardRankerTest.java @@ -2,17 +2,14 @@ package forge; import forge.card.CardRarity; import forge.card.CardRules; -import forge.card.DeckHints; import forge.item.PaperCard; import forge.limited.CardRanker; import forge.properties.ForgeConstants; import forge.util.FileUtil; -import org.apache.commons.lang3.tuple.Pair; import org.junit.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; -import java.awt.print.Paper; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -32,12 +29,16 @@ public class CardRankerTest { Assert.assertEquals("Hero of Goma Fada", cp.getName()); List list = new ArrayList(); - PaperCard c0 = readCard("hero_of_goma_fada.txt"); + PaperCard c0 = readCard("makindi_patrol.txt"); list.add(c0); - PaperCard c1 = readCard("makindi_patrol.txt"); + PaperCard c1 = readCard("hero_of_goma_fada.txt"); list.add(c1); + PaperCard c2 = readCard("altars_reap.txt"); + list.add(c2); + PaperCard c3 = readCard("plains.txt"); + list.add(c3); - List ranked = ranker.rankCards(list); + List ranked = ranker.rankCardsInDeck(list); } /** diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java index 48fea0762aa..6450f4ec538 100644 --- a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java +++ b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java @@ -49,14 +49,9 @@ public class BoosterDraftAI { protected static final int N_DECKS = 7; // holds all the cards for each of the computer's decks - protected final List> deck = new ArrayList>(); + protected final List> decks = new ArrayList>(); protected final List playerColors = new ArrayList(); - - // roughly equivalent to 25 ranks in a core set, or 15 ranks in a small set - private static final double TAKE_BEST_THRESHOLD = 0.1; - - // rank worse than any other card available to draft - private static final double RANK_UNPICKABLE = 999.0; + protected CardRanker ranker = new CardRanker(); /** *

@@ -74,99 +69,26 @@ public class BoosterDraftAI { System.out.println("Player[" + player + "] pack: " + chooseFrom.toString()); } + final List deck = decks.get(player); final DeckColors deckCols = this.playerColors.get(player); - final ColorSet currentChoice = deckCols.getChosenColors(); + final ColorSet chosenColors = deckCols.getChosenColors(); final boolean canAddMoreColors = deckCols.canChoseMoreColors(); - final List> rankedCards = rankCards(chooseFrom, IBoosterDraft.CUSTOM_RANKINGS_FILE[0]); - - for (final Pair p : rankedCards) { - double valueBoost = 0; - - // If a card is not ai playable, somewhat decrease its rating - if( p.getKey().getRules().getAiHints().getRemAIDecks() ) { - valueBoost = TAKE_BEST_THRESHOLD; - } - - // if I cannot choose more colors, and the card cannot be played with chosen colors, decrease its rating. - if( !canAddMoreColors && !p.getKey().getRules().getManaCost().canBePaidWithAvaliable(currentChoice.getColor())) { - valueBoost = TAKE_BEST_THRESHOLD * 3; - } - - if (valueBoost > 0) { - p.setValue(p.getValue() + valueBoost); - //System.out.println(p.getKey() + " is now " + p.getValue()); - } - } - - double bestRanking = Double.MAX_VALUE; - PaperCard bestPick = null; - final List possiblePick = new ArrayList(); - for (final Pair p : rankedCards) { - final double rating = p.getValue(); - if(rating <= bestRanking + .01) { - if (rating < bestRanking) { - // found a better card start a new list - possiblePick.clear(); - bestRanking = rating; - } - possiblePick.add(p.getKey()); - } - } - - bestPick = Aggregates.random(possiblePick); + List rankedCards = ranker.rankCardsInPack(chooseFrom, deck, chosenColors, canAddMoreColors); + PaperCard bestPick = rankedCards.get(0); if (canAddMoreColors) { deckCols.addColorsOf(bestPick); } if (ForgePreferences.DEV_MODE) { - System.out.println("Player[" + player + "] picked: " + bestPick + " ranking of " + bestRanking); + System.out.println("Player[" + player + "] picked: " + bestPick); } - this.deck.get(player).add(bestPick); + this.decks.get(player).add(bestPick); return bestPick; } - /** - * Sort cards by rank. Note that if pack has cards from different editions, - * they could have the same rank. Basic lands and unrecognised cards are - * rated worse than all other possible picks. - * - * @param chooseFrom - * List of cards - * @return map of rankings - */ - private static List> rankCards(final Iterable chooseFrom, String customRankings) { - final List> rankedCards = new ArrayList>(); - for (final PaperCard card : chooseFrom) { - Double rank; - if (MagicColor.Constant.BASIC_LANDS.contains(card.getName())) { - rank = RANK_UNPICKABLE; - } else { - if (customRankings != null) { - rank = DraftRankCache.getCustomRanking(customRankings, card.getName()); - if (rank == null) { - // try the default draft rankings if there's no entry in the custom rankings file - rank = DraftRankCache.getRanking(card.getName(), card.getEdition()); - } - } else { - rank = DraftRankCache.getRanking(card.getName(), card.getEdition()); - } - - if (rank == null) { - if (ForgePreferences.DEV_MODE) { - System.out.println("Draft Rankings - Card Not Found: " + card.getName()); - } - rank = RANK_UNPICKABLE; - } - } - - rankedCards.add(MutablePair.of(card, rank)); - } - return rankedCards; - } - /** *

* getDecks. @@ -175,14 +97,14 @@ public class BoosterDraftAI { * @return an array of {@link forge.deck.Deck} objects. */ public Deck[] getDecks() { - final Deck[] out = new Deck[this.deck.size()]; + final Deck[] out = new Deck[this.decks.size()]; - for (int i = 0; i < this.deck.size(); i++) { + for (int i = 0; i < this.decks.size(); i++) { if (ForgePreferences.DEV_MODE) { System.out.println("Deck[" + i + "]"); } - out[i] = new BoosterDeckBuilder(this.deck.get(i), this.playerColors.get(i)).buildDeck(); + out[i] = new BoosterDeckBuilder(this.decks.get(i), this.playerColors.get(i)).buildDeck(); } return out; } // getDecks() @@ -195,7 +117,7 @@ public class BoosterDraftAI { public BoosterDraftAI() { // Initialize deck array and playerColors list for (int i = 0; i < N_DECKS; i++) { - this.deck.add(new ArrayList()); + this.decks.add(new ArrayList()); this.playerColors.add(new DeckColors()); } } // BoosterDraftAI() diff --git a/forge-gui/src/main/java/forge/limited/CardRanker.java b/forge-gui/src/main/java/forge/limited/CardRanker.java index 1c5db755e53..64998c53acd 100644 --- a/forge-gui/src/main/java/forge/limited/CardRanker.java +++ b/forge-gui/src/main/java/forge/limited/CardRanker.java @@ -2,8 +2,7 @@ package forge.limited; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; -import forge.card.CardRulesPredicates; -import forge.card.DeckHints; +import forge.card.*; import forge.item.PaperCard; import org.apache.commons.lang3.tuple.Pair; @@ -14,24 +13,29 @@ import java.util.Map; public class CardRanker { + private static final double SCORE_UNPICKABLE = -100.0; + /** * Rank cards. * * @param cards PaperCards to rank * @return List of beans with card rankings */ - public List rankCards(final Iterable cards) { + public List rankCardsInDeck(final Iterable cards) { List> cardScores = getScores(cards); - Collections.sort(cardScores, Collections.reverseOrder(new CardRankingComparator())); + return sortAndCreateList(cardScores); + } - List rankedCards = new ArrayList<>(cardScores.size()); - for (Pair pair : cardScores) { - System.out.println(pair.getKey().toString() + " " + pair.getValue().getName()); - rankedCards.add(pair.getValue()); - } + public List rankCardsInPack( + final Iterable cardsInPack, + final List deck, + ColorSet chosenColors, + boolean canAddMoreColors + ) { + List> cardScores = getScoresForPack(cardsInPack, deck, chosenColors, canAddMoreColors); - return rankedCards; + return sortAndCreateList(cardScores); } private List> getScores(Iterable cards) { @@ -42,14 +46,15 @@ public class CardRanker { cache.add(card); } - String customRankings = IBoosterDraft.CUSTOM_RANKINGS_FILE[0]; for (int i = 0; i < cache.size(); i++) { final PaperCard card = cache.get(i); - double score = getRawScore(card, customRankings); - - List otherCards = getCardsExcept(cache, i); + double score = getRawScore(card); + if (card.getRules().getAiHints().getRemAIDecks()) { + score -= 20.0; + } + List otherCards = getCardsExceptOne(cache, i); score += calculateSynergies(card, otherCards); cardScores.add(Pair.of(score, card)); @@ -58,28 +63,58 @@ public class CardRanker { return cardScores; } - private double getRawScore(PaperCard card, String customRankings) { - Double rkg; - if (customRankings != null) { - rkg = DraftRankCache.getCustomRanking(customRankings, card.getName()); - if (rkg == null) { - // try the default rankings if custom rankings contain no entry - rkg = DraftRankCache.getRanking(card.getName(), card.getEdition()); + private List> getScoresForPack( + Iterable cardsInPack, + List deck, + ColorSet chosenColors, + boolean canAddMoreColors + ) { + List> cardScores = new ArrayList<>(); + + for (PaperCard card : cardsInPack) { + double score = getRawScore(card); + if (card.getRules().getAiHints().getRemAIDecks()) { + score -= 20.0; } - } else { - rkg = DraftRankCache.getRanking(card.getName(), card.getEdition()); + if( !canAddMoreColors && !card.getRules().getManaCost().canBePaidWithAvaliable(chosenColors.getColor())) { + score -= 50.0; + } + + score += calculateSynergies(card, deck); + + cardScores.add(Pair.of(score, card)); } - double rawScore; - if (rkg != null) { - rawScore = 100 - (100 * rkg); + return cardScores; + } + + private double getRawScore(PaperCard card) { + Double rawScore; + if (MagicColor.Constant.BASIC_LANDS.contains(card.getName())) { + rawScore = SCORE_UNPICKABLE; } else { - rawScore = 0.0; + Double rkg; + String customRankings = IBoosterDraft.CUSTOM_RANKINGS_FILE[0]; + if (customRankings != null) { + rkg = DraftRankCache.getCustomRanking(customRankings, card.getName()); + if (rkg == null) { + // try the default rankings if custom rankings contain no entry + rkg = DraftRankCache.getRanking(card.getName(), card.getEdition()); + } + } else { + rkg = DraftRankCache.getRanking(card.getName(), card.getEdition()); + } + + if (rkg != null) { + rawScore = 100 - (100 * rkg); + } else { + rawScore = SCORE_UNPICKABLE; + } } return rawScore; } - private List getCardsExcept(List cache, int i) { + private List getCardsExceptOne(List cache, int i) { List otherCards = new ArrayList<>(); otherCards.addAll(cache.subList(0, i)); if (i + 1 < cache.size()) { @@ -102,7 +137,9 @@ public class CardRanker { final DeckHints hints = card.getRules().getAiHints().getDeckHints(); if (hints != null && hints.getType() != DeckHints.Type.NONE) { final List comboCards = hints.filter(otherCards); - score = comboCards.size() * 10; + if (comboCards.size() > 0) { + score = comboCards.size() * 10; + } } return score; } @@ -115,9 +152,22 @@ public class CardRanker { String buff = var.getValue(); final Iterable buffers = Iterables.filter(otherCards, Predicates.compose(CardRulesPredicates.subType(buff), PaperCard.FN_GET_RULES)); - matchBuffScore = Iterables.size(buffers) * 3; + if (Iterables.size(buffers) > 0) { + matchBuffScore = Iterables.size(buffers) * 3; + } } } return matchBuffScore; } + + private List sortAndCreateList(List> cardScores) { + Collections.sort(cardScores, Collections.reverseOrder(new CardRankingComparator())); + + List rankedCards = new ArrayList<>(cardScores.size()); + for (Pair pair : cardScores) { + rankedCards.add(pair.getValue()); + } + + return rankedCards; + } } diff --git a/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java b/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java index 18488597c8d..c480a23f773 100644 --- a/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java +++ b/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java @@ -1,8 +1,6 @@ package forge.limited; -import java.awt.print.Paper; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -10,8 +8,6 @@ import java.util.ListIterator; import java.util.Map; import java.util.Set; -import org.apache.commons.lang3.tuple.Pair; - import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; @@ -62,13 +58,14 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { private final List aiPlayables; private final List deckList = new ArrayList(); private final List setsWithBasicLands = new ArrayList(); - // Views for aiPlayable - protected CardRanker ranker = new CardRanker(); + private CardRanker ranker = new CardRanker(); + + // Views for aiPlayable private Iterable onColorCreatures; private Iterable onColorNonCreatures; - private static final boolean logToConsole = true; + private static final boolean logToConsole = false; /** * @@ -88,7 +85,7 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { // remove Unplayables final Iterable playables = Iterables.filter(availableList, Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard.FN_GET_RULES)); - this.aiPlayables = this.ranker.rankCards(playables); + this.aiPlayables = this.ranker.rankCardsInDeck(playables); this.availableList.removeAll(aiPlayables); findBasicLandSets(); diff --git a/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java b/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java index a6e9612b211..58bf1dd02bf 100644 --- a/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java +++ b/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java @@ -22,10 +22,10 @@ public class WinstonDraftAI extends BoosterDraftAI{ } public WinstonDraftAI() { - this.deck.clear(); + this.decks.clear(); this.playerColors.clear(); for (int i = 0; i < N_DECKS; i++) { - this.deck.add(new ArrayList()); + this.decks.add(new ArrayList()); this.playerColors.add(new DeckColors()); } } @@ -61,7 +61,7 @@ public class WinstonDraftAI extends BoosterDraftAI{ } } if (acquire != null) { - this.deck.get(0).addAll(acquire.toFlatList()); + this.decks.get(0).addAll(acquire.toFlatList()); //tallyDeckColors(); } } @@ -104,6 +104,6 @@ public class WinstonDraftAI extends BoosterDraftAI{ }*/ public int getAIDraftSize() { - return this.deck.get(0).size(); + return this.decks.get(0).size(); } }