sclass ProbabilisticMachine2 { transient TreeSetWithDuplicates states = new(byProbability()); transient TreeSetWithDuplicates steppableStates = new(byProbability()); transient TreeSetWithDuplicates droppedStates = new(byProbability()); transient int stateCount; bool verbose; double cutoffPercentage = 50; new L> onStateAdded; Comparator byProbability() { ret (a, b) -> cmp(b.probability, a.probability); } abstract sclass State { ProbabilisticMachine2 probabilisticMachine; int stateNumber; State previousState; double probability = 100; //abstract State emptyClone(); // override me unless it's a terminal state void step {} toString { ret toStringWithFields(this, "stateNumber", "probability"); } State prepareDescendant(State s) { copyFields(this, s, 'probabilisticMachine, 'probability); s.previousState = this; ret s; } ProbabilisticMachine2 probabilisticMachine() { ret probabilisticMachine; } } // This only works when A = ProbabilisticMachine2.State A addState(Runnable r) { if (r != null) addState((A) new State { void step { r.run(); } }); } A addState(A s) { if (verbose) print("Adding state to machine " + this + ": " + s); s.probabilisticMachine = this; if (s.stateNumber == 0) s.stateNumber = ++stateCount; if (s.probability < cutoffPercentage) ret with droppedStates.add(s); addToCollections(s, states, steppableStates); pcallFAll(onStateAdded, s); if (verbose) printStats(); ret s; } // returns false when done stepping bool stepFirstUnstepped() { A s = popFirst(steppableStates), ret false if null; ret true with s.step(); } void reset { clearAll(states, steppableStates, droppedStates); stateCount = 0; } void think { while ping (stepFirstUnstepped()) {} } void printStats() { print("States: " + stats(states) + ", steppable: " + stats(steppableStates) + ", dropped: " + stats(droppedStates)); } S stats(TreeSetWithDuplicates ts) { ret l(ts) + (empty(ts) ? "" : " (best: " + iround(first(ts).probability) + ")"); } }