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

229
LINES

< > BotCompany Repo | #1003575 // LooseBot v6 (with generic adapters)

JavaX fragment (include)

// 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; }
}

abstract sclass GenericAdapter {
  void modify(OccTree2 node) {}
}

// 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)
  GenericAdapter genericAdapter;

  // 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 (genericAdapter != null)
          genericAdapter.modify(n);
        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);
  }
}

Author comment

Began life as a copy of #1003413

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1003575
Snippet name: LooseBot v6 (with generic adapters)
Eternal ID of this version: #1003575/1
Text MD5: 0174bb8b912c2c411b624bfcc5bc9b0c
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:54:32
Source code size: 5649 bytes / 229 lines
Pitched / IR pitched: No / No
Views / Downloads: 450 / 407
Referenced in: [show references]