summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java59
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java177
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java68
3 files changed, 304 insertions, 0 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java
new file mode 100644
index 0000000..0245b17
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java
@@ -0,0 +1,59 @@
+package bjc.utils.gen;
+
+import java.util.HashMap;
+
+import bjc.utils.funcdata.FunctionalList;
+
+/**
+ * A weighted grammar where all the rules have a equal chance of occuring.
+ * @author ben
+ *
+ * @param <E> The type of grammar elements to use.
+ */
+public class RandomGrammar<E> extends WeightedGrammar<E> {
+
+ /**
+ * Create a new random grammar.
+ */
+ public RandomGrammar() {
+ rules = new HashMap<>();
+ }
+
+ /**
+ * Add cases to a specified rule.
+ * @param rule The name of the rule to add cases to.
+ * @param cases The cases to add for this rule.
+ */
+ @SafeVarargs
+ public final void addCases(E rule, FunctionalList<E>... cases) {
+ for (FunctionalList<E> cse : cases) {
+ super.addCase(rule, 1, cse);
+ }
+ }
+
+ /**
+ * Create a rule with the specified name and cases.
+ * @param rule The name of the rule to add.
+ * @param cases The cases to add for this rule.
+ */
+ @SafeVarargs
+ public final void makeRule(E rule, FunctionalList<E>... cases) {
+ super.addRule(rule);
+
+ for (FunctionalList<E> cse : cases) {
+ super.addCase(rule, 1, cse);
+ }
+ }
+
+ /**
+ * Create a rule with the specified name and cases.
+ * @param rule The name of the rule to add.
+ * @param cases The cases to add for this rule.
+ */
+ public void makeRule(E rule,
+ FunctionalList<FunctionalList<E>> cases) {
+ super.addRule(rule);
+
+ cases.forEach(cse -> super.addCase(rule, 1, cse));
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
new file mode 100644
index 0000000..8733723
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
@@ -0,0 +1,177 @@
+package bjc.utils.gen;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.function.Function;
+
+import bjc.utils.funcdata.FunctionalList;
+
+/**
+ * A random grammar, where certain rules will come up morre often than
+ * others.
+ *
+ * @author ben
+ *
+ * @param <E> The values that make up sentances of this grammar.
+ */
+public class WeightedGrammar<E> {
+ protected Map<E, WeightedRandom<FunctionalList<E>>> rules;
+ protected Map<E, WeightedGrammar<E>> subgrammars;
+ private Random sr;
+
+ /**
+ * Create a new weighted grammar that uses the specified source of randomness.
+ */
+ public WeightedGrammar(Random src) {
+ this();
+ sr = src;
+ }
+
+ /**
+ * Create a new weighted grammar.
+ */
+ public WeightedGrammar() {
+ rules = new HashMap<>();
+ }
+
+ /**
+ * Add a case to an already existing rule.
+ *
+ * @param rule The rule to add a case to.
+ * @param prob The probability for this rule to be chosen.
+ * @param cse The case being added.
+ */
+ public void addCase(E rule, int prob, FunctionalList<E> cse) {
+ WeightedRandom<FunctionalList<E>> rn = rules.get(rule);
+
+ rn.addProb(prob, cse);
+ }
+
+ /**
+ * Add a new rule with no cases.
+ * @param name The name of the rule to add.
+ * @return Whether or not the rule was succesfully added.
+ */
+ public boolean addRule(E name) {
+ if(sr == null) {
+ sr = new Random();
+ }
+ return addRule(name, new WeightedRandom<>(sr));
+ }
+
+ /**
+ * Add a new rule with a set of cases.
+ * @param name The name of the rule to add.
+ * @param rnd The set of cases for the rule.
+ * @return Whether or not the rule was succesfully added.
+ */
+ public boolean addRule(E name, WeightedRandom<FunctionalList<E>> rnd) {
+ if (rules.containsKey(name)) {
+ return false;
+ } else {
+ rules.put(name, rnd);
+ return true;
+ }
+ }
+
+ /**
+ * Add a subgrammar.
+ * @param name The name of the subgrammar.
+ * @param subG The subgrammar to add.
+ * @return Whether or not the subgrammar was succesfully added.
+ */
+ public boolean addSubGrammar(E name, WeightedGrammar<E> subG) {
+ if (subgrammars.containsKey(name)) {
+ return false;
+ } else {
+ subgrammars.put(name, subG);
+ return true;
+ }
+ }
+
+ /**
+ * Generate a set of debug sentences for the specified rule.
+ * Only generates sentances one layer deep.
+ * @param rl The rule to test.
+ * @return A set of sentances generated by the specified rule.
+ */
+ public FunctionalList<FunctionalList<E>> debugVals(E rl) {
+ FunctionalList<FunctionalList<E>> fl = new FunctionalList<>();
+
+ WeightedRandom<FunctionalList<E>> random = rules.get(rl);
+
+ for (int i = 0; i < 10; i++) {
+ fl.add(random.genVal());
+ }
+
+ return fl;
+ }
+
+ /**
+ * Generate a generic sentance from a initial rule.
+ *
+ * @param initRule The initial rule to start with.
+ * @param f The function to transform grammar output into something.
+ * @param spacer The spacer element to add in between output tokens.
+ * @return A randomly generated sentance from the specified initial rule.
+ */
+ public <T> FunctionalList<T> genGeneric(E initRule, Function<E, T> f,
+ T spacer) {
+ FunctionalList<T> r = new FunctionalList<>();
+
+ if (subgrammars.containsKey(initRule)) {
+ subgrammars.get(initRule).genGeneric(initRule, f, spacer)
+ .forEach(rp -> {
+ r.add(rp);
+ r.add(spacer);
+ });
+ } else if (rules.containsKey(initRule)) {
+ rules.get(initRule).genVal().forEach(
+ rp -> genGeneric(rp, f, spacer).forEach(rp2 -> {
+ r.add(rp2);
+ r.add(spacer);
+ }));
+ } else {
+ r.add(f.apply(initRule));
+ r.add(spacer);
+ }
+
+ return r;
+ }
+
+ /**
+ * Generate a random list of grammar elements from a given initial rule.
+ * @param initRule The initial rule to start with.
+ * @param spacer The item to use to space the list.
+ * @return A list of random grammar elements generated by the specified rule.
+ */
+ public FunctionalList<E> genList(E initRule, E spacer) {
+ return genGeneric(initRule, s -> s, spacer);
+ }
+
+ /**
+ * Get the subgrammar with the specified name.
+ * @param name The name of the subgrammar to get.
+ * @return The subgrammar with the specified name.
+ */
+ public WeightedGrammar<E> getSubGrammar(E name) {
+ return subgrammars.get(name);
+ }
+
+ /**
+ * Remove a rule with the specified name.
+ * @param name The name of the rule to remove.
+ */
+ public void removeRule(E name) {
+ rules.remove(name);
+ }
+
+ /**
+ * Remove a subgrammar with the specified name.
+ * @param name The name of the subgrammar to remove.
+ */
+ public void removeSubgrammar(E name) {
+ subgrammars.remove(name);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
new file mode 100644
index 0000000..ecd4e36
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -0,0 +1,68 @@
+package bjc.utils.gen;
+
+import java.util.Random;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.data.GenHolder;
+
+/**
+ * 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> {
+ private Random src;
+
+ private FunctionalList<Integer> probs;
+ private FunctionalList<E> results;
+
+ private int totalChance;
+
+ /**
+ * Create a new weighted random generator with the specified source of randomness
+ * @param sr The source of randomness to use.
+ */
+ public WeightedRandom(Random sr) {
+ probs = new FunctionalList<>();
+ results = new FunctionalList<>();
+
+ src = sr;
+ }
+
+ /**
+ * Add a probability for a specific result to be given.
+ * @param chance The chance to get this result.
+ * @param res The result to get when the chance comes up.
+ */
+ public void addProb(int chance, E res) {
+ probs.add(chance);
+ results.add(res);
+
+ totalChance += chance;
+ }
+
+ /**
+ * Generate a weighted random value.
+ * @return A random value selected in a weighted fashion.
+ */
+ public E genVal() {
+ GenHolder<Integer> v = new GenHolder<>(src.nextInt(totalChance));
+ GenHolder<E> res = new GenHolder<E>();
+ GenHolder<Boolean> bl = new GenHolder<>(true);
+
+ probs.forEachIndexed((i, p) -> {
+ if (bl.held) {
+ if (v.held < p) {
+ res.held = results.getByIndex(i);
+ bl.held = false;
+ } else {
+ v.held -= p;
+ }
+ }
+ });
+
+ return res.held;
+ }
+}