summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-06-07 13:04:43 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-06-07 13:04:43 -0300
commitf8f9166be2c5d02edc17b3fb1d4ea6baa9f926da (patch)
tree7f6897a4bf112e57bbfb8b435b0a72dfede09c94 /base
parentca2a5c012267c500d9f0fd883c98904d125a64f0 (diff)
Update
Diffstat (limited to 'base')
-rw-r--r--base/src/main/java/bjc/utils/funcdata/FunctionalList.java27
-rw-r--r--base/src/main/java/bjc/utils/funcdata/IList.java10
-rw-r--r--base/src/main/java/bjc/utils/gen/WeightedRandom.java82
3 files changed, 102 insertions, 17 deletions
diff --git a/base/src/main/java/bjc/utils/funcdata/FunctionalList.java b/base/src/main/java/bjc/utils/funcdata/FunctionalList.java
index c730424..6953bd0 100644
--- a/base/src/main/java/bjc/utils/funcdata/FunctionalList.java
+++ b/base/src/main/java/bjc/utils/funcdata/FunctionalList.java
@@ -169,6 +169,33 @@ public class FunctionalList<E> implements Cloneable, IList<E> {
}
@Override
+ public E last() {
+ if(wrapped.size() < 1) throw new NoSuchElementException("Attempted to get last element of empty list");
+
+ return wrapped.get(wrapped.size() - 1);
+ }
+
+ @Override
+ public E popFirst() {
+ if(wrapped.size() < 1) throw new NoSuchElementException("Attempted to pop first element of empty list");
+
+ E head = first();
+ wrapped.remove(0);
+
+ return head;
+ }
+
+ @Override
+ public E popLast() {
+ if(wrapped.size() < 1) throw new NoSuchElementException("Attempted to pop last element of empty list");
+
+ E tail = last();
+ wrapped.remove(wrapped.size() - 1);
+
+ return tail;
+ }
+
+ @Override
public <T> IList<T> flatMap(final Function<E, IList<T>> expander) {
if(expander == null) throw new NullPointerException("Expander must not be null");
diff --git a/base/src/main/java/bjc/utils/funcdata/IList.java b/base/src/main/java/bjc/utils/funcdata/IList.java
index cfda68d..12eaf2f 100644
--- a/base/src/main/java/bjc/utils/funcdata/IList.java
+++ b/base/src/main/java/bjc/utils/funcdata/IList.java
@@ -160,6 +160,16 @@ public interface IList<ContainedType> extends Iterable<ContainedType> {
ContainedType first();
/**
+ * Get the last element in the list.
+ *
+ * @return The last element in this list.
+ */
+ ContainedType last();
+
+ ContainedType popFirst();
+ ContainedType popLast();
+
+ /**
* Apply a function to each member of the list, then flatten the
* results.
*
diff --git a/base/src/main/java/bjc/utils/gen/WeightedRandom.java b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
index c9bdad8..405d685 100644
--- a/base/src/main/java/bjc/utils/gen/WeightedRandom.java
+++ b/base/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -5,6 +5,7 @@ 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;
@@ -18,10 +19,7 @@ import bjc.utils.funcdata.IList;
* 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;
+ private final IList<IPair<Integer, E>> values;
/* The source for any needed random numbers */
private Random source;
@@ -30,6 +28,7 @@ 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.
@@ -38,8 +37,7 @@ public class WeightedRandom<E> {
* The source of randomness to use.
*/
public WeightedRandom(Random src) {
- probabilities = new FunctionalList<>();
- results = new FunctionalList<>();
+ values = new FunctionalList<>();
if(src == null) throw new NullPointerException("Source of randomness must not be null");
@@ -52,6 +50,15 @@ public class WeightedRandom<E> {
public WeightedRandom() {
this(BASE);
}
+
+ private WeightedRandom(Random src, IList<IPair<Integer, E>> vals, int chance) {
+ source = src;
+
+ values = vals;
+
+ totalChance = chance;
+ }
+
/**
* Add a probability for a specific result to be given.
*
@@ -62,8 +69,7 @@ public class WeightedRandom<E> {
* The result to get when the chance comes up.
*/
public void addProbability(final int chance, final E result) {
- probabilities.add(chance);
- results.add(result);
+ values.add(new Pair<>(chance, result));
totalChance += chance;
}
@@ -81,14 +87,23 @@ public class WeightedRandom<E> {
int target = rn.nextInt(totalChance);
int i = 0;
- for(int prob : probabilities) {
- if(target < prob) return results.getByIndex(i);
+ for(IPair<Integer, E> val : values) {
+ int prob = val.getLeft();
+
+ if(target < prob) {
+ if(exhaust) {
+ totalChance -= val.getLeft();
+ values.removeMatching(val);
+ }
+
+ return val.getRight();
+ }
target -= prob;
i += 1;
}
- throw new NullPointerException("Fell off the end of the results list");
+ return null;
}
/**
* Return a list of values that can be generated by this generator
@@ -96,7 +111,7 @@ public class WeightedRandom<E> {
* @return A list of all the values that can be generated
*/
public IList<E> getResults() {
- return results;
+ return values.map(IPair::getRight);
}
/**
@@ -106,7 +121,7 @@ public class WeightedRandom<E> {
* @return A list of pairs of values and value probabilities
*/
public IList<IPair<Integer, E>> getValues() {
- return probabilities.pairWith(results);
+ return values;
}
public E getDescent(int factor) {
@@ -114,13 +129,24 @@ public class WeightedRandom<E> {
}
public E getDescent(int factor, Random rn) {
- for(E res : results) {
+ if(values.getSize() == 0) return null;
+
+ for(IPair<Integer, E> val : values) {
if(rn.nextInt(factor) == 0) continue;
- return res;
+ if(exhaust) {
+ totalChance -= val.getLeft();
+
+ values.removeMatching(val);
+ }
+
+ return val.getRight();
}
- return results.getByIndex(results.getSize() - 1);
+ IPair<Integer, E> val = values.getByIndex(values.getSize() - 1);
+ if(exhaust) values.removeMatching(val);
+
+ return val.getRight();
}
public E getBinomial(int target, int bound, int trials) {
@@ -128,6 +154,8 @@ public class WeightedRandom<E> {
}
public E getBinomial(int target, int bound, int trials, Random rn) {
+ if(values.getSize() == 0) return null;
+
int numSuc = 0;
for(int i = 0; i < trials; i++) {
@@ -145,6 +173,26 @@ public class WeightedRandom<E> {
}
//System.err.printf("\tTRACE: got %d success for binomial trials (%d <= 1d%d, %d times)\n", numSuc, target, bound, trials);
- return results.getByIndex(Math.min(numSuc, results.getSize() - 1));
+ IPair<Integer, E> val = values.getByIndex(Math.min(numSuc, values.getSize() - 1));
+ if(exhaust) {
+ totalChance -= val.getLeft();
+
+ values.removeMatching(val);
+ }
+
+ return val.getRight();
+ }
+
+ public WeightedRandom<E> exhaustible() {
+ IList<IPair<Integer, E>> lst = new FunctionalList<>();
+ for(IPair<Integer, E> val : values) {
+ lst.add(val);
+ }
+
+ WeightedRandom<E> res = new WeightedRandom<>(source, lst, totalChance);
+
+ res.exhaust = true;
+
+ return res;
}
}