diff --git a/.gitattributes b/.gitattributes index b9177b16245..51bf55fd691 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9833,6 +9833,7 @@ src/main/java/net/slightlymagic/braids/util/progress_monitor/BaseProgressMonitor src/main/java/net/slightlymagic/braids/util/progress_monitor/BraidsProgressMonitor.java svneol=native#text/plain src/main/java/net/slightlymagic/braids/util/progress_monitor/StderrProgressMonitor.java svneol=native#text/plain src/main/java/net/slightlymagic/braids/util/progress_monitor/package-info.java svneol=native#text/plain +src/main/java/net/slightlymagic/maxmtg/Predicate.java -text src/main/java/treeProperties/PropertyElement.java svneol=native#text/plain src/main/java/treeProperties/PropertyType.java svneol=native#text/plain src/main/java/treeProperties/TreeProperties.java svneol=native#text/plain diff --git a/src/main/java/net/slightlymagic/maxmtg/Predicate.java b/src/main/java/net/slightlymagic/maxmtg/Predicate.java new file mode 100644 index 00000000000..b3f57dad0f2 --- /dev/null +++ b/src/main/java/net/slightlymagic/maxmtg/Predicate.java @@ -0,0 +1,230 @@ +package net.slightlymagic.maxmtg; + +import java.util.ArrayList; +import java.util.List; + +import net.slightlymagic.braids.util.lambda.Lambda1; +/** + * Predicate class allows to select items or type , which are or contain an object of type , + * matching to some criteria set by predicate. No need to write that simple operations by hand. + * + * @author Max + * + * @param - class to check condition against + */ + +public abstract class Predicate { + /** + * Possible operators on two predicates + * @author Max + * + */ + public enum PredicatesOp { AND, OR, XOR, EQ, NOR, NAND } + + /** + * Possible operators for comparables. + * @author Max + * + */ + public enum ComparableOp { EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, GT_OR_EQUAL, LT_OR_EQUAL } + + /** + * Possible operators for string operands. + * @author Max + * + */ + public enum StringOp { CONTAINS, NOT_CONTAINS, EQUALS } + + public abstract boolean isTrue(T subject); + // 1. operations on pure T ... check(T card), list.add(card) + // 2. operations on something U containing CardOracles ... check(accessor(U)), list.add(U) + // 3. gets T from U, saves U transformed into v ... check(accessor(U)), list.add(transformer(U)) + + // selects are fun + public final List select(final Iterable source) { + ArrayList result = new ArrayList(); + if (source != null) for (T c : source) { if (isTrue(c)) { result.add(c); } } + return result; + } + public final List select(final Iterable source, final Lambda1 accessor) { + ArrayList result = new ArrayList(); + if (source != null) for (U c : source) { if (isTrue(accessor.apply(c))) { result.add(c); } } + return result; + } + public final List select(final Iterable source, final Lambda1 cardAccessor, + final Lambda1 transformer) + { + ArrayList result = new ArrayList(); + if (source != null) for (U c : source) { if (isTrue(cardAccessor.apply(c))) { result.add(transformer.apply(c)); } } + return result; + } + + // select top 1 + public final T first(final Iterable source) { + if (source != null) for (T c : source) { if (isTrue(c)) { return c; } } + return null; + } + public final U first(final Iterable source, final Lambda1 accessor) { + if (source != null) for (U c : source) { if (isTrue(accessor.apply(c))) { return c; } } + return null; + } + public final V first(final Iterable source, final Lambda1 cardAccessor, + final Lambda1 transformer) + { + if (source != null) for (U c : source) { if (isTrue(cardAccessor.apply(c))) { return transformer.apply(c); } } + return null; + } + + // splits are even more fun + public final void split(final Iterable source, + final List trueList, final List falseList) + { + if (source != null) for (T c : source) { if (isTrue(c)) { trueList.add(c); } else { falseList.add(c); } } + } + public final void split(final Iterable source, final Lambda1 accessor, + final List trueList, final List falseList) + { + if (source != null) for (U c : source) { if (isTrue(accessor.apply(c))) { trueList.add(c); } else { falseList.add(c); } } + } + public final void split(final Iterable source, final Lambda1 cardAccessor, + final Lambda1 transformer, final List trueList, final List falseList) + { + if (source != null) for (U c : source) { + if (isTrue(cardAccessor.apply(c))) { trueList.add(transformer.apply(c)); } + else { falseList.add(transformer.apply(c)); } + } + } + + // Count + public final int count(final Iterable source) { + int result = 0; + if (source != null) for (T c : source) { if (isTrue(c)) { result++; } } + return result; + } + public final int count(final Iterable source, final Lambda1 accessor) { + int result = 0; + if (source != null) for (U c : source) { if (isTrue(accessor.apply(c))) { result++; } } + return result; + } + + // Aggregates? + public final int aggregate(final Iterable source, final Lambda1 accessor, + final Lambda1 valueAccessor) + { + int result = 0; + if (source != null) for (U c : source) { if (isTrue(accessor.apply(c))) { result += valueAccessor.apply(c); } } + return result; + } + + // Random - algorithm adapted from Braid's GeneratorFunctions + public final T random(final Iterable source) { // + int n = 0; + T candidate = null; + for (T item : source) { + if (!isTrue(item)) { continue; } + if (Math.random() * ++n < 1) { candidate = item; } + } + return candidate; + } + public final U random(final Iterable source, final Lambda1 accessor) { + int n = 0; + U candidate = null; + for (U item : source) { + if (!isTrue(accessor.apply(item))) { continue; } + if (Math.random() * ++n < 1) { candidate = item; } + } + return candidate; + } + // Static builder methods - they choose concrete implementation by themselves + public static Predicate not(final Predicate operand1) { return new Not(operand1); } + public static Predicate compose(final Predicate operand1, + final PredicatesOp operator, final Predicate operand2) + { + return new Node(operand1, operator, operand2); + } + public static Predicate and(final Predicate operand1, final Predicate operand2) { + return new NodeAnd(operand1, operand2); + } + public static Predicate and(final Iterable> operand) { return new MultiNodeAnd(operand); } + public static Predicate or(final Predicate operand1, final Predicate operand2) { + return new NodeOr(operand1, operand2); + } + public static Predicate or(final Iterable> operand) { return new MultiNodeOr(operand); } + + // Concrete implementations + // unary operators + protected static final class Not extends Predicate { + protected final Predicate filter; + public Not(final Predicate operand) { filter = operand; } + @Override public boolean isTrue(final T card) { return !filter.isTrue(card); } + } + + // binary operators + protected static class Node extends Predicate { + private final PredicatesOp operator; + protected final Predicate filter1; + protected final Predicate filter2; + + public Node(final Predicate operand1, final PredicatesOp op, final Predicate operand2) + { + operator = op; + filter1 = operand1; + filter2 = operand2; + } + + @Override public boolean isTrue(final T card) { + switch (operator) { + case AND: return filter1.isTrue(card) && filter2.isTrue(card); + case NAND: return !(filter1.isTrue(card) && filter2.isTrue(card)); + case OR: return filter1.isTrue(card) || filter2.isTrue(card); + case NOR: return !(filter1.isTrue(card) || filter2.isTrue(card)); + case XOR: return filter1.isTrue(card) ^ filter2.isTrue(card); + case EQ: return filter1.isTrue(card) == filter2.isTrue(card); + default: return false; + } + } + } + protected static final class NodeOr extends Node { + public NodeOr(final Predicate operand1, final Predicate operand2) { + super(operand1, PredicatesOp.OR, operand2); + } + @Override public boolean isTrue(final T card) { return filter1.isTrue(card) || filter2.isTrue(card); } + } + protected static final class NodeAnd extends Node { + public NodeAnd(final Predicate operand1, final Predicate operand2) { + super(operand1, PredicatesOp.AND, operand2); + } + @Override public boolean isTrue(final T card) { return filter1.isTrue(card) && filter2.isTrue(card); } + } + + // multi-operand operators + protected abstract static class MultiNode extends Predicate { + protected final Iterable> operands; + public MultiNode(Iterable> filters) { operands = filters; } + } + protected final static class MultiNodeAnd extends MultiNode { + public MultiNodeAnd(final Iterable> filters) { super(filters); } + @Override public boolean isTrue(final T subject) { + for (Predicate p : operands) { if (!p.isTrue(subject)) { return false; } } + return true; + } + } + protected final static class MultiNodeOr extends MultiNode { + public MultiNodeOr(final Iterable> filters) { super(filters); } + @Override public boolean isTrue(final T subject) { + for (Predicate p : operands) { if (p.isTrue(subject)) { return true; } } + return false; + } + } + + protected static class LeafConstant extends Predicate { + private final boolean bValue; + + @Override + public boolean isTrue(final T card) { return bValue; } + public LeafConstant(final boolean value) { bValue = value; } + } + + public static Predicate getTrue(final Class cls) { return new LeafConstant(true); } + public static Predicate getFalse(final Class cls) { return new LeafConstant(false); } +}