Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

231
LINES

< > BotCompany Repo | #1002211 // 1st Level Dialog Engine, multi-user, multi-script (LIVE)

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Click here for Pure Java version (2720L/18K/58K).

1  
!759
2  
3  
static Map<S, L<S>> thescripts = synchroTreeMap();
4  
5  
static class PerUser {
6  
  S dialogID;
7  
  ScriptState scriptState;
8  
}
9  
10  
static class ScriptState {
11  
  S scriptID;
12  
  long position;
13  
  
14  
  *(S *scriptID) {}
15  
  *() {}
16  
}
17  
18  
static new Map<S, PerUser> perUserMap;
19  
static new ThreadLocal<PerUser> puCurrent;
20  
static new ThreadLocal<ScriptState> scriptStateCurrent;
21  
22  
static new L<S> snippetIDs;
23  
24  
static O mainBot;
25  
  
26  
p {
27  
  load("snippetIDs");
28  
  
29  
  reload();
30  
  
31  
  load("perUserMap");
32  
  makeBot("A Dialog Bot");
33  
}
34  
35  
// does not increase the index
36  
static FC parseFunctionCall() {
37  
  ret parseFunctionCall(currentScriptLine());
38  
}
39  
40  
static S currentScriptLine() {
41  
  int l = l(thescript());
42  
  int idx = (int) (scriptState().position % l);
43  
  ret thescript().get(idx);
44  
}
45  
46  
synchronized answer {
47  
  // init per-user stuff
48  
  
49  
  S dialogID = cast call(mainBot, "getDialogID");
50  
  
51  
  if "get dialog id" {
52  
    ret structure(dialogID);
53  
  }
54  
  
55  
  if "dialog engine: number of users" {
56  
    ret str(l(perUserMap));
57  
  }
58  
  
59  
  if (dialogID == null) ret null; // need a dialog id now
60  
  PerUser pu = perUserMap.get(dialogID);
61  
  if (pu == null) {
62  
    pu = new PerUser;
63  
    pu.dialogID = dialogID;
64  
    printFormat("Created new dialog: *", dialogID);
65  
    perUserMap.put(dialogID, pu);
66  
  }
67  
  puCurrent.set(pu);
68  
  
69  
  // admin stuff
70  
  
71  
  if "print scripts"
72  
    ret structure(thescripts);
73  
    
74  
  if "list scripts"
75  
    ret structure(snippetIDs);
76  
    
77  
  if "add dialog script *" {
78  
    setAdd(snippetIDs, formatSnippetID(m.unq(0)));
79  
    save("snippetIDs");
80  
    reload();
81  
    ret "OK, scripts now: " + structure(snippetIDs);
82  
  }
83  
  
84  
  if "remove dialog script *" {
85  
    snippetIDs.remove(formatSnippetID(m.unq(0)));
86  
    save("snippetIDs");
87  
    reload();
88  
    ret "OK, scripts now: " + structure(snippetIDs);
89  
  }
90  
  
91  
  if "reload dialogs" {
92  
    reload();
93  
    ret "OK, " + l(snippetIDs) + " dialog scripts reloaded.";
94  
  }
95  
  
96  
  // try current script first
97  
  
98  
  pcall {
99  
    if (u().scriptState != null && thescript() != null) {
100  
      S answer = answerUsingScript(u().scriptState, s);
101  
      if (!empty(answer)) ret answer;
102  
    }
103  
  }
104  
  
105  
  // try all scripts
106  
  
107  
  for (S scriptID : thescripts.keySet()) pcall {
108  
    ScriptState scriptState = new ScriptState(scriptID);
109  
    S answer = answerUsingScript(scriptState, s);
110  
    if (!empty(answer)) {
111  
      u().scriptState = scriptState; // Switch to new script
112  
      save("perUserMap");
113  
      ret answer;
114  
    }
115  
  }
116  
}
117  
118  
static synchronized S answerUsingScript(ScriptState scriptState, S s) {
119  
  scriptStateCurrent.set(scriptState);
120  
  int safety = 0;
121  
  while (safety++ < 1000) try {
122  
    FC fc = parseFunctionCall();
123  
    S f = fc.f;
124  
    if (eq(f, "match")) {
125  
      S pat = getString(fc.args, 0);
126  
      if (!match(pat, s)) {
127  
        softFail("I only understand: *", pat);
128  
        null;
129  
      }
130  
      nextPosition(); // only after match succeeds, otherwise stay at that point
131  
    } else if (eq(f, "say")) {
132  
      nextPosition();
133  
      S answer = getString(fc.args, 0);
134  
      ret answer;
135  
    } else
136  
      throw fail("Unknown function in script: *", fc.f);
137  
  } catch (Throwable e) {
138  
    printFormat("Was parsing: *", currentScriptLine());
139  
    throw asRuntimeException(e);
140  
  }
141  
  throw fail("hard limit reached - 1000 script lines at once - possible endless loop?");
142  
}
143  
144  
// a parsed function call
145  
static class FC {
146  
  int idx; // index of next token
147  
  S f;
148  
  new L args;
149  
}
150  
151  
static FC parseFunctionCall(S s) {
152  
  L<S> tok = javaTok(s);
153  
  new FC fc;
154  
  fc.f = assertIsIdentifier(tok.get(1));
155  
  int i = 5;
156  
  assertEquals("(", tok.get(3));
157  
  while (i < l(tok) && !eq(tok.get(i), ")")) {
158  
    fc.args.add(unquote(tok.get(i)));
159  
    i += 2;
160  
    if (tok.get(i).equals(",")) // otherwise it's kinda mangled, eh. well! we just keep on parsing...
161  
      i += 2;
162  
  }
163  
  if (eq(tok.get(i), ")")) // we even allow a missing closing bracket!
164  
    i += 2;
165  
  fc.idx = i; // save index so some other parser can continue parsing
166  
  ret fc;
167  
}
168  
169  
static void nextPosition() {
170  
  ++scriptState().position;
171  
  save("perUserMap"); // might not always be necessary
172  
  print("Position in script now: " + scriptState().position % l(thescript()));
173  
}
174  
175  
// get per-user data for current thread
176  
static PerUser u() {
177  
  ret puCurrent.get();
178  
}
179  
180  
static ScriptState scriptState() {
181  
  ret scriptStateCurrent.get();
182  
}
183  
184  
static L<S> thescript() {
185  
  S scriptID = scriptState().scriptID;
186  
  ret thescripts.get(scriptID);
187  
}
188  
189  
static void loadMore() {
190  
  for (S snippetID : snippetIDs) pcall {
191  
    L<S> lines = toLinesFullTrim(loadSnippet(snippetID));
192  
    new L<S> currentScript;
193  
    int i = 0;
194  
    for (; i < l(lines); i += 2) {
195  
      S q = lines.get(i);
196  
      if (q.startsWith("-")) {
197  
        if (nempty(currentScript))
198  
          thescripts.put(snippetID + "-" + i, currentScript);
199  
        currentScript = litlist();
200  
        --i;
201  
      } else {
202  
        S a = lines.get(i+1);
203  
        a = dropPrefix("eleu:", a).trim();
204  
        currentScript.addAll(litlist(
205  
          "match(" + quote(q) + ");",
206  
          "say(" + quote(a) + ");"));
207  
      }
208  
    }
209  
    if (nempty(currentScript))
210  
      thescripts.put(snippetID + "-" + i, currentScript);
211  
  }
212  
}
213  
214  
static void reload() {
215  
  thescripts.clear();
216  
  thescripts.put("1", toLinesFullTrim([[
217  
    match("Hi Eleutheria");
218  
    say("Hi there!");
219  
    match("Hi Eleutheria");
220  
    say("You have said that before :)");
221  
  ]]));
222  
  
223  
  thescripts.put("2", toLinesFullTrim([[
224  
    match("how old are you");
225  
    say("less than one year i believe");
226  
    match("really?");
227  
    say("yeah");
228  
  ]]));
229  
  
230  
  loadMore();
231  
}  

Author comment

Began life as a copy of #1002210

download  show line numbers  debug dex  old transpilations   

Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1002211
Snippet name: 1st Level Dialog Engine, multi-user, multi-script (LIVE)
Eternal ID of this version: #1002211/1
Text MD5: 7cd1fd6375bdc8169cc00de2810aa09b
Transpilation MD5: eb4f5cd515e05435a138bcad2dc94365
Author: stefan
Category: javax
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-01-23 19:41:21
Source code size: 5679 bytes / 231 lines
Pitched / IR pitched: No / No
Views / Downloads: 915 / 2079
Referenced in: [show references]