diff options
Diffstat (limited to 'BJC-Utils2/src/main/java')
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; + } +} |
