// adapters are immutable! (plus returns a modified clone)
abstract sclass Adapter {
abstract bool canMatch(S in, S out);
Adapter plus(S in, S out) { ret this; }
S get(S in) { ret in; }
double size() { ret 0; }
}
// node in flight (+ optional adapter)
sclass InFlight {
OccTree2 node;
Adapter adapter;
*(OccTree2 *node) {}
*(OccTree2 *node, Adapter *adapter) {}
E adapted() {
// TODO: security when rewriting states
ret adapter == null ? node.e : new E(adapter.get(node.e.text()), node.e.type());
}
}
sclass LooseBot {
sbool debug, repeat = true;
OccTree2 tree;
new L<InFlight> nodes;
new L<L> rewindStack;
O newAdapter;
O grabber; // func(S -> E)
// WordAdapter now default
*(OccTree2 tree) { this(tree, func { new WordAdapter }); }
// main constructor
*(OccTree2 *tree, O *newAdapter) {
expandEllipsis(tree);
}
*(S theme) { this(makeOccTree(theme)); }
*(S theme, O newAdapter) { this(makeOccTree(theme), newAdapter); }
Adapter makeAdapter() {
ret newAdapter == null ? null : (Adapter) call(newAdapter);
}
void take(E in) {
remember();
// try starting over from beginning of tree too
if (repeat) setAdd(nodes, new InFlight(tree, makeAdapter()));
new L<InFlight> l;
// try grabber
if (grabber != null && in.q()) try {
E grabbed = cast callFunction(grabber, in.text());
if (grabbed != null) {
if (debug)
print("Grabber worked! " + in.text() + " => " + grabbed);
// make a mini tree with Q + A so it is matched in
// next call to getSingleOutput()
OccTree2 node = new OccTree2(in);
node.next.add(new OccTree2(grabbed));
l.add(new InFlight(node));
} else
if (debug)
print("Grabber didnt't return anything. " + in.text());
} catch e {
if (debug) printStackTrace(e);
}
for (InFlight flight : nodes)
for (OccTree2 n : flight.node.next)
if (eq(n.e.type(), in.type()) && (flight.adapter != null
? flight.adapter.canMatch(n.e.text(), in.text())
: matchE(n.e, in))) {
l.add(new InFlight(n, flight.adapter == null ? null
: flight.adapter.plus(n.e.text(), in.text())));
}
nodes = l;
}
L<E> possibleNextInput() {
new HashSet<E> l;
if (repeat) l.add(tree.e);
L<InFlight> ns = cloneList(nodes);
if (repeat) setAdd(ns, new InFlight(tree, makeAdapter()));
for (InFlight flight : ns)
for (OccTree2 n : flight.node.next)
l.add(new InFlight(n, flight.adapter).adapted());
ret asList(l);
}
void remember() {
if (rewindStack != null)
rewindStack.add(cloneList(nodes));
}
E getSingleOutput() {
remember();
new L<InFlight> l;
for (InFlight flight : nodes)
for (OccTree2 n : flight.node.next)
if (n.e.a() || isCommand(n.e))
l.add(new InFlight(n, flight.adapter));
if (empty(l)) { rewind(); null; }
nodes = l;
ret first(nodes).adapted();
}
void rewind() {
nodes = popLast(rewindStack);
}
bool isCommand(E e) {
ret e.state() && matchStart("bot", e.state);
}
void noRewind() {
rewindStack = null;
}
bool matchE(E a, E b) {
// standard NL matching
ret eq(a.type(), b.type()) && match(a.text(), b.text());
}
S nodesToString(L<InFlight> nodes) {
new L<S> l;
l.add(n(l(nodes), "node"));
for (InFlight flight : nodes) {
l.add(str(flight.node.e));
if (flight.adapter != null)
l.add(" " + flight.adapter);
}
ret rtrim(fromLines(l));
}
S thoughts() {
new L<S> l;
l.add("Expecting input:\n");
for (E e : possibleNextInput())
if (e != null)
l.add(" " + e);
l.add("");
l.add(nodesToString(nodes));
if (rewindStack != null) {
l.add("\nHistory\n");
for (L<InFlight> nodes : reversedList(rewindStack))
l.add(indent(nodesToString(nodes)));
}
ret fromLines(l);
}
LooseBot debugOn() {
debug = true;
ret this;
}
}
sclass WordAdapter extends Adapter {
new Map<S, S> wordMap;
L<S> tok(S s) {
ret nlTok2(dropPunctuation2(s));
}
bool canMatch(S in, S out) {
L<S> t1 = tok(in), t2 = tok(out);
ret l(t1) == l(t2);
}
Adapter plus(S in, S out) {
L<S> t1 = tok(in), t2 = tok(out);
if (l(t1) != l(t2)) ret this;
WordAdapter a = cast nuObject(getClass());
a.wordMap = cloneMap(wordMap);
for (int i = 1; i < l(t1); i += 2) {
S w1 = t1.get(i), w2 = t2.get(i);
if (!eqic(w1, w2))
// just overwrite - be flexible!
a.wordMap.put(w1.toLowerCase(), w2.toLowerCase());
}
ret a;
}
S get(S s) {
L<S> tok = nlTok2(s);
for (int i = 1; i < l(tok); i += 2) {
S w = lookupToken(tok.get(i));
if (nempty(w))
tok.set(i, w);
}
ret join(tok);
}
S lookupToken(S s) {
ret wordMap.get(s.toLowerCase());
}
double size() {
ret l(wordMap);
}
public S toString() {
ret structure(wordMap);
}
}
sclass WordAdapter2 extends WordAdapter {
new Map<S, S> wordMap;
L<S> tok(S s) {
ret nlTok2(s);
}
}Began life as a copy of #1003412
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
| Snippet ID: | #1003413 |
| Snippet name: | LooseBot v5 (with adapters + grabbers) |
| Eternal ID of this version: | #1003413/1 |
| Text MD5: | 07e5514dfe4696e4ee1a82920e0c27a5 |
| Author: | stefan |
| Category: | javax |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2016-07-20 00:49:18 |
| Source code size: | 5466 bytes / 221 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 1090 / 2192 |
| Referenced in: | [show references] |