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 The values that make up sentances of this grammar. */ public class WeightedGrammar { protected Map>> rules; protected Map> 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 cse) { WeightedRandom> 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> 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 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> debugVals(E rl) { FunctionalList> fl = new FunctionalList<>(); WeightedRandom> 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 FunctionalList genGeneric(E initRule, Function f, T spacer) { FunctionalList 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 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 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); } }