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

This commit is contained in:
Maxmtg
2011-09-05 22:53:45 +00:00
parent d8bde04f98
commit 582d9ffe16
10 changed files with 141 additions and 34 deletions

View File

@@ -24,11 +24,14 @@ public class CardPoolView implements Iterable<Entry<CardPrinted, Integer>> {
new Lambda1<CardRules, Entry<CardPrinted, Integer>>() { new Lambda1<CardRules, Entry<CardPrinted, Integer>>() {
@Override public CardRules apply(final Entry<CardPrinted, Integer> from) { return from.getKey().getCard(); } @Override public CardRules apply(final Entry<CardPrinted, Integer> from) { return from.getKey().getCard(); }
}; };
public final static Lambda1<CardPrinted, Entry<CardPrinted, Integer>> fnToReference = public final static Lambda1<CardPrinted, Entry<CardPrinted, Integer>> fnToPrinted =
new Lambda1<CardPrinted, Entry<CardPrinted, Integer>>() { new Lambda1<CardPrinted, Entry<CardPrinted, Integer>>() {
@Override public CardPrinted apply(final Entry<CardPrinted, Integer> from) { return from.getKey(); } @Override public CardPrinted apply(final Entry<CardPrinted, Integer> from) { return from.getKey(); }
}; };
public final static Lambda1<String, Entry<CardPrinted, Integer>> fnToCardName =
new Lambda1<String, Entry<CardPrinted, Integer>>() {
@Override public String apply(final Entry<CardPrinted, Integer> from) { return from.getKey().getName(); }
};
public final static Lambda1<Integer, Entry<CardPrinted, Integer>> fnToCount = public final static Lambda1<Integer, Entry<CardPrinted, Integer>> fnToCount =
new Lambda1<Integer, Entry<CardPrinted, Integer>>() { new Lambda1<Integer, Entry<CardPrinted, Integer>>() {
@Override public Integer apply(final Entry<CardPrinted, Integer> from) { return from.getValue(); } @Override public Integer apply(final Entry<CardPrinted, Integer> from) { return from.getValue(); }

View File

@@ -1,10 +1,14 @@
package forge.card; package forge.card;
import java.lang.reflect.Array;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import net.slightlymagic.braids.util.lambda.Lambda1; import net.slightlymagic.braids.util.lambda.Lambda1;
import net.slightlymagic.maxmtg.Predicate; import net.slightlymagic.maxmtg.Predicate;
import net.slightlymagic.maxmtg.Predicate.StringOp;
import forge.AllZone; import forge.AllZone;
import forge.Card; import forge.Card;
import forge.CardUtil; import forge.CardUtil;
@@ -122,8 +126,10 @@ public final class CardPrinted implements Comparable<CardPrinted> {
return cardSet.compareTo(o.cardSet); 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<CardPrinted> rarity(final boolean isEqual, final CardRarity value) public static Predicate<CardPrinted> rarity(final boolean isEqual, final CardRarity value)
{ {
return new PredicateRarity(value, isEqual); return new PredicateRarity(value, isEqual);
@@ -135,6 +141,15 @@ public final class CardPrinted implements Comparable<CardPrinted> {
} }
return new PredicateSets(value, shouldContain); return new PredicateSets(value, shouldContain);
} }
public static Predicate<CardPrinted> 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<CardPrinted> name(final StringOp op, final String what) {
return new PredicateName(op, what);
}
private static class PredicateRarity extends Predicate<CardPrinted> { private static class PredicateRarity extends Predicate<CardPrinted> {
private final CardRarity operand; private final CardRarity operand;
@@ -157,14 +172,39 @@ public final class CardPrinted implements Comparable<CardPrinted> {
@Override public boolean isTrue(final CardPrinted card) { @Override public boolean isTrue(final CardPrinted card) {
return sets.contains(card.cardSet) == mustContain; return sets.contains(card.cardSet) == mustContain;
} }
public PredicateSets(final List<String> wantSets, boolean shouldContain) { public PredicateSets(final List<String> wantSets, final boolean shouldContain) {
sets = wantSets; // maybe should make a copy here? sets = wantSets; // maybe should make a copy here?
mustContain = shouldContain; mustContain = shouldContain;
} }
} }
private static class PredicateName extends Predicate<CardPrinted> {
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 { public abstract static class Presets {
// Think twice before using these, since rarity is a prop of printed card. // Think twice before using these, since rarity is a prop of printed card.

View File

@@ -223,10 +223,12 @@ public final class CardRules {
} }
private boolean op(final String op1, final String op2) { private boolean op(final String op1, final String op2) {
if (operator == StringOp.CONTAINS) { return StringUtils.containsIgnoreCase(op1, op2); } switch (operator) {
if (operator == StringOp.NOT_CONTAINS) { return !StringUtils.containsIgnoreCase(op1, op2); } case CONTAINS: return StringUtils.containsIgnoreCase(op1, op2);
if (operator == StringOp.EQUALS) { return op1.equalsIgnoreCase(op2); } case NOT_CONTAINS: return !StringUtils.containsIgnoreCase(op1, op2);
return false; case EQUALS: return op1.equalsIgnoreCase(op2);
default: return false;
}
} }
public LeafString(final CardField field, final StringOp operator, final String operand) public LeafString(final CardField field, final StringOp operator, final String operand)
@@ -393,6 +395,8 @@ public final class CardRules {
colors.add(isGreen); colors.add(isGreen);
colors.add(isColorless); colors.add(isColorless);
} }
public static final Predicate<CardRules> constantTrue = Predicate.getTrue(CardRules.class);
// Think twice before using these, since rarity is a prop of printed card. // Think twice before using these, since rarity is a prop of printed card.
public static final Predicate<CardRules> isInLatestSetCommon = rarityInCardsLatestSet(true, CardRarity.Common); public static final Predicate<CardRules> isInLatestSetCommon = rarityInCardsLatestSet(true, CardRarity.Common);

View File

@@ -156,7 +156,7 @@ public final class DeckEditor extends DeckEditorBase implements NewConstants {
public DeckEditor() { public DeckEditor() {
try { try {
filterBoxes = new FilterCheckBoxes(true); filterBoxes = new FilterCheckBoxes(true);
top = new TableWithCards("Avaliable Cards", true); top = new TableWithCards("Avaliable Cards", true, true);
bottom = new TableWithCards("Deck", true); bottom = new TableWithCards("Deck", true);
cardView = new CardPanelHeavy(); cardView = new CardPanelHeavy();
@@ -311,24 +311,24 @@ public final class DeckEditor extends DeckEditorBase implements NewConstants {
} }
@Override @Override
protected Predicate<CardRules> buildFilter() { protected Predicate<CardPrinted> buildFilter() {
List<Predicate<CardRules>> rules = new ArrayList<Predicate<CardRules>>(5); List<Predicate<CardPrinted>> rules = new ArrayList<Predicate<CardPrinted>>(5);
rules.add(super.buildFilter()); rules.add(super.buildFilter());
if (StringUtils.isNotBlank(txtCardName.getText())) { 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())) { 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())) { 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) { if (searchSetCombo.getSelectedIndex() != 0) {
String setCode = SetUtils.getCode3ByName(searchSetCombo.getSelectedItem().toString()); 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); return rules.size() == 1 ? rules.get(0) : Predicate.and(rules);

View File

@@ -10,6 +10,7 @@ import javax.swing.JOptionPane;
import net.slightlymagic.maxmtg.Predicate; import net.slightlymagic.maxmtg.Predicate;
import forge.GUI_DeckAnalysis; import forge.GUI_DeckAnalysis;
import forge.card.CardPrinted;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardPoolView; import forge.card.CardPoolView;
@@ -38,9 +39,9 @@ public abstract class DeckEditorBase extends JFrame implements DeckDisplay {
// THIS IS HERE FOR OVERLOADING!!!1 // THIS IS HERE FOR OVERLOADING!!!1
// or may be return abstract getFilter from derived class + this filter ... virtual protected member, but later // or may be return abstract getFilter from derived class + this filter ... virtual protected member, but later
protected Predicate<CardRules> buildFilter() { protected Predicate<CardPrinted> buildFilter() {
if (null == filterBoxes) { if (null == filterBoxes) {
return Predicate.getTrue(CardRules.class); return Predicate.getTrue(CardPrinted.class);
} }
return filterBoxes.buildFilter(); return filterBoxes.buildFilter();
} }

View File

@@ -246,13 +246,10 @@ public class DeckEditorMenu extends JMenuBar implements NewConstants {
currentGameType = Constant.GameType.Constructed; currentGameType = Constant.GameType.Constructed;
setDeckData("", false); setDeckData("", false);
// This is an expensive heap operation.
CardPool allCards = new CardPool(); 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 }//new constructed
/** /**
@@ -302,7 +299,7 @@ public class DeckEditorMenu extends JMenuBar implements NewConstants {
GenerateConstructedDeck gen = new GenerateConstructedDeck(); GenerateConstructedDeck gen = new GenerateConstructedDeck();
// This is an expensive heap operation. // This is an expensive heap operation.
CardPool allCards = new CardPool( CardDb.instance().getAllUniqueCards() ); CardPool allCards = new CardPool( CardDb.instance().getAllCards() );
CardPool generated = new CardPool(); CardPool generated = new CardPool();
for (Card c : gen.generateDeck()) { generated.add( CardDb.instance().getCard(c)); } for (Card c : gen.generateDeck()) { generated.add( CardDb.instance().getCard(c)); }

View File

@@ -7,6 +7,7 @@ import java.util.List;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import net.slightlymagic.maxmtg.Predicate; import net.slightlymagic.maxmtg.Predicate;
import forge.card.CardPrinted;
import forge.card.CardRules; import forge.card.CardRules;
/** /**
@@ -71,7 +72,7 @@ class FilterCheckBoxes {
} }
public final Predicate<CardRules> buildFilter() { public final Predicate<CardPrinted> buildFilter() {
List<Predicate<CardRules>> colors = new ArrayList<Predicate<CardRules>>(); List<Predicate<CardRules>> colors = new ArrayList<Predicate<CardRules>>();
if (white.isSelected()) { colors.add(CardRules.Predicates.Presets.isWhite); } if (white.isSelected()) { colors.add(CardRules.Predicates.Presets.isWhite); }
if (blue.isSelected()) { colors.add(CardRules.Predicates.Presets.isBlue); } 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 (planeswalker.isSelected()) { types.add(CardRules.Predicates.Presets.isPlaneswalker); }
if (artifact.isSelected()) { types.add(CardRules.Predicates.Presets.isArtifact); } if (artifact.isSelected()) { types.add(CardRules.Predicates.Presets.isArtifact); }
if (enchantment.isSelected()) { types.add(CardRules.Predicates.Presets.isEnchantment); } if (enchantment.isSelected()) { types.add(CardRules.Predicates.Presets.isEnchantment); }
Predicate<CardRules> filterByType = colors.size() == 7 ? Predicate.getTrue(CardRules.class) : Predicate.or(types); Predicate<CardRules> 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);
} }
} }

View File

@@ -33,8 +33,9 @@ public final class TableWithCards {
protected JTable table = new JTable(); protected JTable table = new JTable();
protected JScrollPane jScrollPane = new JScrollPane(); protected JScrollPane jScrollPane = new JScrollPane();
protected JLabel statsLabel = new JLabel(); protected JLabel statsLabel = new JLabel();
protected Predicate<CardRules> filter = null; protected Predicate<CardPrinted> filter = null;
protected boolean isTrackingStats = false; protected boolean isTrackingStats = false;
protected boolean wantUnique = false;
// need this to allow users place its contents // need this to allow users place its contents
public JComponent getTableDecorated() { return jScrollPane; } public JComponent getTableDecorated() { return jScrollPane; }
@@ -42,6 +43,9 @@ public final class TableWithCards {
public JComponent getLabel() { return statsLabel; } public JComponent getLabel() { return statsLabel; }
public TableWithCards(final String title, final boolean showStats) { public TableWithCards(final String title, final boolean showStats) {
this(title, showStats, false);
}
public TableWithCards(final String title, final boolean showStats, final boolean forceUnique) {
// components // components
Color gray = new Color(148, 145, 140); Color gray = new Color(148, 145, 140);
TitledBorder titledBorder = new TitledBorder(BorderFactory.createEtchedBorder(Color.white, gray), title); TitledBorder titledBorder = new TitledBorder(BorderFactory.createEtchedBorder(Color.white, gray), title);
@@ -56,6 +60,7 @@ public final class TableWithCards {
// class data // class data
isTrackingStats = showStats; isTrackingStats = showStats;
wantUnique = forceUnique;
} }
public void setup(final List<TableColumnInfo<CardPrinted>> columns, final CardPanelBase cardView) public void setup(final List<TableColumnInfo<CardPrinted>> columns, final CardPanelBase cardView)
@@ -137,7 +142,7 @@ public final class TableWithCards {
private boolean isUnfiltered() { return filter == null || filter.is1(); } private boolean isUnfiltered() { return filter == null || filter.is1(); }
private boolean isFiltered() { return filter != null && !filter.is1(); } private boolean isFiltered() { return filter != null && !filter.is1(); }
public void setFilter(final Predicate<CardRules> filterToSet) { public void setFilter(final Predicate<CardPrinted> filterToSet) {
filter = filterToSet; filter = filterToSet;
updateView(); updateView();
} }
@@ -158,10 +163,18 @@ public final class TableWithCards {
} }
public void updateView() { public void updateView() {
if (isFiltered()) { if (isFiltered() || wantUnique) {
model.clear(); 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(); model.resort();
} }

View File

@@ -1,7 +1,13 @@
package net.slightlymagic.maxmtg; package net.slightlymagic.maxmtg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map;
import forge.card.CardPrinted;
import forge.card.CardRules;
import net.slightlymagic.braids.util.lambda.Lambda1; import net.slightlymagic.braids.util.lambda.Lambda1;
/** /**
@@ -104,6 +110,38 @@ public abstract class Predicate<T> {
} }
} }
// Unique
public final <K> Iterable<T> uniqueByLast(final Iterable<T> source, final Lambda1<K, T> fnUniqueKey)
{
Map<K, T> uniques = new Hashtable<K, T>();
for (T c : source) { if (isTrue(c)) { uniques.put(fnUniqueKey.apply(c), c); } }
return uniques.values();
}
public final <K, U> Iterable<U> uniqueByLast(final Iterable<U> source, final Lambda1<K, U> fnUniqueKey, final Lambda1<T, U> accessor)
{ // this might be exotic
Map<K, U> uniques = new Hashtable<K, U>();
for (U c : source) { if (isTrue(accessor.apply(c))) { uniques.put(fnUniqueKey.apply(c), c); } }
return uniques.values();
}
public final <K> Iterable<T> uniqueByFirst(final Iterable<T> source, final Lambda1<K, T> fnUniqueKey)
{
Map<K, T> uniques = new Hashtable<K, T>();
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 <K, U> Iterable<U> uniqueByFirst(final Iterable<U> source, final Lambda1<K, U> fnUniqueKey, final Lambda1<T, U> accessor)
{ // this might be exotic
Map<K, U> uniques = new Hashtable<K, U>();
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 // Count
public final int count(final Iterable<T> source) { public final int count(final Iterable<T> source) {
int result = 0; int result = 0;
@@ -167,6 +205,11 @@ public abstract class Predicate<T> {
} }
// Static builder methods - they choose concrete implementation by themselves // Static builder methods - they choose concrete implementation by themselves
public static <U, T> Predicate<U> brigde(Predicate<T> predicate, Lambda1<T, U> fnBridge) {
// TODO Auto-generated method stub
return new Bridge<T, U>(predicate, fnBridge);
}
public static <T> Predicate<T> not(final Predicate<T> operand1) { return new Not<T>(operand1); } public static <T> Predicate<T> not(final Predicate<T> operand1) { return new Not<T>(operand1); }
public static <T> Predicate<T> compose(final Predicate<T> operand1, public static <T> Predicate<T> compose(final Predicate<T> operand1,
final PredicatesOp operator, final Predicate<T> operand2) final PredicatesOp operator, final Predicate<T> operand2)
@@ -193,7 +236,12 @@ public abstract class Predicate<T> {
public Not(final Predicate<T> operand) { filter = operand; } public Not(final Predicate<T> operand) { filter = operand; }
@Override public boolean isTrue(final T card) { return !filter.isTrue(card); } @Override public boolean isTrue(final T card) { return !filter.isTrue(card); }
} }
protected static final class Bridge<T, U> extends Predicate<U> {
protected final Predicate<T> filter;
protected final Lambda1<T, U> fnBridge;
public Bridge(final Predicate<T> operand, final Lambda1<T, U> fnTfromU) { filter = operand; fnBridge = fnTfromU; }
@Override public boolean isTrue(final U card) { return filter.isTrue(fnBridge.apply(card)); }
}
// binary operators // binary operators
protected static class Node<T> extends Predicate<T> { protected static class Node<T> extends Predicate<T> {
private final PredicatesOp operator; private final PredicatesOp operator;

View File

@@ -25,7 +25,7 @@ public class BoosterDraft_1Test {
while (draft.hasNextChoice()) { while (draft.hasNextChoice()) {
CardPoolView list = draft.nextChoice(); CardPoolView list = draft.nextChoice();
System.out.println(list.countAll()); 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));
} }
} }
} }