summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/gen/WeightedRandom.java
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-08 22:39:59 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-08 22:39:59 -0300
commitc82e3b3b2de0633317ec8fc85925e91422820597 (patch)
tree96567416ce23c5ce85601f9cedc3a94bb1c55cba /base/src/main/java/bjc/utils/gen/WeightedRandom.java
parentb3ac1c8690c3e14c879913e5dcc03a5f5e14876e (diff)
Start splitting into maven modules
Diffstat (limited to 'base/src/main/java/bjc/utils/gen/WeightedRandom.java')
-rw-r--r--base/src/main/java/bjc/utils/gen/WeightedRandom.java112
1 files changed, 112 insertions, 0 deletions
diff --git a/base/src/main/java/bjc/utils/gen/WeightedRandom.java b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
new file mode 100644
index 0000000..18225ef
--- /dev/null
+++ b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -0,0 +1,112 @@
+package bjc.utils.gen;
+
+import java.util.Random;
+
+import bjc.utils.data.IHolder;
+import bjc.utils.data.IPair;
+import bjc.utils.data.Identity;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+
+/**
+ * Represents a random number generator where certain results are weighted more
+ * heavily than others.
+ *
+ * @author ben
+ *
+ * @param <E>
+ * The type of values that are randomly selected.
+ */
+public class WeightedRandom<E> {
+ /*
+ * The list of probabilities for each result
+ */
+ private final IList<Integer> probabilities;
+
+ /*
+ * The list of possible results to pick from
+ */
+ private final IList<E> results;
+
+ /*
+ * The source for any needed random numbers
+ */
+ private final Random source;
+
+ private int totalChance;
+
+ /**
+ * Create a new weighted random generator with the specified source of
+ * randomness
+ *
+ * @param src
+ * The source of randomness to use.
+ */
+ public WeightedRandom(final Random src) {
+ probabilities = new FunctionalList<>();
+ results = new FunctionalList<>();
+
+ if (src == null) throw new NullPointerException("Source of randomness must not be null");
+
+ source = src;
+ }
+
+ /**
+ * Add a probability for a specific result to be given.
+ *
+ * @param chance
+ * The chance to get this result.
+ * @param result
+ * The result to get when the chance comes up.
+ */
+ public void addProbability(final int chance, final E result) {
+ probabilities.add(chance);
+ results.add(result);
+
+ totalChance += chance;
+ }
+
+ /**
+ * Generate a weighted random value.
+ *
+ * @return A random value selected in a weighted fashion.
+ */
+ public E generateValue() {
+ final IHolder<Integer> value = new Identity<>(source.nextInt(totalChance));
+ final IHolder<E> current = new Identity<>();
+ final IHolder<Boolean> picked = new Identity<>(true);
+
+ probabilities.forEachIndexed((index, probability) -> {
+ if (picked.unwrap(bool -> bool)) {
+ if (value.unwrap((number) -> number < probability)) {
+ current.transform((result) -> results.getByIndex(index));
+
+ picked.transform((bool) -> false);
+ } else {
+ value.transform((number) -> number - probability);
+ }
+ }
+ });
+
+ return current.unwrap((result) -> result);
+ }
+
+ /**
+ * Return a list of values that can be generated by this generator
+ *
+ * @return A list of all the values that can be generated
+ */
+ public IList<E> getResults() {
+ return results;
+ }
+
+ /**
+ * Return a list containing values that can be generated paired with the
+ * probability of those values being generated
+ *
+ * @return A list of pairs of values and value probabilities
+ */
+ public IList<IPair<Integer, E>> getValues() {
+ return probabilities.pairWith(results);
+ }
+}