From eda9a86d8d48758e9982cfffd470c3b38a0a4b0b Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Sat, 21 Nov 2020 23:11:43 -0500 Subject: Make dice generic Convert dice from dealing exclusively with ints, to deal with objects of arbitrary types --- dice/src/main/java/bjc/dicelang/neodice/Die.java | 82 -------- .../main/java/bjc/dicelang/neodice/DiePool.java | 199 ------------------ dice/src/main/java/bjc/dicelang/neodice/IDie.java | 96 +++++++++ .../main/java/bjc/dicelang/neodice/IDiePool.java | 222 +++++++++++++++++++++ .../bjc/dicelang/neodice/die/PolyhedralDie.java | 4 +- .../java/bjc/dicelang/neodice/die/RerollDie.java | 75 +++++-- .../dicelang/neodice/diepool/DropFirstPool.java | 58 ------ .../bjc/dicelang/neodice/diepool/DropLastPool.java | 58 ------ .../dicelang/neodice/diepool/ExpandDiePool.java | 25 +++ .../dicelang/neodice/diepool/FilteredDiePool.java | 47 ----- .../bjc/dicelang/neodice/diepool/FixedDiePool.java | 53 ++--- .../dicelang/neodice/diepool/KeepFirstDiePool.java | 58 ------ .../dicelang/neodice/diepool/KeepLastDiePool.java | 58 ------ .../dicelang/neodice/diepool/SortedDiePool.java | 63 ------ .../bjc/dicelang/neodice/diepool/TimesDiePool.java | 26 +-- .../dicelang/neodice/diepool/TransformDiePool.java | 52 +++++ 16 files changed, 486 insertions(+), 690 deletions(-) delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/Die.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/DiePool.java create mode 100644 dice/src/main/java/bjc/dicelang/neodice/IDie.java create mode 100644 dice/src/main/java/bjc/dicelang/neodice/IDiePool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/DropFirstPool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/DropLastPool.java create mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/ExpandDiePool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/FilteredDiePool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/KeepFirstDiePool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/KeepLastDiePool.java delete mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/SortedDiePool.java create mode 100644 dice/src/main/java/bjc/dicelang/neodice/diepool/TransformDiePool.java (limited to 'dice/src/main/java') diff --git a/dice/src/main/java/bjc/dicelang/neodice/Die.java b/dice/src/main/java/bjc/dicelang/neodice/Die.java deleted file mode 100644 index 9bcbb0f..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/Die.java +++ /dev/null @@ -1,82 +0,0 @@ -package bjc.dicelang.neodice; - -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import bjc.dicelang.neodice.die.*; -import bjc.dicelang.neodice.diepool.*; - -/** - * Represents a single polyhedral die. - * @author Ben Culkin - * - */ -@FunctionalInterface -public interface Die { - /** - * Rolls this die. - * - * @param rng The source for random numbers - * - * @return The result of rolling the die. - */ - public int roll(Random rng); - - /** - * Returns a die pool which rolls this die the specified number of times. - * - * @param numTimes The number of times to roll this die. - * - * @return A die pool that rolls this die the specified number of times. - */ - default DiePool times(int numTimes) { - return new TimesDiePool(this, numTimes); - }; - - /** - * Returns a die which will reroll this die as long as the provided condition is true. - * - * @param condition The condition to reroll the die on. - * - * @return A die that rerolls when the given condition is met. - */ - default Die reroll(IntPredicate condition) { - return new RerollDie(this, condition, (lst) -> lst.get(lst.size())); - } - - /** - * Returns a die which will reroll this die up to a specified number of times, - * as long as the provided condition is true. - * - * @param condition The condition to reroll the die on. - * @param limit The maximum number of times to reroll the die. - * - * @return A die that rerolls when the given condition is met. - */ - default Die reroll(IntPredicate condition, int limit) { - return new RerollDie(this, condition, (lst) -> lst.get(lst.size()), limit); - } - - /** - * Create an iterator which gives rolls of this dice. - * - * @param rng The source for random numbers. - * - * @return An iterator which gives rolls of this dice. - */ - default Iterator iterator(Random rng) { - return IntStream.generate(() -> this.roll(rng)).iterator(); - } - - /** - * Create a simple polyhedral die with a fixed number of sides. - * - * @param sides The number of sides for the die. - * - * @return A die which returns a result from 1 to sides. - */ - static Die polyhedral(int sides) { - return new PolyhedralDie(sides); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/DiePool.java b/dice/src/main/java/bjc/dicelang/neodice/DiePool.java deleted file mode 100644 index ac35988..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/DiePool.java +++ /dev/null @@ -1,199 +0,0 @@ -package bjc.dicelang.neodice; - -import java.util.*; -import java.util.function.*; - -import bjc.dicelang.neodice.diepool.*; - -/** - * Represents a pool of dice. - * - * @author Ben Culkin - * - */ -@FunctionalInterface -public interface DiePool { - /** - * Roll each die in the pool, and return the results. - * - * Note that this array is not guaranteed to be the same size every time it - * is rolled, because there are some pool types that could add/remove dice. - * - * @param rng The source for random numbers - * - * @return The result of rolling each die in the pool. - */ - public int[] roll(Random rng); - - /** - * Gets the dice contained in this pool. - * - * Note that the length of this array may not be the same as the length of - * the array returned by roll, because certain pool types may add additional - * dice. - * - * Also note that this array (and the Die instances contained in it) should - * not be modified. That may work for certain pool types, but it isn't - * guaranteed to work, and can lead to unintuitive behavior. For instances, - * certain pool types may return an array where multiple elements of it refer - * to the same Die instance. - * - * The default implementation throws an UnsupportedOperationException. - * - * @return The dice contained in this pool. - * - * @throws UnsupportedOperationException If the composite dice can't be retrieved. - */ - default Die[] contained() { - throw new UnsupportedOperationException("Can't get composite dice"); - } - - /* - * These die pool operations transform this pool in some way. - */ - - /** - * Returns a version of this die pool which returns its results in sorted - * order. - * - * At the moment, sorting in descending order is somewhat less efficent than - * sorting in ascending order, because Java doesn't provide a built-in - * descending sort for primitive arrays. - * - * @param isDescending True to sort in descending order, false to sort in ascending order. - * - * @return The die pool, which returns its results in sorted order. - */ - default DiePool sorted(boolean isDescending) { - return new SortedDiePool(this, isDescending); - } - - /** - * Return a die pool which rolls this one, then filters out any results that - * don't match the provided predicate. - * - * @param matcher The predicate that determines - * - * @return A die pool which contains only entries that pass the predicate. - */ - default DiePool filtered(IntPredicate matcher) { - return new FilteredDiePool(this, matcher); - } - - /** - * Return a die pool which rolls this one, then drops a number of the first values. - * - * @param number The number of first values to drop. - * - * @return A die pool which has the first entries dropped. - */ - default DiePool dropFirst(int number) { - return new DropFirstPool(this, number); - } - - /** - * Return a die pool which rolls this one, then drops a number of the last values. - * - * @param number The number of last values to drop. - * - * @return A die pool which has the last entries dropped. - */ - default DiePool dropLast(int number) { - return new DropLastPool(this, number); - } - - /** - * Return a die pool which rolls this one, then keeps a number of the first values. - * - * @param number The number of first values to keep. - * - * @return A die pool which has the first entries kept. - */ - default DiePool keepFirst(int number) { - return new KeepFirstDiePool(this, number); - } - - /** - * Return a die pool which rolls this one, then keeps a number of the last values. - * - * @param number The number of last values to keep. - * - * @return A die pool which has the last entries kept. - */ - default DiePool keepLast(int number) { - return new KeepLastDiePool(this, number); - } - - /* - * These die-pool operations are formed exclusively through other die pool - * operations. - */ - - /** - * Return a die pool which rolls this one, then drops a number of the lowest values. - * - * @param number The number of lowest values to drop. - * - * @return A die pool which has the lowest entries dropped. - */ - default DiePool dropLowest(int number) { - return this.sorted(false).dropFirst(number); - } - - /** - * Return a die pool which rolls this one, then drops a number of the lowest values. - * - * @param number The number of lowest values to drop. - * - * @return A die pool which has the lowest entries dropped. - */ - default DiePool dropHighest(int number) { - return this.sorted(false).dropLast(number); - } - - /** - * Return a die pool which rolls this one, then keeps a number of the lowest values. - * - * @param number The number of lowest values to keep. - * - * @return A die pool which has the lowest entries kept. - */ - default DiePool keepLowest(int number) { - return this.sorted(false).keepFirst(number); - } - - /** - * Return a die pool which rolls this one, then keeps a number of the highest values. - * - * @param number The number of highest values to keep. - * - * @return A die pool which has the highest entries kept. - */ - default DiePool keepHighest(int number) { - return this.sorted(false).keepLast(number); - } - - /* These are misc. operations that don't form new dice pools. */ - - /** - * Get an iterator which iterates over a single roll of this die pool. - * - * @param rng The source of random numbers. - * - * @return An iterator over a single roll of this die pool. - */ - default Iterator iterator(Random rng) { - return Arrays.stream(this.roll(rng)).iterator(); - } - - /** - * Create a die pool containing the provided dice. - * - * @param dice The dice to put into the pool. - * - * @return A pool which contains the provided dice. - */ - static DiePool containing(Die... dice) { - return new FixedDiePool(dice); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/IDie.java b/dice/src/main/java/bjc/dicelang/neodice/IDie.java new file mode 100644 index 0000000..274af66 --- /dev/null +++ b/dice/src/main/java/bjc/dicelang/neodice/IDie.java @@ -0,0 +1,96 @@ +package bjc.dicelang.neodice; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import bjc.dicelang.neodice.die.*; +import bjc.dicelang.neodice.diepool.*; + +/** + * Represents a single polyhedral die. + * @author Ben Culkin + * + */ +@FunctionalInterface +public interface IDie { + /** + * Rolls this die. + * + * @param rng The source for random numbers + * + * @return The result of rolling the die. + */ + public SideType roll(Random rng); + + /** + * Returns a die pool which rolls this die the specified number of times. + * + * @param numTimes The number of times to roll this die. + * + * @return A die pool that rolls this die the specified number of times. + */ + default IDiePool times(int numTimes) { + return new ExpandDiePool<>(this, (die, rng) -> { + return Stream.generate(() -> die.roll(rng)) + .limit(numTimes); + }); + }; + + /** + * Returns a die which will reroll this die as long as the provided condition is true. + * + * @param condition The condition to reroll the die on. + * + * @return A die that rerolls when the given condition is met. + */ + default IDie reroll( + Comparator comparer, + Predicate condition) { + return RerollDie.create(comparer, this, condition, + (list) -> list.get(list.size())); + } + + /** + * Returns a die which will reroll this die up to a specified number of times, + * as long as the provided condition is true. + * + * @param condition The condition to reroll the die on. + * @param limit The maximum number of times to reroll the die. + * + * @return A die that rerolls when the given condition is met. + */ + default IDie reroll( + Comparator comparer, + Predicate condition, + int limit) { + return RerollDie.create(comparer, this, condition, + (list) -> list.get(list.size()), limit); + } + + /** + * Create an stream which gives rolls of this dice. + * + * @param rng The source for random numbers. + * + * @return An iterator which gives rolls of this dice. + */ + default Stream stream(Random rng) { + return Stream.generate(() -> this.roll(rng)); + } + + default IDie transform(Function mapper) { + return (rng) -> mapper.apply(this.roll(rng)); + } + + /** + * Create a simple polyhedral die with a fixed number of sides. + * + * @param sides The number of sides for the die. + * + * @return A die which returns a result from 1 to sides. + */ + static IDie polyhedral(int sides) { + return new PolyhedralDie(sides); + } +} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/IDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/IDiePool.java new file mode 100644 index 0000000..b887784 --- /dev/null +++ b/dice/src/main/java/bjc/dicelang/neodice/IDiePool.java @@ -0,0 +1,222 @@ +package bjc.dicelang.neodice; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import bjc.dicelang.neodice.diepool.*; + +/** + * Represents a pool of dice. + * + * @author Ben Culkin + * + */ +@FunctionalInterface +public interface IDiePool { + /** + * Roll each die in the pool, and return the results. + * + * Note that this list is not guaranteed to be the same size every time it + * is rolled, because there are some pool types that could add/remove dice. + * + * @param rng The source for random numbers + * + * @return The result of rolling each die in the pool. + */ + public Stream roll(Random rng); + + /** + * Gets the dice contained in this pool. + * + * Note that the length of this list may not be the same as the length of + * the list returned by roll, because certain pool types may add additional + * dice. + * + * Also note that this list (and the Die instances contained in it) should + * not be modified. That may work for certain pool types, but it isn't + * guaranteed to work, and can lead to unintuitive behavior. For instances, + * certain pool types may return an list where multiple elements of it refer + * to the same Die instance. + * + * The default implementation throws an UnsupportedOperationException. + * + * @return The dice contained in this pool. + * + * @throws UnsupportedOperationException If the composite dice can't be retrieved. + */ + default List> contained() { + throw new UnsupportedOperationException("Can't get composite dice"); + } + + /* + * These die pool operations transform this pool in some way. + */ + + /** + * Returns a version of this die pool which returns its results in sorted + * order. + * + * @param isDescending True to sort in descending order, false to sort in ascending order. + * + * @return The die pool, which returns its results in sorted order. + */ + default IDiePool sorted( + Comparator comparer, + boolean isDescending) { + return new TransformDiePool<>(this, + (pool) -> pool.sorted( + isDescending + ? comparer.reversed() + : comparer)); + } + + /** + * Return a die pool which rolls this one, then filters out any results that + * don't match the provided predicate. + * + * @param matcher The predicate that determines + * + * @return A die pool which contains only entries that pass the predicate. + */ + default IDiePool filtered(Predicate matcher) { + return new TransformDiePool<>(this, + (pool) -> pool.filter(matcher)); + } + + /** + * Return a die pool which rolls this one, then drops a number of the first values. + * + * @param number The number of first values to drop. + * + * @return A die pool which has the first entries dropped. + */ + default IDiePool dropFirst(int number) { + return new TransformDiePool<>(this, + (pool) -> pool.skip(number)); + } + + /** + * Return a die pool which rolls this one, then drops a number of the last values. + * + * @param number The number of last values to drop. + * + * @return A die pool which has the last entries dropped. + */ + default IDiePool dropLast(int number) { + return new TransformDiePool<>(this, (pool) -> { + Deque temp = new ArrayDeque<>(); + + pool.forEachOrdered((die) -> temp.add(die)); + + for (int i = 0; i < number; i++) temp.pollLast(); + + return temp.stream(); + }); + } + + /** + * Return a die pool which rolls this one, then keeps a number of the first values. + * + * @param number The number of first values to keep. + * + * @return A die pool which has the first entries kept. + */ + default IDiePool keepFirst(int number) { + return new TransformDiePool<>(this, + (pool) -> pool.limit(number)); + } + + /** + * Return a die pool which rolls this one, then keeps a number of the last values. + * + * @param number The number of last values to keep. + * + * @return A die pool which has the last entries kept. + */ + default IDiePool keepLast(int number) { + return new TransformDiePool<>(this, (pool) -> { + Deque temp = new ArrayDeque<>(); + + pool.forEachOrdered((die) -> temp.add(die)); + + while (temp.size() > number) temp.pollFirst(); + + return temp.stream(); + }); + } + + /* + * These die-pool operations are formed exclusively through other die pool + * operations. + */ + + /** + * Return a die pool which rolls this one, then drops a number of the lowest values. + * + * @param number The number of lowest values to drop. + * + * @return A die pool which has the lowest entries dropped. + */ + default IDiePool dropLowest(Comparator comparer, int number) { + return this.sorted(comparer, false).dropFirst(number); + } + + /** + * Return a die pool which rolls this one, then drops a number of the lowest values. + * + * @param number The number of lowest values to drop. + * + * @return A die pool which has the lowest entries dropped. + */ + default IDiePool dropHighest(Comparator comparer,int number) { + return this.sorted(comparer, false).dropLast(number); + } + + /** + * Return a die pool which rolls this one, then keeps a number of the lowest values. + * + * @param number The number of lowest values to keep. + * + * @return A die pool which has the lowest entries kept. + */ + default IDiePool keepLowest(Comparator comparer,int number) { + return this.sorted(comparer, false).keepFirst(number); + } + + /** + * Return a die pool which rolls this one, then keeps a number of the highest values. + * + * @param number The number of highest values to keep. + * + * @return A die pool which has the highest entries kept. + */ + default IDiePool keepHighest(Comparator comparer,int number) { + return this.sorted(comparer, false).keepLast(number); + } + + /* These are misc. operations that don't form new dice pools. */ + + /** + * Get an iterator which iterates over a single roll of this die pool. + * + * @param rng The source of random numbers. + * + * @return An iterator over a single roll of this die pool. + */ + default Iterator iterator(Random rng) { + return this.roll(rng).iterator(); + } + + /** + * Create a die pool containing the provided dice. + * + * @param dice The dice to put into the pool. + * + * @return A pool which contains the provided dice. + */ + @SafeVarargs + static IDiePool containing(IDie... dice) { + return new FixedDiePool<>(dice); + } +} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/die/PolyhedralDie.java b/dice/src/main/java/bjc/dicelang/neodice/die/PolyhedralDie.java index c1bb2ac..2909724 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/die/PolyhedralDie.java +++ b/dice/src/main/java/bjc/dicelang/neodice/die/PolyhedralDie.java @@ -4,7 +4,7 @@ import java.util.*; import bjc.dicelang.neodice.*; -public class PolyhedralDie implements Die { +public class PolyhedralDie implements IDie { private final int sides; public PolyhedralDie(int sides) { @@ -12,7 +12,7 @@ public class PolyhedralDie implements Die { } @Override - public int roll(Random rng) { + public Integer roll(Random rng) { // Dice are one-based, not zero-based. return rng.nextInt(sides) + 1; } diff --git a/dice/src/main/java/bjc/dicelang/neodice/die/RerollDie.java b/dice/src/main/java/bjc/dicelang/neodice/die/RerollDie.java index 3cd369f..f8cb0fa 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/die/RerollDie.java +++ b/dice/src/main/java/bjc/dicelang/neodice/die/RerollDie.java @@ -6,39 +6,45 @@ import java.util.function.*; import bjc.dicelang.neodice.*; import bjc.esodata.*; -public class RerollDie implements Die { - private final Die contained; +public class RerollDie implements IDie { + private final IDie contained; - private final IntPredicate condition; - private final Function, Integer> chooser; + private final Predicate condition; + private final Function, SideType> chooser; - private int limit = Integer.MAX_VALUE; + private final Comparator comparer; + private int limit = Integer.MAX_VALUE; - public RerollDie(Die contained, IntPredicate condition, - Function, Integer> chooser) { + private RerollDie( + Comparator comparer, + IDie contained, + Predicate condition, + Function, SideType> chooser) { + this.comparer = comparer; + this.contained = contained; this.condition = condition; this.chooser = chooser; } - public RerollDie(Die contained, IntPredicate condition, - Function, Integer> chooser, int limit) { - this.contained = contained; - - this.condition = condition; - this.chooser = chooser; + private RerollDie( + Comparator comparer, + IDie contained, + Predicate condition, + Function, SideType> chooser, + int limit) { + this(comparer, contained, condition, chooser); this.limit = limit; } @Override - public int roll(Random rng) { - int roll = contained.roll(rng); - - MinMaxList newRolls = new MinMaxList( - Comparator.naturalOrder(), roll); + public SideType roll(Random rng) { + SideType roll = contained.roll(rng); + + MinMaxList newRolls = new MinMaxList<>(comparer, roll); int rerollCount = 0; while (condition.test(roll) && rerollCount < limit) { @@ -51,5 +57,36 @@ public class RerollDie implements Die { return chooser.apply(newRolls); } - // No toString, because IntPredicate can't be converted to a string + public static > IDie create( + IDie contained, + Predicate condition, + Function, Side> chooser) { + return new RerollDie<>(Comparator.naturalOrder(), contained, condition, chooser); + } + + public static > IDie create( + IDie contained, + Predicate condition, + Function, Side> chooser, + int limit) { + return new RerollDie<>(Comparator.naturalOrder(), contained, condition, chooser, limit); + } + + + public static IDie create( + Comparator comparer, + IDie contained, + Predicate condition, + Function, Side> chooser) { + return new RerollDie(comparer, contained, condition, chooser); + } + + public static IDie create( + Comparator comparer, + IDie contained, + Predicate condition, + Function, Side> chooser, + int limit) { + return new RerollDie(comparer, contained, condition, chooser, limit); + } } \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/DropFirstPool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/DropFirstPool.java deleted file mode 100644 index 959678b..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/DropFirstPool.java +++ /dev/null @@ -1,58 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; - -import bjc.dicelang.neodice.*; - -public class DropFirstPool implements DiePool { - private final int number; - private final DiePool pool; - - public DropFirstPool(DiePool pool, int number) { - this.pool = pool; - this.number = number; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - if (number >= rolls.length) { - return new int[0]; - } else { - int[] newRolls = new int[rolls.length - number]; - - for (int index = number - 1; index < rolls.length; index++) { - newRolls[index - number] = rolls[index]; - } - - return newRolls; - } - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - @Override - public String toString() { - return String.format("%sdF%d", pool, number); - } - - @Override - public int hashCode() { - return Objects.hash(number, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - DropFirstPool other = (DropFirstPool) obj; - - return number == other.number && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/DropLastPool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/DropLastPool.java deleted file mode 100644 index 9503e8f..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/DropLastPool.java +++ /dev/null @@ -1,58 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; - -import bjc.dicelang.neodice.*; - -public class DropLastPool implements DiePool { - private final int number; - private final DiePool pool; - - public DropLastPool(DiePool pool, int number) { - this.pool = pool; - this.number = number; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - if (number >= rolls.length) { - return new int[0]; - } else { - int[] newRolls = new int[rolls.length - number]; - - for (int index = 0; index < rolls.length - number; index++) { - newRolls[index] = rolls[index]; - } - - return newRolls; - } - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - @Override - public String toString() { - return String.format("%sdL%d", pool, number); - } - - @Override - public int hashCode() { - return Objects.hash(number, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - DropLastPool other = (DropLastPool) obj; - - return number == other.number && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/ExpandDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/ExpandDiePool.java new file mode 100644 index 0000000..7c58e72 --- /dev/null +++ b/dice/src/main/java/bjc/dicelang/neodice/diepool/ExpandDiePool.java @@ -0,0 +1,25 @@ +package bjc.dicelang.neodice.diepool; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import bjc.dicelang.neodice.*; + +public class ExpandDiePool implements IDiePool { + private final IDie contained; + + private final BiFunction, Random, Stream> expander; + + public ExpandDiePool(IDie contained, + BiFunction, Random, Stream> expander) { + this.contained = contained; + this.expander = expander; + } + + + @Override + public Stream roll(Random rng) { + return expander.apply(contained, rng); + } +} diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/FilteredDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/FilteredDiePool.java deleted file mode 100644 index 34d274f..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/FilteredDiePool.java +++ /dev/null @@ -1,47 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; -import java.util.function.*; - -import bjc.dicelang.neodice.*; - -public class FilteredDiePool implements DiePool { - private final DiePool pool; - private final IntPredicate filter; - - public FilteredDiePool(DiePool pool, IntPredicate filter) { - this.pool = pool; - this.filter = filter; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - return Arrays.stream(rolls).filter(filter).toArray(); - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - // No toString, since there isn't any sensible to output the filter - - @Override - public int hashCode() { - return Objects.hash(filter, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - FilteredDiePool other = (FilteredDiePool) obj; - - return Objects.equals(filter, other.filter) - && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/FixedDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/FixedDiePool.java index c60b88a..a536f62 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/FixedDiePool.java +++ b/dice/src/main/java/bjc/dicelang/neodice/diepool/FixedDiePool.java @@ -1,55 +1,46 @@ package bjc.dicelang.neodice.diepool; import java.util.*; +import java.util.stream.*; import bjc.dicelang.neodice.*; -public class FixedDiePool implements DiePool { - private final Die[] dice; +public class FixedDiePool implements IDiePool { + private final List> dice; - public FixedDiePool(Die[] dice) { + public FixedDiePool(List> dice) { this.dice = dice; } + + @SafeVarargs + public FixedDiePool(IDie...dice) { + this.dice = new ArrayList<>(dice.length); + for (IDie die : dice) { + this.dice.add(die); + } + } @Override - public int[] roll(Random rng) { - int[] results = new int[dice.length]; - - for (int index = 0; index < dice.length; index++) { - results[index] = dice[index].roll(rng); - } - - return results; + public Stream roll(Random rng) { + return dice.stream().map((die) -> die.roll(rng)); } @Override - public Die[] contained() { + public List> contained() { return dice; } @Override public String toString() { - StringBuilder builder = new StringBuilder(); - - for (int i = 0; i < dice.length; i++) { - Die die = dice[i]; - - builder.append(die); - - // Don't add an extra trailing comma - if (i < dice.length - 1) builder.append(", "); - } - - return builder.toString(); + return dice.stream() + .map(IDie::toString) + .collect(Collectors.joining(", ")); } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(dice); - return result; + return Objects.hash(dice); } @Override @@ -57,9 +48,9 @@ public class FixedDiePool implements DiePool { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; + + FixedDiePool other = (FixedDiePool) obj; - FixedDiePool other = (FixedDiePool) obj; - - return Arrays.equals(dice, other.dice); + return Objects.equals(dice, other.dice); } } \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepFirstDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepFirstDiePool.java deleted file mode 100644 index d31f104..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepFirstDiePool.java +++ /dev/null @@ -1,58 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; - -import bjc.dicelang.neodice.*; - -public class KeepFirstDiePool implements DiePool { - private final int number; - private final DiePool pool; - - public KeepFirstDiePool(DiePool pool, int number) { - this.pool = pool; - this.number = number; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - if (rolls.length >= number) { - return rolls; - } else { - int[] newRolls = new int[number]; - - for (int index = 0; index < number; index++) { - newRolls[index] = rolls[index]; - } - - return newRolls; - } - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - @Override - public String toString() { - return String.format("%skF%d", pool, number); - } - - @Override - public int hashCode() { - return Objects.hash(number, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - KeepFirstDiePool other = (KeepFirstDiePool) obj; - - return number == other.number && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepLastDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepLastDiePool.java deleted file mode 100644 index 1e2d1ae..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/KeepLastDiePool.java +++ /dev/null @@ -1,58 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; - -import bjc.dicelang.neodice.*; - -public class KeepLastDiePool implements DiePool { - private final int number; - private final DiePool pool; - - public KeepLastDiePool(DiePool pool, int number) { - this.pool = pool; - this.number = number; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - if (rolls.length >= number) { - return rolls; - } else { - int[] newRolls = new int[number]; - - for (int index = number; index > index; index--) { - newRolls[index] = rolls[rolls.length - index]; - } - - return newRolls; - } - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - @Override - public String toString() { - return String.format("%skL%d", pool, number); - } - - @Override - public int hashCode() { - return Objects.hash(number, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - KeepLastDiePool other = (KeepLastDiePool) obj; - - return number == other.number && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/SortedDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/SortedDiePool.java deleted file mode 100644 index 79599c1..0000000 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/SortedDiePool.java +++ /dev/null @@ -1,63 +0,0 @@ -package bjc.dicelang.neodice.diepool; - -import java.util.*; - -import bjc.dicelang.neodice.*; - -public class SortedDiePool implements DiePool { - private final boolean isDescending; - private final DiePool pool; - - public SortedDiePool(DiePool pool, boolean isDescending) { - this.pool = pool; - this.isDescending = isDescending; - } - - @Override - public int[] roll(Random rng) { - int[] rolls = pool.roll(rng); - - Arrays.sort(rolls); - - if (isDescending) { - int[] newRolls = new int[rolls.length]; - - int newIndex = newRolls.length; - for (int index = 0; index < rolls.length; index++) { - newRolls[newIndex--] = rolls[index]; - } - - return newRolls; - } else { - return rolls; - } - } - - @Override - public Die[] contained() { - return pool.contained(); - } - - @Override - public String toString() { - return String.format("%s (sorted %s)", pool, - isDescending ? " descending" : "ascending"); - } - - @Override - public int hashCode() { - return Objects.hash(isDescending, pool); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - SortedDiePool other = (SortedDiePool) obj; - - return isDescending == other.isDescending - && Objects.equals(pool, other.pool); - } -} \ No newline at end of file diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/TimesDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/TimesDiePool.java index 1b34247..56fe0e5 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/diepool/TimesDiePool.java +++ b/dice/src/main/java/bjc/dicelang/neodice/diepool/TimesDiePool.java @@ -1,35 +1,31 @@ package bjc.dicelang.neodice.diepool; import java.util.*; +import java.util.stream.*; import bjc.dicelang.neodice.*; -public class TimesDiePool implements DiePool { - private final Die contained; +public class TimesDiePool implements IDiePool { + private final IDie contained; private final int numDice; - public TimesDiePool(Die contained, int numDice) { + public TimesDiePool(IDie contained, int numDice) { this.contained = contained; this.numDice = numDice; } @Override - public int[] roll(Random rng) { - int[] results = new int[numDice]; - - for (int index = 0; index < numDice; index++) { - results[index] = contained.roll(rng); - } - - return results; + public Stream roll(Random rng) { + return Stream.generate(() -> contained.roll(rng)) + .limit(numDice); } @Override - public Die[] contained() { - Die[] results = new Die[numDice]; + public List> contained() { + List> results = new ArrayList<>(numDice); for (int index = 0; index < numDice; index++) { - results[index] = contained; + results.add(contained); } return results; @@ -51,7 +47,7 @@ public class TimesDiePool implements DiePool { if (obj == null) return false; if (getClass() != obj.getClass()) return false; - TimesDiePool other = (TimesDiePool) obj; + TimesDiePool other = (TimesDiePool) obj; return Objects.equals(contained, other.contained) && numDice == other.numDice; } diff --git a/dice/src/main/java/bjc/dicelang/neodice/diepool/TransformDiePool.java b/dice/src/main/java/bjc/dicelang/neodice/diepool/TransformDiePool.java new file mode 100644 index 0000000..f590e91 --- /dev/null +++ b/dice/src/main/java/bjc/dicelang/neodice/diepool/TransformDiePool.java @@ -0,0 +1,52 @@ +package bjc.dicelang.neodice.diepool; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import bjc.dicelang.neodice.*; + +public class TransformDiePool implements IDiePool { + private final IDiePool contained; + + private UnaryOperator> transform; + + public TransformDiePool(IDiePool contained, + UnaryOperator> transform) { + super(); + this.contained = contained; + this.transform = transform; + } + + @Override + public Stream roll(Random rng) { + return transform.apply(contained.roll(rng)); + } + + @Override + public List> contained() { + return contained.contained(); + } + + @Override + public int hashCode() { + return Objects.hash(contained, transform); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + + TransformDiePool other = (TransformDiePool) obj; + + return Objects.equals(contained, other.contained) + && Objects.equals(transform, other.transform); + } + + @Override + public String toString() { + return contained.toString() + "(transformed)"; + } +} -- cgit v1.2.3