1 | // adapters are immutable! (plus returns a modified clone) |
2 | abstract sclass Adapter { |
3 | abstract bool canMatch(S in, S out); |
4 | Adapter plus(S in, S out) { ret this; } |
5 | S get(S in) { ret in; } |
6 | double size() { ret 0; } |
7 | } |
8 | |
9 | // node in flight (+ optional adapter) |
10 | sclass InFlight { |
11 | OccTree2 node; |
12 | Adapter adapter; |
13 | |
14 | *(OccTree2 *node) {} |
15 | *(OccTree2 *node, Adapter *adapter) {} |
16 | |
17 | E adapted() { |
18 | // TODO: security when rewriting states |
19 | ret adapter == null ? node.e : new E(adapter.get(node.e.text()), node.e.type()); |
20 | } |
21 | } |
22 | |
23 | sclass LooseBot { |
24 | sbool debug, repeat = true; |
25 | OccTree2 tree; |
26 | new L<InFlight> nodes; |
27 | new L<L> rewindStack; |
28 | O newAdapter; |
29 | O grabber; // func(S -> E) |
30 | |
31 | // WordAdapter now default |
32 | *(OccTree2 tree) { this(tree, func { new WordAdapter }); } |
33 | |
34 | // main constructor |
35 | *(OccTree2 *tree, O *newAdapter) { |
36 | expandEllipsis(tree); |
37 | } |
38 | |
39 | *(S theme) { this(makeOccTree(theme)); } |
40 | *(S theme, O newAdapter) { this(makeOccTree(theme), newAdapter); } |
41 | |
42 | Adapter makeAdapter() { |
43 | ret newAdapter == null ? null : (Adapter) call(newAdapter); |
44 | } |
45 | |
46 | void take(E in) { |
47 | remember(); |
48 | |
49 | // try starting over from beginning of tree too |
50 | if (repeat) setAdd(nodes, new InFlight(tree, makeAdapter())); |
51 | |
52 | new L<InFlight> l; |
53 | |
54 | // try grabber |
55 | if (grabber != null && in.q()) try { |
56 | E grabbed = cast callFunction(grabber, in.text()); |
57 | if (grabbed != null) { |
58 | if (debug) |
59 | print("Grabber worked! " + in.text() + " => " + grabbed); |
60 | |
61 | // make a mini tree with Q + A so it is matched in |
62 | // next call to getSingleOutput() |
63 | OccTree2 node = new OccTree2(in); |
64 | node.next.add(new OccTree2(grabbed)); |
65 | |
66 | l.add(new InFlight(node)); |
67 | } else |
68 | if (debug) |
69 | print("Grabber didnt't return anything. " + in.text()); |
70 | } catch e { |
71 | if (debug) printStackTrace(e); |
72 | } |
73 | |
74 | for (InFlight flight : nodes) |
75 | for (OccTree2 n : flight.node.next) |
76 | if (eq(n.e.type(), in.type()) && (flight.adapter != null |
77 | ? flight.adapter.canMatch(n.e.text(), in.text()) |
78 | : matchE(n.e, in))) { |
79 | l.add(new InFlight(n, flight.adapter == null ? null |
80 | : flight.adapter.plus(n.e.text(), in.text()))); |
81 | } |
82 | |
83 | nodes = l; |
84 | } |
85 | |
86 | L<E> possibleNextInput() { |
87 | new HashSet<E> l; |
88 | if (repeat) l.add(tree.e); |
89 | |
90 | L<InFlight> ns = cloneList(nodes); |
91 | if (repeat) setAdd(ns, new InFlight(tree, makeAdapter())); |
92 | for (InFlight flight : ns) |
93 | for (OccTree2 n : flight.node.next) |
94 | l.add(new InFlight(n, flight.adapter).adapted()); |
95 | ret asList(l); |
96 | } |
97 | |
98 | void remember() { |
99 | if (rewindStack != null) |
100 | rewindStack.add(cloneList(nodes)); |
101 | } |
102 | |
103 | E getSingleOutput() { |
104 | remember(); |
105 | new L<InFlight> l; |
106 | for (InFlight flight : nodes) |
107 | for (OccTree2 n : flight.node.next) |
108 | if (n.e.a() || isCommand(n.e)) |
109 | l.add(new InFlight(n, flight.adapter)); |
110 | if (empty(l)) { rewind(); null; } |
111 | nodes = l; |
112 | ret first(nodes).adapted(); |
113 | } |
114 | |
115 | void rewind() { |
116 | nodes = popLast(rewindStack); |
117 | } |
118 | |
119 | bool isCommand(E e) { |
120 | ret e.state() && matchStart("bot", e.state); |
121 | } |
122 | |
123 | void noRewind() { |
124 | rewindStack = null; |
125 | } |
126 | |
127 | bool matchE(E a, E b) { |
128 | // standard NL matching |
129 | ret eq(a.type(), b.type()) && match(a.text(), b.text()); |
130 | } |
131 | |
132 | S nodesToString(L<InFlight> nodes) { |
133 | new L<S> l; |
134 | l.add(n(l(nodes), "node")); |
135 | for (InFlight flight : nodes) { |
136 | l.add(str(flight.node.e)); |
137 | if (flight.adapter != null) |
138 | l.add(" " + flight.adapter); |
139 | } |
140 | ret rtrim(fromLines(l)); |
141 | } |
142 | |
143 | S thoughts() { |
144 | new L<S> l; |
145 | l.add("Expecting input:\n"); |
146 | for (E e : possibleNextInput()) |
147 | if (e != null) |
148 | l.add(" " + e); |
149 | l.add(""); |
150 | l.add(nodesToString(nodes)); |
151 | if (rewindStack != null) { |
152 | l.add("\nHistory\n"); |
153 | for (L<InFlight> nodes : reversedList(rewindStack)) |
154 | l.add(indent(nodesToString(nodes))); |
155 | } |
156 | ret fromLines(l); |
157 | } |
158 | |
159 | LooseBot debugOn() { |
160 | debug = true; |
161 | ret this; |
162 | } |
163 | } |
164 | |
165 | sclass WordAdapter extends Adapter { |
166 | new Map<S, S> wordMap; |
167 | |
168 | L<S> tok(S s) { |
169 | ret nlTok2(dropPunctuation2(s)); |
170 | } |
171 | |
172 | bool canMatch(S in, S out) { |
173 | L<S> t1 = tok(in), t2 = tok(out); |
174 | ret l(t1) == l(t2); |
175 | } |
176 | |
177 | Adapter plus(S in, S out) { |
178 | L<S> t1 = tok(in), t2 = tok(out); |
179 | if (l(t1) != l(t2)) ret this; |
180 | |
181 | WordAdapter a = cast nuObject(getClass()); |
182 | a.wordMap = cloneMap(wordMap); |
183 | for (int i = 1; i < l(t1); i += 2) { |
184 | S w1 = t1.get(i), w2 = t2.get(i); |
185 | if (!eqic(w1, w2)) |
186 | // just overwrite - be flexible! |
187 | a.wordMap.put(w1.toLowerCase(), w2.toLowerCase()); |
188 | } |
189 | ret a; |
190 | } |
191 | |
192 | S get(S s) { |
193 | L<S> tok = nlTok2(s); |
194 | for (int i = 1; i < l(tok); i += 2) { |
195 | S w = lookupToken(tok.get(i)); |
196 | if (nempty(w)) |
197 | tok.set(i, w); |
198 | } |
199 | ret join(tok); |
200 | } |
201 | |
202 | S lookupToken(S s) { |
203 | ret wordMap.get(s.toLowerCase()); |
204 | } |
205 | |
206 | double size() { |
207 | ret l(wordMap); |
208 | } |
209 | |
210 | public S toString() { |
211 | ret structure(wordMap); |
212 | } |
213 | } |
214 | |
215 | sclass WordAdapter2 extends WordAdapter { |
216 | new Map<S, S> wordMap; |
217 | |
218 | L<S> tok(S s) { |
219 | ret nlTok2(s); |
220 | } |
221 | } |
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: | 593 / 1722 |
Referenced in: | [show references] |