summaryrefslogtreecommitdiff
path: root/dice/src/main/java/bjc/dicelang/neodice/DiePool.java
diff options
context:
space:
mode:
Diffstat (limited to 'dice/src/main/java/bjc/dicelang/neodice/DiePool.java')
-rw-r--r--dice/src/main/java/bjc/dicelang/neodice/DiePool.java176
1 files changed, 176 insertions, 0 deletions
diff --git a/dice/src/main/java/bjc/dicelang/neodice/DiePool.java b/dice/src/main/java/bjc/dicelang/neodice/DiePool.java
new file mode 100644
index 0000000..b7ee834
--- /dev/null
+++ b/dice/src/main/java/bjc/dicelang/neodice/DiePool.java
@@ -0,0 +1,176 @@
+package bjc.dicelang.neodice;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * 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");
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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<Integer> iterator(Random rng) {
+ return Arrays.stream(this.roll(rng)).iterator();
+ }
+}
+
+final 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 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);
+ }
+}
+
+final 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();
+ }
+
+ // 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