//!include once #1022817 // Attractor Classes abstract sclass AttractorBot extends AbstractSayAndInputBot implements Runnable { transient LS inputQueue = synchroLinkedList(); transient Set activeThreads = synchroSet(); // functions taking a string and returning a string or collection of strings transient L preprocessors = synchroList(); transient F1 isYes = f isYes_1; new LinkedHashSet facts; new LinkedHashSet assumptions; transient L standardAttractors = synchroList(); // permanent transient L standardLowPrioAttractors = synchroList(); // permanent transient L activeAttractors = synchroList(); // temporary transient L lowPrioAttractors = synchroList(); // temporary S line; *() { input = f getInput; standardPreprocessors(); } 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); line = s; if (empty(activeThreads)) attractorBattle(); } void attractorBattle { if (empty(inputQueue)) ret; S input = getInput(); print("Input: " + input); // high prio active, then standing attractors, then low prio active L attractors = getAndClearList(activeAttractors); addAll(attractors, standardAttractors); addAll(attractors, getAndClearList(lowPrioAttractors)); addAll(attractors, standardLowPrioAttractors); if (empty(attractors)) ret with print("No attractors, ignoring input"); new L matchingAttractors; for (Attractor a : attractors) pcall { if (a.matches_public(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); runAttractor(winner); } // attractors can use AttractorBot.this.say() [old] or emitAnswer() [preferred] void runAttractor(Attractor a) { say(getVars(getEmittedAnswers(a))); } void addAttractor(Attractor a) { addAttractors(a); } void tempAttractor(Attractor a) { addAttractors(a); } void addAttractors(Attractor... attractors) { addAll(activeAttractors, attractors); } void addLowPrioAttractor(Attractor a) { add(lowPrioAttractors, a); } void lowPrioAttractor(Attractor a) { addLowPrioAttractor(a); } void defaultAttractor(Attractor a) { addLowPrioAttractor(a); } void addStandardAttractor(Attractor a) { add(standardAttractors, a); } void standardAttractor(Attractor a) { addStandardAttractor(a); } void standardAttractors(Attractor... attractors) { addAll(standardAttractors, attractors); } void standardLowPrioAttractor(Attractor a) { add(standardLowPrioAttractors, a); } void addPreprocessors(O... l) { addAll(preprocessors, l); } void standardPreprocessors() { addPreprocessors(f ai_dropLeadingAndTrailingAppellations_sortedByLength); } // override me for start-up behavior run {} }