package net.chayden; import java.awt.BorderLayout; import java.awt.Event; import java.awt.Panel; import java.awt.TextArea; import java.awt.TextField; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; /** * Eliza main class. * Stores the processed script. * Does the input transformations. */ public class ElizaMain { final boolean echoInput = false; final boolean printData = false; final boolean printKeys = false; final boolean printSyns = false; final boolean printPrePost = false; final boolean printInitialFinal = false; /** The key list */ KeyList keys = new KeyList(); /** The syn list */ SynList syns = new SynList(); /** The pre list */ PrePostList pre = new PrePostList(); /** The post list */ PrePostList post = new PrePostList(); /** Initial string */ String initial = "Hello."; /** Final string */ String finl = "Goodbye."; /** Quit list */ WordList quit = new WordList(); /** Key stack */ KeyStack keyStack = new KeyStack(); /** Memory */ public /* made public to add history from Voyant */ Mem mem = new Mem(); DecompList lastDecomp; ReasembList lastReasemb; boolean finished = false; static final int success = 0; static final int failure = 1; static final int gotoRule = 2; public boolean finished() { return finished; } /** * Process a line of script input. */ public void collect(String s) { String lines[] = new String[4]; if (EString.match(s, "*reasmb: *", lines)) { if (lastReasemb == null) { System.out.println("Error: no last reasemb"); return; } lastReasemb.add(lines[1]); } else if (EString.match(s, "*decomp: *", lines)) { if (lastDecomp == null) { System.out.println("Error: no last decomp"); return; } lastReasemb = new ReasembList(); String temp = new String(lines[1]); if (EString.match(temp, "$ *", lines)) { lastDecomp.add(lines[0], true, lastReasemb); } else { lastDecomp.add(temp, false, lastReasemb); } } else if (EString.match(s, "*key: * #*", lines)) { lastDecomp = new DecompList(); lastReasemb = null; int n = 0; if (lines[2].length() != 0) { try { n = Integer.parseInt(lines[2]); } catch (NumberFormatException e) { System.out.println("Number is wrong in key: " + lines[2]); } } keys.add(lines[1], n, lastDecomp); } else if (EString.match(s, "*key: *", lines)) { lastDecomp = new DecompList(); lastReasemb = null; keys.add(lines[1], 0, lastDecomp); } else if (EString.match(s, "*synon: * *", lines)) { WordList words = new WordList(); words.add(lines[1]); s = lines[2]; while (EString.match(s, "* *", lines)) { words.add(lines[0]); s = lines[1]; } words.add(s); syns.add(words); } else if (EString.match(s, "*pre: * *", lines)) { pre.add(lines[1], lines[2]); } else if (EString.match(s, "*post: * *", lines)) { post.add(lines[1], lines[2]); } else if (EString.match(s, "*initial: *", lines)) { initial = lines[1]; } else if (EString.match(s, "*final: *", lines)) { finl = lines[1]; } else if (EString.match(s, "*quit: *", lines)) { quit.add(" " + lines[1]+ " "); } else { System.out.println("Unrecognized input: " + s); } } /** * Print the stored script. */ public void print() { if (printKeys) keys.print(0); if (printSyns) syns.print(0); if (printPrePost) { pre.print(0); post.print(0); } if (printInitialFinal) { System.out.println("initial: " + initial); System.out.println("final: " + finl); quit.print(0); } } /** * Process a line of input. */ public String processInput(String s) { String reply; // Do some input transformations first. s = EString.translate(s, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"); s = EString.translate(s, "@#$%^&*()_-+=~`{[}]|:;<>\\\"", " " ); s = EString.translate(s, ",?!", "..."); // Compress out multiple speace. s = EString.compress(s); String lines[] = new String[2]; // Break apart sentences, and do each separately. while (EString.match(s, "*.*", lines)) { reply = sentence(lines[0]); if (reply != null) return reply; s = EString.trim(lines[1]); } if (s.length() != 0) { reply = sentence(s); if (reply != null) return reply; } // Nothing matched, so try memory. String m = mem.get(); if (m != null) return m; // No memory, reply with xnone. Key key = keys.getKey("xnone"); if (key != null) { Key dummy = null; reply = decompose(key, s, dummy); if (reply != null) return reply; } // No xnone, just say anything. return "I am at a loss for words."; } /** * Process a sentence. * (1) Make pre transformations. * (2) Check for quit word. * (3) Scan sentence for keys, build key stack. * (4) Try decompositions for each key. */ String sentence(String s) { s = pre.translate(s); s = EString.pad(s); if (quit.find(s)) { finished = true; return finl; } keys.buildKeyStack(keyStack, s); for (int i = 0; i < keyStack.keyTop(); i++) { Key gotoKey = new Key(); String reply = decompose(keyStack.key(i), s, gotoKey); if (reply != null) return reply; // If decomposition returned gotoKey, try it while (gotoKey.key() != null) { reply = decompose(gotoKey, s, gotoKey); if (reply != null) return reply; } } return null; } /** * Decompose a string according to the given key. * Try each decomposition rule in order. * If it matches, assemble a reply and return it. * If assembly fails, try another decomposition rule. * If assembly is a goto rule, return null and give the key. * If assembly succeeds, return the reply; */ String decompose(Key key, String s, Key gotoKey) { String reply[] = new String[10]; for (int i = 0; i < key.decomp().size(); i++) { Decomp d = (Decomp)key.decomp().elementAt(i); String pat = d.pattern(); if (syns.matchDecomp(s, pat, reply)) { String rep = assemble(d, reply, gotoKey); if (rep != null) return rep; if (gotoKey.key() != null) return null; } } return null; } /** * Assembly a reply from a decomp rule and the input. * If the reassembly rule is goto, return null and give * the gotoKey to use. * Otherwise return the response. */ String assemble(Decomp d, String reply[], Key gotoKey) { String lines[] = new String[3]; d.stepRule(true); String rule = d.nextRule(); if (EString.match(rule, "goto *", lines)) { // goto rule -- set gotoKey and return false. gotoKey.copy(keys.getKey(lines[0])); if (gotoKey.key() != null) return null; System.out.println("Goto rule did not match key: " + lines[0]); return null; } String work = ""; while (EString.match(rule, "* (#)*", lines)) { // reassembly rule with number substitution rule = lines[2]; // there might be more int n = 0; try { n = Integer.parseInt(lines[1]) - 1; } catch (NumberFormatException e) { System.out.println("Number is wrong in reassembly rule " + lines[1]); } if (n < 0 || n >= reply.length) { System.out.println("Substitution number is bad " + lines[1]); return null; } reply[n] = post.translate(reply[n]); work += lines[0] + " " + reply[n]; } work += rule; if (d.mem()) { mem.save(work); return null; } return work; } TextArea textarea; TextField textfield; public void response(String str) { textarea.appendText(str); textarea.appendText("\n"); } public /* this was made public to be called from Voyant */ int readScript(boolean local, String script) { DataInputStream in; try { if (local) { in = new DataInputStream(new FileInputStream(script)); } else { try { URL url = new URL(script); URLConnection connection = url.openConnection(); in = new DataInputStream(connection.getInputStream()); } catch (MalformedURLException e) { System.out.println("The URL is malformed: " + script); return 1; } catch (IOException e) { System.out.println("Could not read script file."); return 1; } } while (true) { String s; s = in.readLine(); if (s == null) break; if (echoInput) System.out.println(s); collect(s); } } catch (IOException e) { System.out.println("There was a problem reading the script file."); System.out.println("Tried " + script); return 1; } if (printData) print(); return 0; } int runProgram(String test, Panel w) { DataInputStream in; if (w != null) { w.setLayout(new BorderLayout(15, 15)); textarea = new TextArea(10, 40); textarea.setEditable(false); w.add("Center", textarea); textfield = new TextField(15); w.add("South", textfield); w.resize(600, 300); w.show(); String hello = "Hello."; response(">> " + hello); response(processInput(hello)); textfield.requestFocus(); } else { try { in = new DataInputStream(new FileInputStream(test)); String s; s = "Hello."; while (true) { System.out.println(">> " + s); String reply = processInput(s); System.out.println(reply); if (finished) break; s = in.readLine(); if (s == null) break; } } catch (IOException e) { System.out.println("Problem reading test file."); return 1; } } return 0; } public boolean handleEvent(Event event) { switch (event.id) { case Event.ACTION_EVENT: if (event.target == textfield) { String input = (String)event.arg; String reply = processInput(input); textfield.setText(""); response(">> " + input); response(reply); return true; } } return false; } }