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); } }