diff --git a/forge-core/src/main/java/forge/card/CardAiHints.java b/forge-core/src/main/java/forge/card/CardAiHints.java index 059f944a15d..593b7fe14b3 100644 --- a/forge-core/src/main/java/forge/card/CardAiHints.java +++ b/forge-core/src/main/java/forge/card/CardAiHints.java @@ -1,7 +1,7 @@ package forge.card; /** - * TODO: Write javadoc for this type. + * CardAiHints holds all the different types of card hints for AI decks. * */ public class CardAiHints { diff --git a/forge-core/src/main/java/forge/card/DeckHints.java b/forge-core/src/main/java/forge/card/DeckHints.java index 1f6618623b1..69a561522f5 100644 --- a/forge-core/src/main/java/forge/card/DeckHints.java +++ b/forge-core/src/main/java/forge/card/DeckHints.java @@ -7,6 +7,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.item.PaperCard; import forge.util.PredicateString.StringOp; +import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.Collection; @@ -22,7 +23,7 @@ public class DeckHints { /** * Enum of types of DeckHints. */ - public enum Type { + private enum Type { /** The Color. */ COLOR, @@ -36,84 +37,98 @@ public class DeckHints { NONE } - private Type type = Type.NONE; - private String filterParam = null; + private boolean valid = false; + private List> filters = null; /** * Construct a DeckHints from the SVar string. * - * @param wants + * @param hints * SVar for DeckHints */ - public DeckHints(String wants) { - String[] pieces = wants.split("\\$"); + public DeckHints(String hints) { + String[] pieces = hints.split("\\&"); + if (pieces.length > 0) { + for (String piece : pieces) { + Pair pair = parseHint(piece.trim()); + if (pair != null) { + if (filters == null) { + filters = new ArrayList<>(); + } + filters.add(pair); + valid = true; + } + } + } + } + + private Pair parseHint(String hint) { + Pair pair = null; + String[] pieces = hint.split("\\$"); if (pieces.length == 2) { try { Type typeValue = Type.valueOf(pieces[0].toUpperCase()); for (Type t : Type.values()) { if (typeValue == t) { - type = t; + pair = Pair.of(t, pieces[1]); break; } } } catch (IllegalArgumentException e) { - // type will remain NONE + // will remain null } - - filterParam = pieces[1]; } + return pair; + } + + public boolean isValid() { + return valid; } /** - * @return the type - */ - public Type getType() { - return type; - } - - /** - * Returns a list of Cards from the given List that match this + * Returns a list of Cards from the given List that match this * DeckHints. I.e., other cards that this Card needs in its deck. * * @param cardList * list of cards to be filtered - * @return List of Cards that match this DeckHints. + * @return List of Cards that match this DeckHints. */ public List filter(Iterable cardList) { - List ret; - switch (type) { - case TYPE: - ret = new ArrayList(); - String[] types = filterParam.split("\\|"); - for (String type : types) { - addMatchingItems(ret, cardList, CardRulesPredicates.subType(type), PaperCard.FN_GET_RULES); + List ret = new ArrayList<>(); + for (Pair pair : filters) { + Type type = pair.getLeft(); + String param = pair.getRight(); + switch (type) { + case TYPE: + String[] types = param.split("\\|"); + for (String t : types) { + addMatchingItems(ret, cardList, CardRulesPredicates.subType(t), PaperCard.FN_GET_RULES); + } + break; + case COLOR: + String[] colors = param.split("\\|"); + for (String color : colors) { + ColorSet cc = ColorSet.fromNames(color); + if (cc.isColorless()) { + addMatchingItems(ret, cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES); + } else { + addMatchingItems(ret, cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES); + } + } + break; + case KEYWORD: + String[] keywords = param.split("\\|"); + for (String keyword : keywords) { + addMatchingItems(ret, cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES); + } + break; + case NAME: + String[] names = param.split("\\|"); + for (String name : names) { + addMatchingItems(ret, cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES); + } + break; } - break; - case COLOR: - ret = new ArrayList(); - String[] colors = filterParam.split("\\|"); - for (String color : colors) { - ColorSet cc = ColorSet.fromNames(color); - addMatchingItems(ret, cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES); - } - break; - case KEYWORD: - ret = new ArrayList(); - String[] keywords = filterParam.split("\\|"); - for (String keyword : keywords) { - addMatchingItems(ret, cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES); - } - break; - case NAME: - ret = new ArrayList(); - String[] names = filterParam.split("\\|"); - for (String name : names) { - addMatchingItems(ret, cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES); - } - break; - default: - ret = Lists.newArrayList(cardList); - break; } return ret; } diff --git a/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java b/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java index a43921fd95b..4e0d7d6378d 100644 --- a/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java +++ b/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java @@ -38,13 +38,11 @@ public class DeckHintsTest { Assert.assertEquals("Griffin Rider", cp.getName()); DeckHints hints = cp.getRules().getAiHints().getDeckHints(); Assert.assertNotNull(hints); - Assert.assertEquals(DeckHints.Type.TYPE, hints.getType()); + Assert.assertTrue(hints.isValid()); List list = new ArrayList(); - PaperCard c0 = readCard("assault_griffin.txt"); - list.add(c0); - PaperCard c1 = readCard("auramancer.txt"); - list.add(c1); + list.add(readCard("assault_griffin.txt")); + list.add(readCard("auramancer.txt")); Assert.assertEquals(1, hints.filter(list).size()); Assert.assertEquals("Assault Griffin", hints.filter(list).get(0).getName()); @@ -59,15 +57,12 @@ public class DeckHintsTest { Assert.assertEquals("Throne of Empires", cp.getName()); DeckHints hints = cp.getRules().getAiHints().getDeckHints(); Assert.assertNotNull(hints); - Assert.assertEquals(DeckHints.Type.NAME, hints.getType()); + Assert.assertTrue(hints.isValid()); List list = new ArrayList(); - PaperCard c0 = readCard("assault_griffin.txt"); - list.add(c0); - PaperCard c1 = readCard("scepter_of_empires.txt"); - list.add(c1); - PaperCard c2 = readCard("crown_of_empires.txt"); - list.add(c2); + list.add(readCard("assault_griffin.txt")); + list.add(readCard("scepter_of_empires.txt")); + list.add(readCard("crown_of_empires.txt")); Assert.assertEquals(2, hints.filter(list).size()); } @@ -80,13 +75,11 @@ public class DeckHintsTest { IPaperCard cp = readCard("mwonvuli_beast_tracker.txt"); DeckHints hints = cp.getRules().getAiHints().getDeckHints(); Assert.assertNotNull(hints); - Assert.assertEquals(DeckHints.Type.KEYWORD, hints.getType()); + Assert.assertTrue(hints.isValid()); List list = new ArrayList(); - PaperCard c0 = readCard("acidic_slime.txt"); - list.add(c0); - PaperCard c1 = readCard("ajanis_sunstriker.txt"); - list.add(c1); + list.add(readCard("acidic_slime.txt")); + list.add(readCard("ajanis_sunstriker.txt")); Assert.assertEquals(1, hints.filter(list).size()); } @@ -99,13 +92,11 @@ public class DeckHintsTest { IPaperCard cp = readCard("wurms_tooth.txt"); DeckHints hints = cp.getRules().getAiHints().getDeckNeeds(); Assert.assertNotNull(hints); - Assert.assertEquals(DeckHints.Type.COLOR, hints.getType()); + Assert.assertTrue(hints.isValid()); List list = new ArrayList(); - PaperCard c0 = readCard("llanowar_elves.txt"); - list.add(c0); - PaperCard c1 = readCard("unsummon.txt"); - list.add(c1); + list.add(readCard("llanowar_elves.txt")); + list.add(readCard("unsummon.txt")); Assert.assertEquals(1, hints.filter(list).size()); } @@ -114,19 +105,30 @@ public class DeckHintsTest { * * Test for no wants. */ - @Test(timeOut = 1000, enabled = false) + @Test(timeOut = 1000, enabled = true) void testNoFilter() { PaperCard cp = readCard("assault_griffin.txt"); DeckHints hints = cp.getRules().getAiHints().getDeckHints(); Assert.assertEquals("Assault Griffin", cp.getName()); + Assert.assertNull(hints); + } + + /** + * Test for multiple. + */ + @Test(timeOut = 1000, enabled = true) + void testMultiple() { + PaperCard pc = readCard("ruination_guide.txt"); + DeckHints hints = pc.getRules().getAiHints().getDeckHints(); Assert.assertNotNull(hints); - Assert.assertEquals(DeckHints.Type.NONE, hints.getType()); + Assert.assertTrue(hints.isValid()); List list = new ArrayList(); - PaperCard c0 = readCard("assault_griffin.txt"); - list.add(c0); + list.add(readCard("assault_griffin.txt")); + list.add(readCard("breaker_of_armies.txt")); + list.add(readCard("benthic_infiltrator.txt")); - Assert.assertEquals(1, hints.filter(list).size()); + Assert.assertEquals(2, hints.filter(list).size()); } /** diff --git a/forge-gui/res/cardsfolder/r/ruination_guide.txt b/forge-gui/res/cardsfolder/r/ruination_guide.txt index 2399591419e..4af2170a760 100644 --- a/forge-gui/res/cardsfolder/r/ruination_guide.txt +++ b/forge-gui/res/cardsfolder/r/ruination_guide.txt @@ -6,6 +6,6 @@ K:Devoid K:Ingest S:Mode$ Continuous | Affected$ Creature.Colorless+Other+YouCtrl | AddPower$ 1 | Description$ Other colorless creatures you control get +1/+0. SVar:PlayMain1:TRUE -DeckHints:Type$Processor +DeckHints:Type$Processor & Keyword$Devoid & Color$Colorless SVar:Picture:http://www.wizards.com/global/images/magic/general/ruination_guide.jpg Oracle:Devoid (This card has no color.)\nIngest (Whenever this creature deals combat damage to a player, that player exiles the top card of his or her library.)\nOther colorless creatures you control get +1/+0. diff --git a/forge-gui/src/main/java/forge/limited/CardRanker.java b/forge-gui/src/main/java/forge/limited/CardRanker.java index 64998c53acd..031d9138667 100644 --- a/forge-gui/src/main/java/forge/limited/CardRanker.java +++ b/forge-gui/src/main/java/forge/limited/CardRanker.java @@ -127,7 +127,6 @@ public class CardRanker { double synergyScore = 0.0; synergyScore += getScoreForDeckHints(card, otherCards); - synergyScore += getScoreForBuffedBy(card, otherCards); return synergyScore; } @@ -135,7 +134,7 @@ public class CardRanker { private double getScoreForDeckHints(PaperCard card, Iterable otherCards) { double score = 0.0; final DeckHints hints = card.getRules().getAiHints().getDeckHints(); - if (hints != null && hints.getType() != DeckHints.Type.NONE) { + if (hints != null && hints.isValid()) { final List comboCards = hints.filter(otherCards); if (comboCards.size() > 0) { score = comboCards.size() * 10; @@ -144,22 +143,6 @@ public class CardRanker { return score; } - private double getScoreForBuffedBy(PaperCard card, Iterable otherCards) { - double matchBuffScore = 0.0; - Iterable> vars = card.getRules().getMainPart().getVariables(); - for (Map.Entry var : vars) { - if (var.getKey().equals("BuffedBy")) { - String buff = var.getValue(); - final Iterable buffers = Iterables.filter(otherCards, - Predicates.compose(CardRulesPredicates.subType(buff), PaperCard.FN_GET_RULES)); - if (Iterables.size(buffers) > 0) { - matchBuffScore = Iterables.size(buffers) * 3; - } - } - } - return matchBuffScore; - } - private List sortAndCreateList(List> cardScores) { Collections.sort(cardScores, Collections.reverseOrder(new CardRankingComparator())); diff --git a/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java b/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java index c480a23f773..991dbaba374 100644 --- a/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java +++ b/forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java @@ -558,12 +558,12 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { if (ai.getRemRandomDecks()) { final List comboCards = new ArrayList(); if (ai.getDeckNeeds() != null - && ai.getDeckNeeds().getType() != DeckHints.Type.NONE) { + && ai.getDeckNeeds().isValid()) { final DeckHints needs = ai.getDeckNeeds(); comboCards.addAll(needs.filter(deckList)); } if (ai.getDeckHints() != null - && ai.getDeckHints().getType() != DeckHints.Type.NONE) { + && ai.getDeckHints().isValid()) { final DeckHints hints = ai.getDeckHints(); comboCards.addAll(hints.filter(deckList)); }