diff options
| author | Ben Culkin <scorpress@gmail.com> | 2020-11-21 18:03:31 -0500 |
|---|---|---|
| committer | Ben Culkin <scorpress@gmail.com> | 2020-11-21 18:03:31 -0500 |
| commit | d92c0ed766188f614ed4077395881549132305d0 (patch) | |
| tree | 85466b1a7534c6faade13ac4cce427e3aefd554f /dice/src/main/java | |
| parent | 84f0803068ba50bcba67de42634a4bf3d0e9e170 (diff) | |
Some more work on the new dice implementation
Diffstat (limited to 'dice/src/main/java')
| -rw-r--r-- | dice/src/main/java/bjc/dicelang/neodice/Die.java | 75 | ||||
| -rw-r--r-- | dice/src/main/java/bjc/dicelang/neodice/DiePool.java | 321 |
2 files changed, 396 insertions, 0 deletions
diff --git a/dice/src/main/java/bjc/dicelang/neodice/Die.java b/dice/src/main/java/bjc/dicelang/neodice/Die.java index a331e4e..a986ca2 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/Die.java +++ b/dice/src/main/java/bjc/dicelang/neodice/Die.java @@ -1,8 +1,11 @@ package bjc.dicelang.neodice; import java.util.*; +import java.util.function.*; import java.util.stream.*; +import bjc.esodata.*; + /** * Represents a single polyhedral die. * @author Ben Culkin @@ -31,6 +34,30 @@ public interface Die { }; /** + * 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. @@ -93,4 +120,52 @@ final class TimesDiePool implements DiePool { return Objects.equals(contained, other.contained) && numDice == other.numDice; } +} + +final class RerollDie implements Die { + private final Die contained; + + private final IntPredicate condition; + private final Function<MinMaxList<Integer>, Integer> chooser; + + private int limit = Integer.MAX_VALUE; + + + public RerollDie(Die contained, IntPredicate condition, + Function<MinMaxList<Integer>, Integer> chooser) { + this.contained = contained; + + this.condition = condition; + this.chooser = chooser; + } + + public RerollDie(Die contained, IntPredicate condition, + Function<MinMaxList<Integer>, Integer> chooser, int limit) { + this.contained = contained; + + this.condition = condition; + this.chooser = chooser; + + this.limit = limit; + } + + @Override + public int roll(Random rng) { + int roll = contained.roll(rng); + + MinMaxList<Integer> newRolls = new MinMaxList<Integer>( + Comparator.naturalOrder(), roll); + + int rerollCount = 0; + while (condition.test(roll) && rerollCount < limit) { + roll = contained.roll(rng); + newRolls.add(roll); + + rerollCount += 1; + } + + return chooser.apply(newRolls); + } + + // No toString, because IntPredicate can't be converted to a string }
\ 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 index b7ee834..70dfa50 100644 --- a/dice/src/main/java/bjc/dicelang/neodice/DiePool.java +++ b/dice/src/main/java/bjc/dicelang/neodice/DiePool.java @@ -46,6 +46,10 @@ public interface DiePool { 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. @@ -75,6 +79,101 @@ public interface DiePool { } /** + * 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. @@ -114,6 +213,11 @@ final class SortedDiePool implements DiePool { return rolls; } } + + @Override + public Die[] contained() { + return pool.contained(); + } @Override public String toString() { @@ -155,6 +259,11 @@ final class FilteredDiePool implements DiePool { 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 @@ -173,4 +282,216 @@ final class FilteredDiePool implements DiePool { return Objects.equals(filter, other.filter) && Objects.equals(pool, other.pool); } +} + +final 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); + } +} + +final 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); + } +} + +final 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); + } +} + +final 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 |
