The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

Wednesday, November 11, 2015

The Psychotherapy of Racter

One idea I have for this year's NaNoGenMo is Oz As She Is Spoke, an homage to English As She Is Spoke. The process is simple. Take the text from The Wonderful Wizard of Oz:

She was awakened by a shock, so sudden and severe that if Dorothy had not been lying on the soft bed she might have been hurt. As it was, the jar made her catch her breath and wonder what had happened; and Toto put his cold little nose into her face and whined dismally. Dorothy sat up and noticed that the house was not moving; nor was it dark, for the bright sunshine came in at the window, flooding the little room. She sprang from her bed and with Toto at her heels ran and opened the door.

The Wonderful Wizard of Oz, Chapter 2

and translate it to language A, then from A to B, and finally back to English:

Dorothy was he suddenly so bad, was awake by pushing The injury may have been lying on a soft bed, no. This was, This jar to catch his spirit, and he was made the surprise; And Toto put his cold little nose and his face and dismally whined. Dorothy sat up and noticed that the house is not growing; Nor was it Dark, bright sunlight entering through the window, the fill A small room. He sprang with his heel into his bed and ran to and Toto And has opened the door.

(I'll leave it to you, dear reader, to figure out the two intermediate langauges I used) Amusing, but I think I'll save that idea in case my current idea, a conversation between Racter and Eliza (the idea that Bunny would like to see) proves to be too difficult to pull off.

So, before tackling the difficult problem of “scripting Racter” I'd thought I'd try to get a version of Eliza up and running. I found this version, and with this commentary, it's pretty easy to see how Eliza works.

We can map the key sequences to possible responses:

local keyword_reply =
  ["can you"] =
    "Don't you believe that i can*",
    "Perhaps you would like me to be able to*",
    "You want me to be able to*",

  ["can i"] =
    "Perhaps you don't want to*",
    "Do you want to be able to*",

  ["you are"] =
    "What makes you think i am*",
    "Does it please you believe i am *",
    "Perhaps you would like to be*", 
    "Do you sometimes wish you were*",

  -- ...

And by using LPeg, we can easily build a parsing pattern that can match these key sequences:

local nonalpha = R(" @","[`","{~")

local keywords = P(false)
for kw in pairs(keyword_reply) do
  if kw ~= "" then
    keywords = keywords + P(kw)

local parse = (P(1) - (keywords * nonalpha))^0 * C(keywords) * C(P(1)^0)

key,rest = parse:match "please, can i turn you off now?"

key will contain “can i” and rest will contain “turn you off now?” And given “can i”, we can pick one of the two possible responses. In this version, a response that ends with “*” just parrots the rest of the input, but at this point, Eliza would print: “Do you want to be able to turn you off now?” which isn't correct. We need to correct the pronouns. Again, some LPeg code to do just that:

conjugate = Cs((
                   P" are"  / " am "
                 + P" were" / " was "
                 + P" you"  / " me "
                 + P" your" / " my "
                 + P" I've" / " you've "
                 + P" I'm"  / " you're "
                 + P" me"   / " you "
                 + C(1)

rest = conjugate:match(rest)

and now we get: “Do you want to be able to turn me off now?” which is correct.

LPeg makes Eliza much easier to write and modify. Even if you can't understand the code itself, it's easy to see what needs to be added to do the conversion. Compare that with the original version I'm using as a reference:

380 REM ******************************************
410 REM ******************************************
430 C$=" "+RIGHT$(I$,LEN(I$)-LEN(F$)-L+1)+" "
440 FOR X=1 TO N2/2
460 FOR L=1 TO LEN(C$)
495 L = L+LEN(WORDOUT$(X))
500 GOTO 540
540 NEXT L
550 NEXT X
555 IF MID$(C$,2,1)=" "THEN C$=RIGHT$(C$,LEN(C$)-1):REM ONLY 1 SPACE
556 FOR L=1 TO LEN(C$)
557 IF MID$(C$,L,1)="!" THEN C$=LEFT$(C$,L-1)+RIGHT$(C$,LEN(C$)-L):GOTO 557
558 NEXT L

Just a bit more work to get some corner cases worked out and then comes the hard part of getting Eliza to talk to Racter.

Obligatory Picture

[“I am NOT a number, I am … a Q-CODE!”]

Obligatory Contact Info

Obligatory Feeds

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site:, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2024 by Sean Conner. All Rights Reserved.