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).

!759

static Map<S, L<S>> thescripts = synchroTreeMap();

static class PerUser {
  S dialogID;
  ScriptState scriptState;
}

static class ScriptState {
  S scriptID;
  long position;
  
  *(S *scriptID) {}
  *() {}
}

static new Map<S, PerUser> perUserMap;
static new ThreadLocal<PerUser> puCurrent;
static new ThreadLocal<ScriptState> scriptStateCurrent;

static new L<S> snippetIDs;

static O mainBot;
  
p {
  load("snippetIDs");
  
  reload();
  
  load("perUserMap");
  makeBot("A Dialog Bot");
}

// does not increase the index
static FC parseFunctionCall() {
  ret parseFunctionCall(currentScriptLine());
}

static S currentScriptLine() {
  int l = l(thescript());
  int idx = (int) (scriptState().position % l);
  ret thescript().get(idx);
}

synchronized answer {
  // init per-user stuff
  
  S dialogID = cast call(mainBot, "getDialogID");
  
  if "get dialog id" {
    ret structure(dialogID);
  }
  
  if "dialog engine: number of users" {
    ret str(l(perUserMap));
  }
  
  if (dialogID == null) ret null; // need a dialog id now
  PerUser pu = perUserMap.get(dialogID);
  if (pu == null) {
    pu = new PerUser;
    pu.dialogID = dialogID;
    printFormat("Created new dialog: *", dialogID);
    perUserMap.put(dialogID, pu);
  }
  puCurrent.set(pu);
  
  // admin stuff
  
  if "print scripts"
    ret structure(thescripts);
    
  if "list scripts"
    ret structure(snippetIDs);
    
  if "add dialog script *" {
    setAdd(snippetIDs, formatSnippetID(m.unq(0)));
    save("snippetIDs");
    reload();
    ret "OK, scripts now: " + structure(snippetIDs);
  }
  
  if "remove dialog script *" {
    snippetIDs.remove(formatSnippetID(m.unq(0)));
    save("snippetIDs");
    reload();
    ret "OK, scripts now: " + structure(snippetIDs);
  }
  
  if "reload dialogs" {
    reload();
    ret "OK, " + l(snippetIDs) + " dialog scripts reloaded.";
  }
  
  // try current script first
  
  pcall {
    if (u().scriptState != null && thescript() != null) {
      S answer = answerUsingScript(u().scriptState, s);
      if (!empty(answer)) ret answer;
    }
  }
  
  // try all scripts
  
  for (S scriptID : thescripts.keySet()) pcall {
    ScriptState scriptState = new ScriptState(scriptID);
    S answer = answerUsingScript(scriptState, s);
    if (!empty(answer)) {
      u().scriptState = scriptState; // Switch to new script
      save("perUserMap");
      ret answer;
    }
  }
}

static synchronized S answerUsingScript(ScriptState scriptState, S s) {
  scriptStateCurrent.set(scriptState);
  int safety = 0;
  while (safety++ < 1000) try {
    FC fc = parseFunctionCall();
    S f = fc.f;
    if (eq(f, "match")) {
      S pat = getString(fc.args, 0);
      if (!match(pat, s)) {
        softFail("I only understand: *", pat);
        null;
      }
      nextPosition(); // only after match succeeds, otherwise stay at that point
    } else if (eq(f, "say")) {
      nextPosition();
      S answer = getString(fc.args, 0);
      ret answer;
    } else
      throw fail("Unknown function in script: *", fc.f);
  } catch (Throwable e) {
    printFormat("Was parsing: *", currentScriptLine());
    throw asRuntimeException(e);
  }
  throw fail("hard limit reached - 1000 script lines at once - possible endless loop?");
}

// a parsed function call
static class FC {
  int idx; // index of next token
  S f;
  new L args;
}

static FC parseFunctionCall(S s) {
  L<S> tok = javaTok(s);
  new FC fc;
  fc.f = assertIsIdentifier(tok.get(1));
  int i = 5;
  assertEquals("(", tok.get(3));
  while (i < l(tok) && !eq(tok.get(i), ")")) {
    fc.args.add(unquote(tok.get(i)));
    i += 2;
    if (tok.get(i).equals(",")) // otherwise it's kinda mangled, eh. well! we just keep on parsing...
      i += 2;
  }
  if (eq(tok.get(i), ")")) // we even allow a missing closing bracket!
    i += 2;
  fc.idx = i; // save index so some other parser can continue parsing
  ret fc;
}

static void nextPosition() {
  ++scriptState().position;
  save("perUserMap"); // might not always be necessary
  print("Position in script now: " + scriptState().position % l(thescript()));
}

// get per-user data for current thread
static PerUser u() {
  ret puCurrent.get();
}

static ScriptState scriptState() {
  ret scriptStateCurrent.get();
}

static L<S> thescript() {
  S scriptID = scriptState().scriptID;
  ret thescripts.get(scriptID);
}

static void loadMore() {
  for (S snippetID : snippetIDs) pcall {
    L<S> lines = toLinesFullTrim(loadSnippet(snippetID));
    new L<S> currentScript;
    int i = 0;
    for (; i < l(lines); i += 2) {
      S q = lines.get(i);
      if (q.startsWith("-")) {
        if (nempty(currentScript))
          thescripts.put(snippetID + "-" + i, currentScript);
        currentScript = litlist();
        --i;
      } else {
        S a = lines.get(i+1);
        a = dropPrefix("eleu:", a).trim();
        currentScript.addAll(litlist(
          "match(" + quote(q) + ");",
          "say(" + quote(a) + ");"));
      }
    }
    if (nempty(currentScript))
      thescripts.put(snippetID + "-" + i, currentScript);
  }
}

static void reload() {
  thescripts.clear();
  thescripts.put("1", toLinesFullTrim([[
    match("Hi Eleutheria");
    say("Hi there!");
    match("Hi Eleutheria");
    say("You have said that before :)");
  ]]));
  
  thescripts.put("2", toLinesFullTrim([[
    match("how old are you");
    say("less than one year i believe");
    match("really?");
    say("yeah");
  ]]));
  
  loadMore();
}  

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: 914 / 2078
Referenced in: [show references]