abstract sclass AbstractSayAndInputBot2 extends AbstractSayAndInputBot implements Runnable { LS inputQueue = synchroLinkedList(); Set activeThreads = synchroSet(); // functions taking a string and returning a string or collection of strings L preprocessors = synchroList(); F1 isYes = f isYes_1; new LinkedHashSet facts; new LinkedHashSet assumptions; L standardAttractors = synchroList(); L activeAttractors = synchroList(); abstract class Attractor implements Runnable { abstract bool matches(S s); } *() { input = f getInput; } void remember(S fact) { if (facts.add(fact)) print("[Bot learned:] " + fact); } void assume(S fact) { if (assumptions.add(fact)) print("[Bot assumes:] " + fact); } S getInput() { while (empty(inputQueue)) sleep(10); ret trim(popFirst(inputQueue)); } bool yes() { ret callF(isYes, input()); } // call this instead of run() so thread is marked void run_public() { temp tempAddToCollection(activeThreads, currentThread()); run(); } void addInput(S s) { inputQueue.add(s); if (empty(activeThreads)) attractorBattle(); } void attractorBattle { if (empty(inputQueue)) ret; S input = getInput(); print("Input: " + input); L attractors = getAndClearList(activeAttractors); addAll(attractors, standardAttractors); if (empty(attractors)) ret with print("No attractors, ignoring input"); new L matchingAttractors; for (Attractor a : attractors) pcall { if (a.matches(input)) matchingAttractors.add(a); } if (empty(matchingAttractors)) ret with print("No matching attractors, ignoring input"); print("Got " + n2(matchingAttractors, "matching attractor") + ": " + matchingAttractors); Attractor winner = first(matchingAttractors); if (l(matchingAttractors) > 1) print("Choosing first attractor"); winner.run(); } void addAttractors(Attractor... attractors) { addAll(activeAttractors, attractors); } void standardAttractors(Attractor... attractors) { addAll(standardAttractors, attractors); } }