From 582d9ffe16cba9917ccd4a3332fd766adfbfb75a Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Mon, 5 Sep 2011 22:53:45 +0000 Subject: [PATCH] fixed a bug with deckeditor filters: (1) when you select 6 core types of 7, all 7 are shown anyway, (2) with active set filter didn't show some cards issued in other sets --- src/main/java/forge/card/CardPoolView.java | 7 ++- src/main/java/forge/card/CardPrinted.java | 48 ++++++++++++++++-- src/main/java/forge/card/CardRules.java | 12 +++-- .../java/forge/gui/deckeditor/DeckEditor.java | 14 +++--- .../forge/gui/deckeditor/DeckEditorBase.java | 5 +- .../forge/gui/deckeditor/DeckEditorMenu.java | 9 ++-- .../gui/deckeditor/FilterCheckBoxes.java | 7 +-- .../forge/gui/deckeditor/TableWithCards.java | 21 ++++++-- .../net/slightlymagic/maxmtg/Predicate.java | 50 ++++++++++++++++++- src/test/java/forge/BoosterDraft_1Test.java | 2 +- 10 files changed, 141 insertions(+), 34 deletions(-) diff --git a/src/main/java/forge/card/CardPoolView.java b/src/main/java/forge/card/CardPoolView.java index bd41a8cb2dd..1966d317526 100644 --- a/src/main/java/forge/card/CardPoolView.java +++ b/src/main/java/forge/card/CardPoolView.java @@ -24,11 +24,14 @@ public class CardPoolView implements Iterable> { new Lambda1>() { @Override public CardRules apply(final Entry from) { return from.getKey().getCard(); } }; - public final static Lambda1> fnToReference = + public final static Lambda1> fnToPrinted = new Lambda1>() { @Override public CardPrinted apply(final Entry from) { return from.getKey(); } }; - + public final static Lambda1> fnToCardName = + new Lambda1>() { + @Override public String apply(final Entry from) { return from.getKey().getName(); } + }; public final static Lambda1> fnToCount = new Lambda1>() { @Override public Integer apply(final Entry from) { return from.getValue(); } diff --git a/src/main/java/forge/card/CardPrinted.java b/src/main/java/forge/card/CardPrinted.java index a403316867a..c3f514fe4cb 100644 --- a/src/main/java/forge/card/CardPrinted.java +++ b/src/main/java/forge/card/CardPrinted.java @@ -1,10 +1,14 @@ package forge.card; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; +import org.apache.commons.lang3.StringUtils; + import net.slightlymagic.braids.util.lambda.Lambda1; import net.slightlymagic.maxmtg.Predicate; +import net.slightlymagic.maxmtg.Predicate.StringOp; import forge.AllZone; import forge.Card; import forge.CardUtil; @@ -122,8 +126,10 @@ public final class CardPrinted implements Comparable { return cardSet.compareTo(o.cardSet); } - - public static abstract class Predicates { + /** + * Number of filters based on CardPrinted values. + */ + public abstract static class Predicates { public static Predicate rarity(final boolean isEqual, final CardRarity value) { return new PredicateRarity(value, isEqual); @@ -135,6 +141,15 @@ public final class CardPrinted implements Comparable { } return new PredicateSets(value, shouldContain); } + public static Predicate printedInSets(final String value) { + if (value == null || value.isEmpty()) { + return Predicate.getTrue(CardPrinted.class); + } + return new PredicateSets(Arrays.asList(new String[]{value}), true); + } + public static Predicate name(final StringOp op, final String what) { + return new PredicateName(op, what); + } private static class PredicateRarity extends Predicate { private final CardRarity operand; @@ -157,14 +172,39 @@ public final class CardPrinted implements Comparable { @Override public boolean isTrue(final CardPrinted card) { return sets.contains(card.cardSet) == mustContain; } - public PredicateSets(final List wantSets, boolean shouldContain) { + public PredicateSets(final List wantSets, final boolean shouldContain) { sets = wantSets; // maybe should make a copy here? mustContain = shouldContain; } } + private static class PredicateName extends Predicate { + private final String operand; + private final StringOp operator; + + @Override + public boolean isTrue(final CardPrinted card) { + return op(card.getName(), operand); + } + + private boolean op(final String op1, final String op2) { + switch (operator) { + case CONTAINS: return StringUtils.containsIgnoreCase(op1, op2); + case NOT_CONTAINS: return !StringUtils.containsIgnoreCase(op1, op2); + case EQUALS: return op1.equalsIgnoreCase(op2); + default: return false; + } + } + + public PredicateName(final StringOp operator, final String operand) + { + this.operand = operand; + this.operator = operator; + } + } + /** - * Pre-built predicates are stored here to allow their re-usage and easier access from code + * Pre-built predicates are stored here to allow their re-usage and easier access from code. */ public abstract static class Presets { // Think twice before using these, since rarity is a prop of printed card. diff --git a/src/main/java/forge/card/CardRules.java b/src/main/java/forge/card/CardRules.java index 26f993fa77e..f8d6d85810c 100644 --- a/src/main/java/forge/card/CardRules.java +++ b/src/main/java/forge/card/CardRules.java @@ -223,10 +223,12 @@ public final class CardRules { } private boolean op(final String op1, final String op2) { - if (operator == StringOp.CONTAINS) { return StringUtils.containsIgnoreCase(op1, op2); } - if (operator == StringOp.NOT_CONTAINS) { return !StringUtils.containsIgnoreCase(op1, op2); } - if (operator == StringOp.EQUALS) { return op1.equalsIgnoreCase(op2); } - return false; + switch (operator) { + case CONTAINS: return StringUtils.containsIgnoreCase(op1, op2); + case NOT_CONTAINS: return !StringUtils.containsIgnoreCase(op1, op2); + case EQUALS: return op1.equalsIgnoreCase(op2); + default: return false; + } } public LeafString(final CardField field, final StringOp operator, final String operand) @@ -393,6 +395,8 @@ public final class CardRules { colors.add(isGreen); colors.add(isColorless); } + + public static final Predicate constantTrue = Predicate.getTrue(CardRules.class); // Think twice before using these, since rarity is a prop of printed card. public static final Predicate isInLatestSetCommon = rarityInCardsLatestSet(true, CardRarity.Common); diff --git a/src/main/java/forge/gui/deckeditor/DeckEditor.java b/src/main/java/forge/gui/deckeditor/DeckEditor.java index 547f298d177..b2d7b8b354d 100644 --- a/src/main/java/forge/gui/deckeditor/DeckEditor.java +++ b/src/main/java/forge/gui/deckeditor/DeckEditor.java @@ -156,7 +156,7 @@ public final class DeckEditor extends DeckEditorBase implements NewConstants { public DeckEditor() { try { filterBoxes = new FilterCheckBoxes(true); - top = new TableWithCards("Avaliable Cards", true); + top = new TableWithCards("Avaliable Cards", true, true); bottom = new TableWithCards("Deck", true); cardView = new CardPanelHeavy(); @@ -311,24 +311,24 @@ public final class DeckEditor extends DeckEditorBase implements NewConstants { } @Override - protected Predicate buildFilter() { - List> rules = new ArrayList>(5); + protected Predicate buildFilter() { + List> rules = new ArrayList>(5); rules.add(super.buildFilter()); if (StringUtils.isNotBlank(txtCardName.getText())) { - rules.add(CardRules.Predicates.name(StringOp.CONTAINS, txtCardName.getText())); + rules.add(CardPrinted.Predicates.name(StringOp.CONTAINS, txtCardName.getText())); } if (StringUtils.isNotBlank(txtCardType.getText())) { - rules.add(CardRules.Predicates.joinedType(StringOp.CONTAINS, txtCardType.getText())); + rules.add(Predicate.brigde(CardRules.Predicates.joinedType(StringOp.CONTAINS, txtCardType.getText()), CardPrinted.fnGetRules)); } if (StringUtils.isNotBlank(txtCardRules.getText())) { - rules.add(CardRules.Predicates.rules(StringOp.CONTAINS, txtCardRules.getText())); + rules.add(Predicate.brigde(CardRules.Predicates.rules(StringOp.CONTAINS, txtCardRules.getText()), CardPrinted.fnGetRules)); } if (searchSetCombo.getSelectedIndex() != 0) { String setCode = SetUtils.getCode3ByName(searchSetCombo.getSelectedItem().toString()); - rules.add(CardRules.Predicates.wasPrintedInSet(setCode)); + rules.add(CardPrinted.Predicates.printedInSets(setCode)); } return rules.size() == 1 ? rules.get(0) : Predicate.and(rules); diff --git a/src/main/java/forge/gui/deckeditor/DeckEditorBase.java b/src/main/java/forge/gui/deckeditor/DeckEditorBase.java index ee3d64fb958..14b893fcec5 100644 --- a/src/main/java/forge/gui/deckeditor/DeckEditorBase.java +++ b/src/main/java/forge/gui/deckeditor/DeckEditorBase.java @@ -10,6 +10,7 @@ import javax.swing.JOptionPane; import net.slightlymagic.maxmtg.Predicate; import forge.GUI_DeckAnalysis; +import forge.card.CardPrinted; import forge.card.CardRules; import forge.card.CardPoolView; @@ -38,9 +39,9 @@ public abstract class DeckEditorBase extends JFrame implements DeckDisplay { // THIS IS HERE FOR OVERLOADING!!!1 // or may be return abstract getFilter from derived class + this filter ... virtual protected member, but later - protected Predicate buildFilter() { + protected Predicate buildFilter() { if (null == filterBoxes) { - return Predicate.getTrue(CardRules.class); + return Predicate.getTrue(CardPrinted.class); } return filterBoxes.buildFilter(); } diff --git a/src/main/java/forge/gui/deckeditor/DeckEditorMenu.java b/src/main/java/forge/gui/deckeditor/DeckEditorMenu.java index 47494d40767..7c957ff9e1e 100644 --- a/src/main/java/forge/gui/deckeditor/DeckEditorMenu.java +++ b/src/main/java/forge/gui/deckeditor/DeckEditorMenu.java @@ -246,13 +246,10 @@ public class DeckEditorMenu extends JMenuBar implements NewConstants { currentGameType = Constant.GameType.Constructed; setDeckData("", false); - // This is an expensive heap operation. - - CardPool allCards = new CardPool(); - allCards.addAllCards(CardDb.instance().getAllUniqueCards()); + allCards.addAllCards(CardDb.instance().getAllCards()); - deckDisplay.setDecks(allCards, new CardPoolView()); + deckDisplay.setDecks(allCards, null); }//new constructed /** @@ -302,7 +299,7 @@ public class DeckEditorMenu extends JMenuBar implements NewConstants { GenerateConstructedDeck gen = new GenerateConstructedDeck(); // This is an expensive heap operation. - CardPool allCards = new CardPool( CardDb.instance().getAllUniqueCards() ); + CardPool allCards = new CardPool( CardDb.instance().getAllCards() ); CardPool generated = new CardPool(); for (Card c : gen.generateDeck()) { generated.add( CardDb.instance().getCard(c)); } diff --git a/src/main/java/forge/gui/deckeditor/FilterCheckBoxes.java b/src/main/java/forge/gui/deckeditor/FilterCheckBoxes.java index c30408fb64e..1cc7101107b 100644 --- a/src/main/java/forge/gui/deckeditor/FilterCheckBoxes.java +++ b/src/main/java/forge/gui/deckeditor/FilterCheckBoxes.java @@ -7,6 +7,7 @@ import java.util.List; import javax.swing.JCheckBox; import net.slightlymagic.maxmtg.Predicate; +import forge.card.CardPrinted; import forge.card.CardRules; /** @@ -71,7 +72,7 @@ class FilterCheckBoxes { } - public final Predicate buildFilter() { + public final Predicate buildFilter() { List> colors = new ArrayList>(); if (white.isSelected()) { colors.add(CardRules.Predicates.Presets.isWhite); } if (blue.isSelected()) { colors.add(CardRules.Predicates.Presets.isBlue); } @@ -89,9 +90,9 @@ class FilterCheckBoxes { if (planeswalker.isSelected()) { types.add(CardRules.Predicates.Presets.isPlaneswalker); } if (artifact.isSelected()) { types.add(CardRules.Predicates.Presets.isArtifact); } if (enchantment.isSelected()) { types.add(CardRules.Predicates.Presets.isEnchantment); } - Predicate filterByType = colors.size() == 7 ? Predicate.getTrue(CardRules.class) : Predicate.or(types); + Predicate filterByType = types.size() == 7 ? Predicate.getTrue(CardRules.class) : Predicate.or(types); - return Predicate.and(filterByColor, filterByType); + return Predicate.brigde(Predicate.and(filterByColor, filterByType), CardPrinted.fnGetRules); } } diff --git a/src/main/java/forge/gui/deckeditor/TableWithCards.java b/src/main/java/forge/gui/deckeditor/TableWithCards.java index a2e9055359e..9f04c913ee0 100644 --- a/src/main/java/forge/gui/deckeditor/TableWithCards.java +++ b/src/main/java/forge/gui/deckeditor/TableWithCards.java @@ -33,8 +33,9 @@ public final class TableWithCards { protected JTable table = new JTable(); protected JScrollPane jScrollPane = new JScrollPane(); protected JLabel statsLabel = new JLabel(); - protected Predicate filter = null; + protected Predicate filter = null; protected boolean isTrackingStats = false; + protected boolean wantUnique = false; // need this to allow users place its contents public JComponent getTableDecorated() { return jScrollPane; } @@ -42,6 +43,9 @@ public final class TableWithCards { public JComponent getLabel() { return statsLabel; } public TableWithCards(final String title, final boolean showStats) { + this(title, showStats, false); + } + public TableWithCards(final String title, final boolean showStats, final boolean forceUnique) { // components Color gray = new Color(148, 145, 140); TitledBorder titledBorder = new TitledBorder(BorderFactory.createEtchedBorder(Color.white, gray), title); @@ -56,6 +60,7 @@ public final class TableWithCards { // class data isTrackingStats = showStats; + wantUnique = forceUnique; } public void setup(final List> columns, final CardPanelBase cardView) @@ -137,7 +142,7 @@ public final class TableWithCards { private boolean isUnfiltered() { return filter == null || filter.is1(); } private boolean isFiltered() { return filter != null && !filter.is1(); } - public void setFilter(final Predicate filterToSet) { + public void setFilter(final Predicate filterToSet) { filter = filterToSet; updateView(); } @@ -158,10 +163,18 @@ public final class TableWithCards { } public void updateView() { - if (isFiltered()) { + if (isFiltered() || wantUnique) { model.clear(); - model.addCards(filter.select(pool, CardPoolView.fnToCard)); } + + if (isFiltered() && wantUnique) { + model.addCards(filter.uniqueByLast(pool, CardPoolView.fnToCardName, CardPoolView.fnToPrinted)); + } else if (isFiltered()) { + model.addCards(filter.select(pool, CardPoolView.fnToPrinted)); + } else if (wantUnique) { + model.addCards(CardRules.Predicates.Presets.constantTrue.uniqueByLast(pool, CardPoolView.fnToCardName, CardPoolView.fnToCard)); + } + model.resort(); } diff --git a/src/main/java/net/slightlymagic/maxmtg/Predicate.java b/src/main/java/net/slightlymagic/maxmtg/Predicate.java index 9c8e480c98c..977b2171b9e 100644 --- a/src/main/java/net/slightlymagic/maxmtg/Predicate.java +++ b/src/main/java/net/slightlymagic/maxmtg/Predicate.java @@ -1,7 +1,13 @@ package net.slightlymagic.maxmtg; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; import java.util.List; +import java.util.Map; + +import forge.card.CardPrinted; +import forge.card.CardRules; import net.slightlymagic.braids.util.lambda.Lambda1; /** @@ -104,6 +110,38 @@ public abstract class Predicate { } } + // Unique + public final Iterable uniqueByLast(final Iterable source, final Lambda1 fnUniqueKey) + { + Map uniques = new Hashtable(); + for (T c : source) { if (isTrue(c)) { uniques.put(fnUniqueKey.apply(c), c); } } + return uniques.values(); + } + public final Iterable uniqueByLast(final Iterable source, final Lambda1 fnUniqueKey, final Lambda1 accessor) + { // this might be exotic + Map uniques = new Hashtable(); + for (U c : source) { if (isTrue(accessor.apply(c))) { uniques.put(fnUniqueKey.apply(c), c); } } + return uniques.values(); + } + public final Iterable uniqueByFirst(final Iterable source, final Lambda1 fnUniqueKey) + { + Map uniques = new Hashtable(); + for (T c : source) { + K key = fnUniqueKey.apply(c); + if (isTrue(c) && !uniques.containsKey(key)) { uniques.put(fnUniqueKey.apply(c), c); } + } + return uniques.values(); + } + public final Iterable uniqueByFirst(final Iterable source, final Lambda1 fnUniqueKey, final Lambda1 accessor) + { // this might be exotic + Map uniques = new Hashtable(); + for (U c : source) { + K key = fnUniqueKey.apply(c); + if (isTrue(accessor.apply(c)) && !uniques.containsKey(key)) { uniques.put(fnUniqueKey.apply(c), c); } + } + return uniques.values(); + } + // Count public final int count(final Iterable source) { int result = 0; @@ -167,6 +205,11 @@ public abstract class Predicate { } // Static builder methods - they choose concrete implementation by themselves + public static Predicate brigde(Predicate predicate, Lambda1 fnBridge) { + // TODO Auto-generated method stub + return new Bridge(predicate, fnBridge); + } + public static Predicate not(final Predicate operand1) { return new Not(operand1); } public static Predicate compose(final Predicate operand1, final PredicatesOp operator, final Predicate operand2) @@ -193,7 +236,12 @@ public abstract class Predicate { public Not(final Predicate operand) { filter = operand; } @Override public boolean isTrue(final T card) { return !filter.isTrue(card); } } - + protected static final class Bridge extends Predicate { + protected final Predicate filter; + protected final Lambda1 fnBridge; + public Bridge(final Predicate operand, final Lambda1 fnTfromU) { filter = operand; fnBridge = fnTfromU; } + @Override public boolean isTrue(final U card) { return filter.isTrue(fnBridge.apply(card)); } + } // binary operators protected static class Node extends Predicate { private final PredicatesOp operator; diff --git a/src/test/java/forge/BoosterDraft_1Test.java b/src/test/java/forge/BoosterDraft_1Test.java index 644956135c8..8df6e7aa916 100644 --- a/src/test/java/forge/BoosterDraft_1Test.java +++ b/src/test/java/forge/BoosterDraft_1Test.java @@ -25,7 +25,7 @@ public class BoosterDraft_1Test { while (draft.hasNextChoice()) { CardPoolView list = draft.nextChoice(); System.out.println(list.countAll()); - draft.setChoice(Predicate.getTrue(CardRules.class).first(list, CardPoolView.fnToCard, CardPoolView.fnToReference)); + draft.setChoice(Predicate.getTrue(CardRules.class).first(list, CardPoolView.fnToCard, CardPoolView.fnToPrinted)); } } }