summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/gen/WeightedRandom.java
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-10-16 06:11:39 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-10-16 06:11:39 -0300
commitd2be5b73d7a5653ad5c8273c17284346baa6f1c7 (patch)
tree9d3c6adb193f53588bd5d004fdf80c0381685351 /base/src/main/java/bjc/utils/gen/WeightedRandom.java
parent0308029629a12711b849ea7765639b9b1f9e03d2 (diff)
parentd1d01769e7c55f7f62dc01cadf420d5f63424584 (diff)
Merge branch 'master' of github.com:bculkin2442/bjc-utils2
Diffstat (limited to 'base/src/main/java/bjc/utils/gen/WeightedRandom.java')
-rw-r--r--base/src/main/java/bjc/utils/gen/WeightedRandom.java113
1 files changed, 89 insertions, 24 deletions
diff --git a/base/src/main/java/bjc/utils/gen/WeightedRandom.java b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
index 405d685..71de333 100644
--- a/base/src/main/java/bjc/utils/gen/WeightedRandom.java
+++ b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -2,9 +2,7 @@ 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.data.Pair;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
@@ -16,7 +14,7 @@ import bjc.utils.funcdata.IList;
* @author ben
*
* @param <E>
- * The type of values that are randomly selected.
+ * The type of values that are randomly selected.
*/
public class WeightedRandom<E> {
private final IList<IPair<Integer, E>> values;
@@ -29,17 +27,18 @@ public class WeightedRandom<E> {
private final static Random BASE = new Random();
private boolean exhaust;
+
/**
* Create a new weighted random generator with the specified source of
* randomness.
*
* @param src
- * The source of randomness to use.
+ * The source of randomness to use.
*/
public WeightedRandom(Random src) {
values = new FunctionalList<>();
- if(src == null) throw new NullPointerException("Source of randomness must not be null");
+ if (src == null) throw new NullPointerException("Source of randomness must not be null");
source = src;
}
@@ -63,10 +62,10 @@ public class WeightedRandom<E> {
* Add a probability for a specific result to be given.
*
* @param chance
- * The chance to get this result.
+ * The chance to get this result.
*
* @param result
- * The result to get when the chance comes up.
+ * The result to get when the chance comes up.
*/
public void addProbability(final int chance, final E result) {
values.add(new Pair<>(chance, result));
@@ -83,15 +82,20 @@ public class WeightedRandom<E> {
return generateValue(source);
}
+ /**
+ * Generate a random value, using the specified Random.
+ *
+ * @param rn
+ * The Random instance to use.
+ * @return A random value.
+ */
public E generateValue(Random rn) {
int target = rn.nextInt(totalChance);
- int i = 0;
-
- for(IPair<Integer, E> val : values) {
+ for (IPair<Integer, E> val : values) {
int prob = val.getLeft();
- if(target < prob) {
- if(exhaust) {
+ if (target < prob) {
+ if (exhaust) {
totalChance -= val.getLeft();
values.removeMatching(val);
}
@@ -100,11 +104,11 @@ public class WeightedRandom<E> {
}
target -= prob;
- i += 1;
}
return null;
}
+
/**
* Return a list of values that can be generated by this generator
*
@@ -124,17 +128,41 @@ public class WeightedRandom<E> {
return values;
}
+ /**
+ * Get a descending value.
+ *
+ * Descending values are quite simple. You have a 1 in factor chance to
+ * advance to the next value, otherwise, the current value is the one
+ * returned.
+ *
+ * @param factor
+ * The descent factor to use.
+ * @return A random value.
+ */
public E getDescent(int factor) {
return getDescent(factor, source);
}
+ /**
+ * Get a descending value.
+ *
+ * Descending values are quite simple. You have a 1 in factor chance to
+ * advance to the next value, otherwise, the current value is the one
+ * returned.
+ *
+ * @param factor
+ * The descent factor to use.
+ * @param rn
+ * The Random instance to use.
+ * @return A random value.
+ */
public E getDescent(int factor, Random rn) {
- if(values.getSize() == 0) return null;
+ if (values.getSize() == 0) return null;
- for(IPair<Integer, E> val : values) {
- if(rn.nextInt(factor) == 0) continue;
+ for (IPair<Integer, E> val : values) {
+ if (rn.nextInt(factor) == 0) continue;
- if(exhaust) {
+ if (exhaust) {
totalChance -= val.getLeft();
values.removeMatching(val);
@@ -144,29 +172,61 @@ public class WeightedRandom<E> {
}
IPair<Integer, E> val = values.getByIndex(values.getSize() - 1);
- if(exhaust) values.removeMatching(val);
+ if (exhaust) values.removeMatching(val);
return val.getRight();
}
+ /**
+ * Get a value, treating this as a set of binomial trials.
+ *
+ * Essentially, the system rolls a bound-sided dice trials times, and
+ * marks a success for every roll less than or equal to target.
+ *
+ * @param target
+ * The number to roll at or under.
+ * @param bound
+ * The maximum roll value.
+ * @param trials
+ * The number of times to roll.
+ * @return The value at the index corresponding to the number of
+ * successes.
+ */
public E getBinomial(int target, int bound, int trials) {
return getBinomial(target, bound, trials, source);
}
+ /**
+ * Get a value, treating this as a set of binomial trials.
+ *
+ * Essentially, the system rolls a bound-sided dice trials times, and
+ * marks a success for every roll less than or equal to target.
+ *
+ * @param target
+ * The number to roll at or under.
+ * @param bound
+ * The maximum roll value.
+ * @param trials
+ * The number of times to roll.
+ * @param rn
+ * The Random instance to use.
+ * @return The value at the index corresponding to the number of
+ * successes.
+ */
public E getBinomial(int target, int bound, int trials, Random rn) {
- if(values.getSize() == 0) return null;
+ if (values.getSize() == 0) return null;
int numSuc = 0;
- for(int i = 0; i < trials; i++) {
- /*
+ for (int i = 0; i < trials; i++) {
+ /*
* Adjust for zero, because it's easy to think of this
* as rolling a bound-sided dice and marking a success
* for every roll less than or equal to target.
*/
int num = rn.nextInt(bound) + 1;
- if(num <= target) {
+ if (num <= target) {
//System.err.printf("\t\tTRACE: mark binomial success (%d <= 1d%d, %d)\n", target, bound, num);
numSuc += 1;
}
@@ -174,7 +234,7 @@ public class WeightedRandom<E> {
//System.err.printf("\tTRACE: got %d success for binomial trials (%d <= 1d%d, %d times)\n", numSuc, target, bound, trials);
IPair<Integer, E> val = values.getByIndex(Math.min(numSuc, values.getSize() - 1));
- if(exhaust) {
+ if (exhaust) {
totalChance -= val.getLeft();
values.removeMatching(val);
@@ -183,9 +243,14 @@ public class WeightedRandom<E> {
return val.getRight();
}
+ /**
+ * Return a new WeightedRandom that is exhaustible (only returns one value once).
+ *
+ * @return A new WeightedRandom that is exhaustible.
+ */
public WeightedRandom<E> exhaustible() {
IList<IPair<Integer, E>> lst = new FunctionalList<>();
- for(IPair<Integer, E> val : values) {
+ for (IPair<Integer, E> val : values) {
lst.add(val);
}