package bjc.utils.gen; import java.util.Random; import bjc.utils.funcdata.FunctionalList; import bjc.utils.data.GenHolder; import bjc.utils.data.IHolder; import bjc.utils.data.Pair; /** * Represents a random number generator where certain results are weighted * more heavily than others. * * @author ben * * @param * The type of values that are randomly selected. */ public class WeightedRandom { /** * The list of probabilities for each result */ private FunctionalList probs; /** * The list of possible results to pick from */ private FunctionalList results; /** * The source for any needed random numbers */ private Random src; 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 v = new GenHolder<>(src.nextInt(totalChance)); IHolder res = new GenHolder(); GenHolder bl = new GenHolder<>(true); probs.forEachIndexed((i, p) -> { if (bl.unwrap(vl -> vl)) { if (v.unwrap((vl) -> vl < p)) { res.transform((vl) -> results.getByIndex(i)); bl.transform((vl) -> false); } else { v.transform((vl) -> vl - p); } } }); return res.unwrap((vl) -> vl); } /** * Return a list of values that can be generated by this generator * * @return A list of all the values that can be generated */ public FunctionalList getResults() { return results; } /** * Return a list containing values that can be generated paired with * the probability of those values being generated * * @return A list of pairs of values and value probabilities */ public FunctionalList> getValues() { return probs.pairWith(results); } }