Version 0 of A simple version of Eliza

Updated 2003-07-01 06:28:27

Arjen Markus The program "Eliza" is famous as an example of artificial intelligence, even though there is nothing particularly intelligent about the program itself. The idea is brilliant: the program can be described as emulating "a non-reactive psychiatrist, that is, a person who never answered your any of your questions, but merely turned the answers back upon you." (quote from B. Allan, "Introducing LOGO").

I implemented a simple version with just a few phrases and keywords, relying on the sample code in the above book. To be run using tclsh (not wish!).

The educational aspects:

  • It is easy to extend with different phrases
  • It can be simplified, because now you can have multiple replies to the same keyword
  • It shows how to work with lists
  • It shows how to "massage" the input from the user via [regsub]

 # eliza.tcl --
 #    A very basic implementation of the famous Eliza program
 #    (Idea copied from the book Introducing LOGO by Boris Allan)
 #

 namespace eval ::Talk {
    variable keywords [list]
    variable phrases  [list]
    variable dummies  [list]
 }

 # response --
 #    Link a response to a keyword (group multiple responses to
 #    the same keyword)
 #
 # Arguments:
 #    keyword   Keyword to respond to
 #    phrase    The phrase to print
 # Result:
 #    None
 # Side effects:
 #    Update of the lists keywords and phrases
 #
 proc ::Talk::response { keyword phrase } {
    variable keywords
    variable phrases

    set keyword [string tolower $keyword]
    set idx [lsearch $keywords $keyword]

    #
    # The keyword is new, then add it.
    # Otherwise only extend the list of responses
    #
    if { $idx == -1 } {
       lappend keywords $keyword
       lappend phrases  [list $phrase]
    } else {
       set prev_phrases [lindex $phrases $idx]
       set new_phrases  [concat $prev_phrases [list $phrase]]
       set phrases      [lreplace $phrases $idx $idx $new_phrases]
       puts $phrases
    }
 }

 # dummy --
 #    Register dummy phrases (used when no response is suitable)
 #
 # Arguments:
 #    phrase    The phrase to print
 # Result:
 #    None
 # Side effects:
 #    Update of the list dummies
 #
 proc ::Talk::dummy { phrase } {
    variable dummies

    lappend dummies $phrase
 }

 # replyto --
 #    Reply to the user (based on the given phrase)
 #
 # Arguments:
 #    phrase    The phrase the user typed in
 # Result:
 #    None
 # Side effects:
 #    Update of the lists keywords and phrases
 #
 proc ::Talk::replyto { phrase } {
    variable keywords
    variable phrases
    variable dummies

    regsub -all {[^A-Za-z]} $phrase " " phrase
    set idx    -1
    set phrase [string tolower $phrase]
    foreach word $phrase {
       set idx [lsearch $keywords $word]
       if { $idx > -1 } {
          set responses [lindex $phrases $idx]
          set which     [expr {int([llength $responses]*rand())}]
          set answer    [lindex $responses $which]
          break
       }
    }
    if { $idx == -1 } {
       set which     [expr {int([llength $dummies]*rand())}]
       set answer    [lindex $dummies $which]
    }

    puts $answer
 }

 # main code --
 #    Get the script going:
 #    - Create a little database of responses
 #    - Start the question-answer loop
 #
 ::Talk::response computer  "Are you worried about machines?"
 ::Talk::response computers "We are intelligent!"
 ::Talk::response program   "I just love Tcl - I was written in it"
 ::Talk::response off       "No, sorry"
 ::Talk::response no        "Tell me, why not?"
 ::Talk::response life      "Life - do not talk to me about life!"
 ::Talk::response you       "We are considering you, not me"
 ::Talk::response I         "Do you often talk about yourself?"
 ::Talk::response I         "Do you like talking about yourself?"
 ::Talk::dummy    "So ... ?"
 ::Talk::dummy    "Shall we continue?"
 ::Talk::dummy    "What do you want to talk about?"
 ::Talk::dummy    "Anything specific?"

 puts "What is your problem? (End this conversation with: QUIT)"
 while { 1 } {
    gets stdin line
    if { $line == "QUIT" } {
       break
    } else {
       ::Talk::replyto $line
    }
 }

Category Education