« Games from the days of 1200 baud modems | Main | What is the What? »
October 17, 2007
Eliza in Apex Code
Every time I do a new project I like to rebuild Eliza in a programming language. Here is Eliza with a Visual Force page and Apex code as the underlying implementation. It doesn't support a lot of different sentence types but there is enough to work now.
The display is done as a Visual Force Page:
<apex:page controller=\"ElizaController\" showHeader=\"false\">
<p>Hello Welcome to the Apex Question and Answer Page </p>
<apex:form id=\"questionForm\">
<apex:inputText id=\"questionText\" value=\"{!QuestionText}\"></apex:inputText>
<!-- apex:commandButton value=\"Click Here\"><apex:param name=\"question\" value=\"{!QuestionText}\"/></apex:commandButton -->
<apex:commandButton value=\"Click Here\"></apex:commandButton>
</apex:form>
<p>Your Question: {!questionText} </p><b> Your Answer: {!answer}</b></p>
</apex:page>
<p>Hello Welcome to the Apex Question and Answer Page </p>
<apex:form id=\"questionForm\">
<apex:inputText id=\"questionText\" value=\"{!QuestionText}\"></apex:inputText>
<!-- apex:commandButton value=\"Click Here\"><apex:param name=\"question\" value=\"{!QuestionText}\"/></apex:commandButton -->
<apex:commandButton value=\"Click Here\"></apex:commandButton>
</apex:form>
<p>Your Question: {!questionText} </p><b> Your Answer: {!answer}</b></p>
</apex:page>
With a custom controller:
public class ElizaController {
private String QuestionText;
public void setQuestionText(String val) {
questionText = val;
}
public String getQuestionText() {
return questionText;
}
public String getAnswer() {
return Eliza.converse(questionText);
}
}
Most of the work is done in the Eliza Util class:
public class ElizaUtil {
private Map variables = new Map();
private static String[] wwords = new String[]{'when','why','where','how'};
public String getValue(String var) {
return variables.get(var);
}
public void setValue(String var,String val) {
variables.put(var,val);
}
public static String wWord() {
Integer value = Math.round(Math.random()*3.0);
return wwords[value];
}
public boolean atom(String s) {
if (s == null) return true;
return s.split(' ',2).size() == 1;
}
public String car(String s) {
if (s == null) return null;
String[] words = s.split(' ',2);
if (words.size() == 0) return null;
return words[0];
}
public String cdr(String s) {
if (s == null) return null;
String[]words = s.split(' ',30);
if (words.size() < 2) return null;
String result = words[1];
for(Integer i=2;i < words.size();i++){
result = result + ' ' + words[i];
}
return result;
}
private static String variableName(String s) {
if (s.length() < 2) return 'default';
else return s.substring(1,2);
}
public Boolean match(String p, String s) {
variables.clear();
return submatch(p,s);
}
public Boolean submatch (String p, String s) {
if (p == null) {
return (s == null);
} else if (s != null && (car(p) == car (s)) && submatch(cdr(p),cdr(s))) {
return true;
} else if (s != null && car(p).startsWith('?')) {
if (match(cdr(p),cdr(s))) {
setValue(variableName(car(p)),car(s));
return true;
}
else return false;
} else if (s != null && car(p).startsWith('*')) {
if (s != null && submatch(cdr(p),cdr(s))) {
setValue(variableName(car(p)),car(s));
return true;
} else if (match(cdr(p),s)) {
setValue(variableName(car(p)),null);
return true;
} else if (s!=null && submatch(p,cdr(s))) {
String currentValue = getValue(variableName(car(p)));
if (currentValue == null) currentValue ='';
setValue(variableName(car(p)),car(s)+' '+currentValue);
return true;
}
return false;
}
return false;
}
static testMethod void testMatchPositive() {
ElizaUtil eu = new ElizaUtil();
System.assertEquals(eu.match('Hello','Hello'),true);
System.assertEquals(eu.match('Hello to you','Hello to you'),true);
System.assertEquals(eu.match('Another test','Another test'),true);
System.assertEquals(eu.match(null,null),true);
}
static testMethod void testMatchNegative() {
ElizaUtil eu = new ElizaUtil();
System.assertEquals(eu.match('Hello to you','Hello to me'),false);
System.assertEquals(eu.match('a',null),false);
System.assertEquals(eu.match(null,'a'),false);
System.assertEquals(eu.match('me','you'),false);
}
static testMethod void testMatchAdvanced() {
ElizaUtil eu = new ElizaUtil();
System.assertEquals(eu.match('*X to you','Hello to me and to you'),true);
System.debug(eu.getValue('X'));
System.assertEquals(eu.getValue('X'),'Hello to me and');
System.assertEquals(eu.match('?X to you','Hello to you'),true);
System.assertEquals(eu.getValue('X'),'Hello');
System.debug(eu.getValue('X'));
System.assertEquals(eu.match('Hello to ?X *Y','Hello to Chris and friends'),true);
System.debug('X->'+eu.getValue('X')+' Y->'+eu.getValue('Y'));
System.assertEquals(eu.getValue('X'),'Chris');
System.assertEquals(eu.getValue('Y'),'and friends');
System.assertEquals(eu.match('*X to you','Hello to me'),false);
System.assertEquals(eu.match('?X to you','Hello to me'),false);
}
static testMethod void testCarCdr() {
ElizaUtil eu = new ElizaUtil();
System.assertEquals(eu.car('Hello'),'Hello');
System.assertEquals(eu.car('Hello to you'),'Hello');
System.assertEquals(eu.cdr('Hello to you'),'to you');
System.assertEquals(eu.cdr('Hello'),null);
System.assertEquals(eu.cdr(null),null);
}
}
Posted by Chris at October 17, 2007 04:30 PM