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) end end 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) )^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 ****************************************** 390 REM **TAKE PART OF STRING AND CONJUGATE IT**** 400 REM **USING THE LIST OF STRINGS TO BE SWAPPED* 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$) 470 IF L+LEN(WORDIN$(X))>LEN(C$) THEN 510 480 IF MID$(C$,L,LEN(WORDIN$(X)))<>WORDIN$(X) THEN 510 490 C$=LEFT$(C$,L-1)+WORDOUT$(X)+RIGHT$(C$,LEN(C$)-L-LEN(WORDIN$(X))+1) 495 L = L+LEN(WORDOUT$(X)) 500 GOTO 540 510 IF L+LEN(WORDOUT$(X))>LEN(C$)THEN 540 520 IF MID$(C$,L,LEN(WORDOUT$(X)))<>WORDOUT$(X) THEN 540 530 C$=LEFT$(C$,L-1)+WORDIN$(X)+RIGHT$(C$,LEN(C$)-L-LEN(WORDOUT$(X))+1) 535 L=L+LEN(WORDIN$(X)) 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.