Got eliza working
authorNeil Smith <neil.git@njae.me.uk>
Mon, 23 Jan 2017 12:01:51 +0000 (12:01 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 23 Jan 2017 12:01:51 +0000 (12:01 +0000)
SIGNED.md [deleted file]
eliza.ipynb
eliza.py [new file with mode: 0644]
read-yaml-rules.ipynb [deleted file]

diff --git a/SIGNED.md b/SIGNED.md
deleted file mode 100644 (file)
index 1d1cd93..0000000
--- a/SIGNED.md
+++ /dev/null
@@ -1,76 +0,0 @@
-##### Signed by https://keybase.io/neilnjae
-```
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v2
-
-iQIcBAABCAAGBQJWjqGHAAoJEJPB2e07PgbqD0kP/REkohoCWKhscZzHwfgQFv7d
-V1f4UeeUCaJaajG+jFkaBxOFcCnuvmihei0iUYe8uX69MWB7QHI4ogK9iKjxXnvH
-LLw2FCR2nCwwJkzU4A2S78cr0ytmT8pzkc+iI/E30xhwnVaYv1QOVR1msZL+VO4L
-BxM7icHqNvQJAuLy+en5bMacvUbcFDIPsogHPAGw8Ot9RtbCXndeCDXKuBLFovQn
-R1mIVtJd/05ZnZk2JUmrknrW3t4aO9VYTocDLTFoC1SjyIVYRBP43DsFE5MQgOhh
-sytxhod6cPI9jPybQY8Carhh0tTTBd4jHVdthroziKgG9aiU9bIBmMC4L2lfzLHz
-qO7seltMHdI7SYyJxwmz9xSd5dHKW5NvPPKxzYVuPVc83yEj8GDjl6M5OxKUoyEH
-XKYfIWm6itGvCo9YtbvrtlwEVD5sBdh5C0wM4RuGBHJBW3CSdbc904mmkjeiWB8q
-QjIRrC4OHJlyk+BUO4u8QvFld8QmyVaVdLsjL3KtSM1UFIaS5cBA/Nm2PwdUuyvt
-0UUJuFeMI+KljH62g7LU17UL2zV19+/hXG1amKkwvZIBXYXUR2fFRqxF3bjl767s
-wR/cRkCQjkaHcZAifKt8f4rndCfmp+cPPVXcxyofUXVzXCo6dM3rQBluT7tAHLJ6
-8Ykhk55Q3in5HqSbK/Lp
-=7jJ5
------END PGP SIGNATURE-----
-
-```
-
-<!-- END SIGNATURES -->
-
-### Begin signed statement 
-
-#### Expect
-
-```
-size     exec  file                     contents                                                                                                                         
-               ./                                                                                                                                                        
-384              .gitignore             a93de2ae5c2a47a38599751d1f914566569dfa09dd1778e207117db6c71421dd                                                                 
-10642            eliza.scm              6583dab3d3a738f7c30ecc466173a87493d8688a38e3a6d3119dcabccd19fb70|05535b9b3ecfd4ed59930bac2aecf07187d0b17598cd5631449c25f33d4a90bc
-1219320          p36-weizenabaum.pdf    3b18ed3ebf7c28670c215709e778c9b339055fb225b0286796bd0767197be041|2193a46558e12df2a2935889418defe494925feea31711675393d97b08cf0950
-8951             read-yaml-rules.ipynb  98abea4ef566c47ac645d82d7ee66bd9391340620d192a036ef493d144a25c70                                                                 
-5684             rules.yaml             33b053eafd822384a60b782859a9c056bb558a81f4e85b4e7d9db87521a37e57                                                                 
-348              rules2.yaml~           71753ea7113018d1409c29990714b39e3601bb0280e05420c5f85aa88aea150b                                                                 
-4804             rules3.yaml~           81b9f4401883b61ffaef2228ddd55fdac5adc76281d5f34d9edd57ed3688fa10                                                                 
-```
-
-#### Ignore
-
-```
-/SIGNED.md
-```
-
-#### Presets
-
-```
-git  # ignore .git and anything as described by .gitignore files
-```
-
-<!-- summarize version = 0.0.9 -->
-
-### End signed statement
-
-<hr>
-
-#### Notes
-
-With keybase you can sign any directory's contents, whether it's a git repo,
-source code distribution, or a personal documents folder. It aims to replace the drudgery of:
-
-  1. comparing a zipped file to a detached statement
-  2. downloading a public key
-  3. confirming it is in fact the author's by reviewing public statements they've made, using it
-
-All in one simple command:
-
-```bash
-keybase dir verify
-```
-
-There are lots of options, including assertions for automating your checks.
-
-For more info, check out https://keybase.io/docs/command_line/code_signing
\ No newline at end of file
index fe7c19949bd191483afe0d141ca493e00d5e46f2..7a6da3ca54e4b4f1c11590d05acedee803385588 100644 (file)
@@ -2,18 +2,31 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 100,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "import yaml"
+    "import yaml\n",
+    "import collections\n",
+    "import random"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 84,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "Match = collections.namedtuple('Match', 'text, rule, bindings')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 169,
    "metadata": {
     "collapsed": false
    },
     {
      "data": {
       "text/plain": [
-       "[{'pattern': '?X hello ?Y',\n",
-       "  'responses': ['how do you do.  please state your problem']},\n",
-       " {'pattern': '?X computer ?Y',\n",
-       "  'responses': ['do computers worry you',\n",
-       "   'what do you think about machines',\n",
-       "   'why do you mention computers',\n",
-       "   'what do you think machines have to do with your problem']},\n",
-       " {'pattern': '?X name ?Y', 'responses': ['i am not interested in names']},\n",
-       " {'pattern': '?X sorry ?Y',\n",
-       "  'responses': [\"please don't apologize\",\n",
-       "   'apologies are not necessary',\n",
-       "   'what feelings do you have when you apologize']},\n",
-       " {'pattern': '?X i remember ?Y',\n",
-       "  'responses': ['do you often think of ?Y',\n",
-       "   'does thinking of ?Y bring anything else to mind',\n",
-       "   'what else do you remember?',\n",
-       "   'why do you recall ?Y right now',\n",
-       "   'what in this present situation reminds you of ?Y',\n",
-       "   'what is the connection between me and ?Y']},\n",
-       " {'pattern': '?X do you remember ?Y',\n",
-       "  'responses': ['did you think i would forget ?Y',\n",
-       "   'why do you think i should recall ?Y',\n",
-       "   'what about ?Y',\n",
-       "   'you mentioned ?Y']},\n",
-       " {'pattern': '?X if ?Y',\n",
-       "  'responses': ['do you really think it is likely that ?Y',\n",
-       "   'do you wish that ?Y',\n",
-       "   'what do you think about ?Y',\n",
-       "   'really -- if ?Y']},\n",
-       " {'pattern': '?X i dreamt ?Y',\n",
-       "  'responses': ['really -- ?Y',\n",
-       "   'have you ever fantasized ?Y while you were awake',\n",
-       "   'have you dreamt ?Y before']},\n",
-       " {'pattern': '?X i dreamed ?Y',\n",
-       "  'responses': ['really -- ?Y',\n",
-       "   'have you ever fantasized ?Y while you were awake',\n",
-       "   'have you dreamed ?Y before']},\n",
-       " {'pattern': '?X dream ?Y',\n",
-       "  'responses': ['what does this dream suggest to you',\n",
-       "   'do you dream often',\n",
-       "   'what persons appear in your dreams',\n",
-       "   \"don't you believe that dream has to do with your problem\"]},\n",
-       " {'pattern': '?X my mother ?Y',\n",
-       "  'responses': ['who else is in your family ?Y',\n",
-       "   'tell me more about your family']},\n",
-       " {'pattern': '?X my father ?Y',\n",
-       "  'responses': ['your father',\n",
-       "   'does he influence you strongly',\n",
-       "   'what else comes to mind when you think of your father']},\n",
-       " {'pattern': '?X i want ?Y',\n",
-       "  'responses': ['what would it mean if you got ?Y',\n",
-       "   'why do you want ?Y',\n",
-       "   'suppose you got ?Y soon']},\n",
-       " {'pattern': '?X i am glad ?Y',\n",
-       "  'responses': ['how have i helped you to be ?Y',\n",
-       "   'what makes you happy just now',\n",
-       "   'can you explain why you are suddenly ?Y']},\n",
-       " {'pattern': '?X i am happy ?Y',\n",
-       "  'responses': ['how have i helped you to be ?Y',\n",
-       "   'what makes you glad just now',\n",
-       "   'can you explain why you are suddenly ?Y']},\n",
-       " {'pattern': '?X i am sad ?Y',\n",
-       "  'responses': ['i am sorry to hear you are depressed',\n",
-       "   \"i'm sure it's not pleasant to be sad\"]},\n",
-       " {'pattern': '?X i am unhappy ?Y',\n",
-       "  'responses': ['i am sorry to hear you are depressed',\n",
-       "   \"i'm sure it's not pleasant to be unhappy\"]},\n",
-       " {'pattern': '?X are like ?Y',\n",
-       "  'responses': ['what resemblence do you see between ?X and ?Y']},\n",
-       " {'pattern': '?X is like ?Y',\n",
-       "  'responses': ['in what way is it that ?X is like ?Y',\n",
-       "   'what resemblence do you see',\n",
-       "   'could there really be some connection',\n",
-       "   'how']},\n",
-       " {'pattern': '?X alike ?Y',\n",
-       "  'responses': ['in what way', 'what similarities are there']},\n",
-       " {'pattern': '?X same ?Y', 'responses': ['what other connections do you see']},\n",
-       " {'pattern': '?X i was ?Y',\n",
-       "  'responses': ['were you really',\n",
-       "   'perhaps i already knew you were ?Y',\n",
-       "   'why do you tell me you were ?Y now']},\n",
-       " {'pattern': '?X was i ?Y',\n",
-       "  'responses': ['what if you were ?Y',\n",
-       "   'do you think you were ?Y',\n",
-       "   'what would it mean if you were ?Y']},\n",
-       " {'pattern': '?X i am ?Y',\n",
-       "  'responses': ['in what way are you ?Y', 'do you want to be ?Y']},\n",
-       " {'pattern': '?X am i ?Y',\n",
-       "  'responses': ['do you believe you are ?Y',\n",
-       "   'would you want to be ?Y',\n",
-       "   'you wish i would tell you you are ?Y',\n",
-       "   'what would it mean if you were ?Y']},\n",
-       " {'pattern': '?X am ?Y',\n",
-       "  'responses': ['why do you say \"am\"', \"i don't understand that\"]},\n",
-       " {'pattern': '?X are you ?Y',\n",
-       "  'responses': ['why are you interested in whether i am ?Y or not',\n",
-       "   \"would you prefer it if i weren't ?Y\",\n",
-       "   'perhaps i am ?Y in your fantasies']},\n",
-       " {'pattern': '?X you are ?Y', 'responses': ['what makes you think i am ?Y']},\n",
-       " {'pattern': '?X because ?Y',\n",
-       "  'responses': ['is that the real reason',\n",
-       "   'what other reason might there be',\n",
-       "   'does that reason seem to explain anything else']},\n",
-       " {'pattern': '?X were you ?Y',\n",
-       "  'responses': ['perhaps i was ?Y',\n",
-       "   'what do you think',\n",
-       "   'what if i had been ?Y']},\n",
-       " {'pattern': \"?X i can't ?Y\",\n",
-       "  'responses': ['maybe you could ?Y now', 'what if you could ?Y']},\n",
-       " {'pattern': '?X i feel ?Y', 'responses': ['do you often feel ?Y']},\n",
-       " {'pattern': '?X i felt ?Y', 'responses': ['what other feelings do you have']},\n",
-       " {'pattern': '?X i ?Y you ?Z',\n",
-       "  'responses': ['perhaps in your fantasies we ?Y each other']},\n",
-       " {'pattern': \"?X why don't you ?Y\",\n",
-       "  'responses': ['should you ?Y yourself',\n",
-       "   \"do you believe i don't ?Y\",\n",
-       "   'perhaps i will ?Y in good time']},\n",
-       " {'pattern': '?X yes ?Y',\n",
-       "  'responses': ['you seem quite positive', 'you are sure', 'i understand']},\n",
-       " {'pattern': '?X no ?Y',\n",
-       "  'responses': ['why not',\n",
-       "   'you are being a bit negative',\n",
-       "   'are you saying \"no\" just to be negative']},\n",
-       " {'pattern': '?X someone ?Y', 'responses': ['can you be more specific']},\n",
-       " {'pattern': '?X everyone ?Y',\n",
-       "  'responses': ['surely not everyone',\n",
-       "   'can you think of anyone in particular',\n",
-       "   'who for example',\n",
-       "   'you are thinking of a special person']},\n",
-       " {'pattern': '?X always ?Y',\n",
-       "  'responses': ['can you think of a specific example',\n",
-       "   'when',\n",
-       "   'what incident are you thinking of',\n",
-       "   'really -- always']},\n",
-       " {'pattern': '?X what ?Y',\n",
-       "  'responses': ['why do you ask',\n",
-       "   'does that question interest you',\n",
-       "   'what is it you really want to know',\n",
-       "   'what do you think',\n",
-       "   'what comes to your mind when you ask that']},\n",
-       " {'pattern': '?X perhaps ?Y', 'responses': ['you do not seem quite certain']},\n",
-       " {'pattern': '?X are ?Y',\n",
-       "  'responses': ['do you think they might not be ?Y', 'possibly they are ?Y']},\n",
-       " {'pattern': '?X',\n",
-       "  'responses': ['very interesting',\n",
-       "   'i am not sure i understand you fully',\n",
-       "   'what does that suggest to you',\n",
-       "   'please continue',\n",
-       "   'go on',\n",
-       "   'do you feel strongly about discussing such things']}]"
+       "[{'pattern': ['?X', 'hello', '?Y'],\n",
+       "  'responses': [['how',\n",
+       "    'do',\n",
+       "    'you',\n",
+       "    'do.',\n",
+       "    'please',\n",
+       "    'state',\n",
+       "    'your',\n",
+       "    'problem']]},\n",
+       " {'pattern': ['?X', 'computer', '?Y'],\n",
+       "  'responses': [['do', 'computers', 'worry', 'you'],\n",
+       "   ['what', 'do', 'you', 'think', 'about', 'machines'],\n",
+       "   ['why', 'do', 'you', 'mention', 'computers'],\n",
+       "   ['what',\n",
+       "    'do',\n",
+       "    'you',\n",
+       "    'think',\n",
+       "    'machines',\n",
+       "    'have',\n",
+       "    'to',\n",
+       "    'do',\n",
+       "    'with',\n",
+       "    'your',\n",
+       "    'problem']]},\n",
+       " {'pattern': ['?X', 'name', '?Y'],\n",
+       "  'responses': [['i', 'am', 'not', 'interested', 'in', 'names']]},\n",
+       " {'pattern': ['?X', 'sorry', '?Y'],\n",
+       "  'responses': [['please', \"don't\", 'apologize'],\n",
+       "   ['apologies', 'are', 'not', 'necessary'],\n",
+       "   ['what', 'feelings', 'do', 'you', 'have', 'when', 'you', 'apologize']]},\n",
+       " {'pattern': ['?X', 'i', 'remember', '?Y'],\n",
+       "  'responses': [['do', 'you', 'often', 'think', 'of', '?Y'],\n",
+       "   ['does', 'thinking', 'of', '?Y', 'bring', 'anything', 'else', 'to', 'mind'],\n",
+       "   ['what', 'else', 'do', 'you', 'remember?'],\n",
+       "   ['why', 'do', 'you', 'recall', '?Y', 'right', 'now'],\n",
+       "   ['what',\n",
+       "    'in',\n",
+       "    'this',\n",
+       "    'present',\n",
+       "    'situation',\n",
+       "    'reminds',\n",
+       "    'you',\n",
+       "    'of',\n",
+       "    '?Y'],\n",
+       "   ['what', 'is', 'the', 'connection', 'between', 'me', 'and', '?Y']]},\n",
+       " {'pattern': ['?X', 'do', 'you', 'remember', '?Y'],\n",
+       "  'responses': [['did', 'you', 'think', 'i', 'would', 'forget', '?Y'],\n",
+       "   ['why', 'do', 'you', 'think', 'i', 'should', 'recall', '?Y'],\n",
+       "   ['what', 'about', '?Y'],\n",
+       "   ['you', 'mentioned', '?Y']]},\n",
+       " {'pattern': ['?X', 'if', '?Y'],\n",
+       "  'responses': [['do',\n",
+       "    'you',\n",
+       "    'really',\n",
+       "    'think',\n",
+       "    'it',\n",
+       "    'is',\n",
+       "    'likely',\n",
+       "    'that',\n",
+       "    '?Y'],\n",
+       "   ['do', 'you', 'wish', 'that', '?Y'],\n",
+       "   ['what', 'do', 'you', 'think', 'about', '?Y'],\n",
+       "   ['really', '--', 'if', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'dreamt', '?Y'],\n",
+       "  'responses': [['really', '--', '?Y'],\n",
+       "   ['have',\n",
+       "    'you',\n",
+       "    'ever',\n",
+       "    'fantasized',\n",
+       "    '?Y',\n",
+       "    'while',\n",
+       "    'you',\n",
+       "    'were',\n",
+       "    'awake'],\n",
+       "   ['have', 'you', 'dreamt', '?Y', 'before']]},\n",
+       " {'pattern': ['?X', 'i', 'dreamed', '?Y'],\n",
+       "  'responses': [['really', '--', '?Y'],\n",
+       "   ['have',\n",
+       "    'you',\n",
+       "    'ever',\n",
+       "    'fantasized',\n",
+       "    '?Y',\n",
+       "    'while',\n",
+       "    'you',\n",
+       "    'were',\n",
+       "    'awake'],\n",
+       "   ['have', 'you', 'dreamed', '?Y', 'before']]},\n",
+       " {'pattern': ['?X', 'dream', '?Y'],\n",
+       "  'responses': [['what', 'does', 'this', 'dream', 'suggest', 'to', 'you'],\n",
+       "   ['do', 'you', 'dream', 'often'],\n",
+       "   ['what', 'persons', 'appear', 'in', 'your', 'dreams'],\n",
+       "   [\"don't\",\n",
+       "    'you',\n",
+       "    'believe',\n",
+       "    'that',\n",
+       "    'dream',\n",
+       "    'has',\n",
+       "    'to',\n",
+       "    'do',\n",
+       "    'with',\n",
+       "    'your',\n",
+       "    'problem']]},\n",
+       " {'pattern': ['?X', 'my', 'mother', '?Y'],\n",
+       "  'responses': [['who', 'else', 'is', 'in', 'your', 'family', '?Y'],\n",
+       "   ['tell', 'me', 'more', 'about', 'your', 'family']]},\n",
+       " {'pattern': ['?X', 'my', 'father', '?Y'],\n",
+       "  'responses': [['your', 'father'],\n",
+       "   ['does', 'he', 'influence', 'you', 'strongly'],\n",
+       "   ['what',\n",
+       "    'else',\n",
+       "    'comes',\n",
+       "    'to',\n",
+       "    'mind',\n",
+       "    'when',\n",
+       "    'you',\n",
+       "    'think',\n",
+       "    'of',\n",
+       "    'your',\n",
+       "    'father']]},\n",
+       " {'pattern': ['?X', 'i', 'want', '?Y'],\n",
+       "  'responses': [['what', 'would', 'it', 'mean', 'if', 'you', 'got', '?Y'],\n",
+       "   ['why', 'do', 'you', 'want', '?Y'],\n",
+       "   ['suppose', 'you', 'got', '?Y', 'soon']]},\n",
+       " {'pattern': ['?X', 'i', 'am', 'glad', '?Y'],\n",
+       "  'responses': [['how', 'have', 'i', 'helped', 'you', 'to', 'be', '?Y'],\n",
+       "   ['what', 'makes', 'you', 'happy', 'just', 'now'],\n",
+       "   ['can', 'you', 'explain', 'why', 'you', 'are', 'suddenly', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'am', 'happy', '?Y'],\n",
+       "  'responses': [['how', 'have', 'i', 'helped', 'you', 'to', 'be', '?Y'],\n",
+       "   ['what', 'makes', 'you', 'glad', 'just', 'now'],\n",
+       "   ['can', 'you', 'explain', 'why', 'you', 'are', 'suddenly', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'am', 'sad', '?Y'],\n",
+       "  'responses': [['i', 'am', 'sorry', 'to', 'hear', 'you', 'are', 'depressed'],\n",
+       "   [\"i'm\", 'sure', \"it's\", 'not', 'pleasant', 'to', 'be', 'sad']]},\n",
+       " {'pattern': ['?X', 'i', 'am', 'unhappy', '?Y'],\n",
+       "  'responses': [['i', 'am', 'sorry', 'to', 'hear', 'you', 'are', 'depressed'],\n",
+       "   [\"i'm\", 'sure', \"it's\", 'not', 'pleasant', 'to', 'be', 'unhappy']]},\n",
+       " {'pattern': ['?X', 'are', 'like', '?Y'],\n",
+       "  'responses': [['what',\n",
+       "    'resemblence',\n",
+       "    'do',\n",
+       "    'you',\n",
+       "    'see',\n",
+       "    'between',\n",
+       "    '?X',\n",
+       "    'and',\n",
+       "    '?Y']]},\n",
+       " {'pattern': ['?X', 'is', 'like', '?Y'],\n",
+       "  'responses': [['in',\n",
+       "    'what',\n",
+       "    'way',\n",
+       "    'is',\n",
+       "    'it',\n",
+       "    'that',\n",
+       "    '?X',\n",
+       "    'is',\n",
+       "    'like',\n",
+       "    '?Y'],\n",
+       "   ['what', 'resemblence', 'do', 'you', 'see'],\n",
+       "   ['could', 'there', 'really', 'be', 'some', 'connection'],\n",
+       "   ['how']]},\n",
+       " {'pattern': ['?X', 'alike', '?Y'],\n",
+       "  'responses': [['in', 'what', 'way'],\n",
+       "   ['what', 'similarities', 'are', 'there']]},\n",
+       " {'pattern': ['?X', 'same', '?Y'],\n",
+       "  'responses': [['what', 'other', 'connections', 'do', 'you', 'see']]},\n",
+       " {'pattern': ['?X', 'i', 'was', '?Y'],\n",
+       "  'responses': [['were', 'you', 'really'],\n",
+       "   ['perhaps', 'i', 'already', 'knew', 'you', 'were', '?Y'],\n",
+       "   ['why', 'do', 'you', 'tell', 'me', 'you', 'were', '?Y', 'now']]},\n",
+       " {'pattern': ['?X', 'was', 'i', '?Y'],\n",
+       "  'responses': [['what', 'if', 'you', 'were', '?Y'],\n",
+       "   ['do', 'you', 'think', 'you', 'were', '?Y'],\n",
+       "   ['what', 'would', 'it', 'mean', 'if', 'you', 'were', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'am', '?Y'],\n",
+       "  'responses': [['in', 'what', 'way', 'are', 'you', '?Y'],\n",
+       "   ['do', 'you', 'want', 'to', 'be', '?Y']]},\n",
+       " {'pattern': ['?X', 'am', 'i', '?Y'],\n",
+       "  'responses': [['do', 'you', 'believe', 'you', 'are', '?Y'],\n",
+       "   ['would', 'you', 'want', 'to', 'be', '?Y'],\n",
+       "   ['you', 'wish', 'i', 'would', 'tell', 'you', 'you', 'are', '?Y'],\n",
+       "   ['what', 'would', 'it', 'mean', 'if', 'you', 'were', '?Y']]},\n",
+       " {'pattern': ['?X', 'am', '?Y'],\n",
+       "  'responses': [['why', 'do', 'you', 'say', '\"am\"'],\n",
+       "   ['i', \"don't\", 'understand', 'that']]},\n",
+       " {'pattern': ['?X', 'are', 'you', '?Y'],\n",
+       "  'responses': [['why',\n",
+       "    'are',\n",
+       "    'you',\n",
+       "    'interested',\n",
+       "    'in',\n",
+       "    'whether',\n",
+       "    'i',\n",
+       "    'am',\n",
+       "    '?Y',\n",
+       "    'or',\n",
+       "    'not'],\n",
+       "   ['would', 'you', 'prefer', 'it', 'if', 'i', \"weren't\", '?Y'],\n",
+       "   ['perhaps', 'i', 'am', '?Y', 'in', 'your', 'fantasies']]},\n",
+       " {'pattern': ['?X', 'you', 'are', '?Y'],\n",
+       "  'responses': [['what', 'makes', 'you', 'think', 'i', 'am', '?Y']]},\n",
+       " {'pattern': ['?X', 'because', '?Y'],\n",
+       "  'responses': [['is', 'that', 'the', 'real', 'reason'],\n",
+       "   ['what', 'other', 'reason', 'might', 'there', 'be'],\n",
+       "   ['does', 'that', 'reason', 'seem', 'to', 'explain', 'anything', 'else']]},\n",
+       " {'pattern': ['?X', 'were', 'you', '?Y'],\n",
+       "  'responses': [['perhaps', 'i', 'was', '?Y'],\n",
+       "   ['what', 'do', 'you', 'think'],\n",
+       "   ['what', 'if', 'i', 'had', 'been', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', \"can't\", '?Y'],\n",
+       "  'responses': [['maybe', 'you', 'could', '?Y', 'now'],\n",
+       "   ['what', 'if', 'you', 'could', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'feel', '?Y'],\n",
+       "  'responses': [['do', 'you', 'often', 'feel', '?Y']]},\n",
+       " {'pattern': ['?X', 'i', 'felt', '?Y'],\n",
+       "  'responses': [['what', 'other', 'feelings', 'do', 'you', 'have']]},\n",
+       " {'pattern': ['?X', 'i', '?Y', 'you', '?Z'],\n",
+       "  'responses': [['perhaps',\n",
+       "    'in',\n",
+       "    'your',\n",
+       "    'fantasies',\n",
+       "    'we',\n",
+       "    '?Y',\n",
+       "    'each',\n",
+       "    'other']]},\n",
+       " {'pattern': ['?X', 'why', \"don't\", 'you', '?Y'],\n",
+       "  'responses': [['should', 'you', '?Y', 'yourself'],\n",
+       "   ['do', 'you', 'believe', 'i', \"don't\", '?Y'],\n",
+       "   ['perhaps', 'i', 'will', '?Y', 'in', 'good', 'time']]},\n",
+       " {'pattern': ['?X', 'yes', '?Y'],\n",
+       "  'responses': [['you', 'seem', 'quite', 'positive'],\n",
+       "   ['you', 'are', 'sure'],\n",
+       "   ['i', 'understand']]},\n",
+       " {'pattern': ['?X', 'no', '?Y'],\n",
+       "  'responses': [['why', 'not'],\n",
+       "   ['you', 'are', 'being', 'a', 'bit', 'negative'],\n",
+       "   ['are', 'you', 'saying', '\"no\"', 'just', 'to', 'be', 'negative']]},\n",
+       " {'pattern': ['?X', 'someone', '?Y'],\n",
+       "  'responses': [['can', 'you', 'be', 'more', 'specific']]},\n",
+       " {'pattern': ['?X', 'everyone', '?Y'],\n",
+       "  'responses': [['surely', 'not', 'everyone'],\n",
+       "   ['can', 'you', 'think', 'of', 'anyone', 'in', 'particular'],\n",
+       "   ['who', 'for', 'example'],\n",
+       "   ['you', 'are', 'thinking', 'of', 'a', 'special', 'person']]},\n",
+       " {'pattern': ['?X', 'always', '?Y'],\n",
+       "  'responses': [['can', 'you', 'think', 'of', 'a', 'specific', 'example'],\n",
+       "   ['when'],\n",
+       "   ['what', 'incident', 'are', 'you', 'thinking', 'of'],\n",
+       "   ['really', '--', 'always']]},\n",
+       " {'pattern': ['?X', 'what', '?Y'],\n",
+       "  'responses': [['why', 'do', 'you', 'ask'],\n",
+       "   ['does', 'that', 'question', 'interest', 'you'],\n",
+       "   ['what', 'is', 'it', 'you', 'really', 'want', 'to', 'know'],\n",
+       "   ['what', 'do', 'you', 'think'],\n",
+       "   ['what', 'comes', 'to', 'your', 'mind', 'when', 'you', 'ask', 'that']]},\n",
+       " {'pattern': ['?X', 'perhaps', '?Y'],\n",
+       "  'responses': [['you', 'do', 'not', 'seem', 'quite', 'certain']]},\n",
+       " {'pattern': ['?X', 'are', '?Y'],\n",
+       "  'responses': [['do', 'you', 'think', 'they', 'might', 'not', 'be', '?Y'],\n",
+       "   ['possibly', 'they', 'are', '?Y']]},\n",
+       " {'pattern': ['?X'],\n",
+       "  'responses': [['very', 'interesting'],\n",
+       "   ['i', 'am', 'not', 'sure', 'i', 'understand', 'you', 'fully'],\n",
+       "   ['what', 'does', 'that', 'suggest', 'to', 'you'],\n",
+       "   ['please', 'continue'],\n",
+       "   ['go', 'on'],\n",
+       "   ['do',\n",
+       "    'you',\n",
+       "    'feel',\n",
+       "    'strongly',\n",
+       "    'about',\n",
+       "    'discussing',\n",
+       "    'such',\n",
+       "    'things']]}]"
       ]
      },
-     "execution_count": 2,
+     "execution_count": 169,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "with open('rules.yaml') as f:\n",
-    "    rules = yaml.load(f)\n",
-    "rules"
+    "def read_rules(rules_file):\n",
+    "    with open(rules_file) as f:\n",
+    "        rules = [{'pattern': r['pattern'].split(),\n",
+    "                 'responses': [t.split() for t in r['responses']]}\n",
+    "            for r in yaml.load(f)]\n",
+    "    return rules\n",
+    "\n",
+    "all_rules = read_rules('rules.yaml')\n",
+    "all_rules"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 102,
    "metadata": {
-    "collapsed": false
+    "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def match(text, rule, bindings=None):\n",
-    "    if text == [] and rule == []:\n",
-    "        return bindings\n",
-    "    elif text != [] and rule != []:\n",
-    "        if bindings == None:\n",
-    "            bindings = {}\n",
-    "        remaining_text, remaining_rule, new_bindings = match_first(text, rule, bindings)\n",
-    "        return match(remaining_text, remaining_rule, new_bindings)\n",
-    "    else:\n",
-    "        return None"
+    "def match(text, rule):\n",
+    "    return all_matches([Match(text, rule, {})])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 240,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def all_matches(matches):\n",
+    "    successes = []\n",
+    "    while matches:\n",
+    "        # print(matches, successes)\n",
+    "        current = matches[0]\n",
+    "        new_matches = []\n",
+    "        if successful_match(current):\n",
+    "            successes += [current.bindings]\n",
+    "        elif current.rule:\n",
+    "            new_matches = match_item(current.text, current.rule, current.bindings)\n",
+    "        matches = matches[1:] + new_matches\n",
+    "    return successes"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 22,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 23,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def match_first(text, rule, bindings):\n",
-    "    if not is_var(rule[0]):\n",
-    "        if text[0] == rule[0]:\n",
-    "            return text[1:], rule[1:], bindings\n",
+    "def successful_match(match):\n",
+    "    return match.text == [] and match.rule == []"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def splits(item):\n",
+    "    return [(item[:i], item[i:]) for i in range(len(item)+1)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('', 'harry'),\n",
+       " ('h', 'arry'),\n",
+       " ('ha', 'rry'),\n",
+       " ('har', 'ry'),\n",
+       " ('harr', 'y'),\n",
+       " ('harry', '')]"
+      ]
+     },
+     "execution_count": 25,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "splits(\"harry\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 236,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def match_item(text, rule, bindings):\n",
+    "    r0 = rule[0]\n",
+    "    if is_var(r0):\n",
+    "        if r0 in bindings:\n",
+    "            # already seen this variable\n",
+    "            if text[:len(bindings[r0])] == bindings[r0]:\n",
+    "                return [Match(text[(len(bindings[r0])):], rule[1:], bindings)]\n",
+    "            else:\n",
+    "                return []\n",
+    "        else:\n",
+    "            # not seen this variable yet\n",
+    "            matches = []\n",
+    "            for pre, suf in splits(text):\n",
+    "                new_bindings = bindings.copy()\n",
+    "                new_bindings[r0] = pre\n",
+    "                matches += [Match(suf, rule[1:], new_bindings)]\n",
+    "            return matches\n",
+    "    elif text and text[0] == r0:\n",
+    "        return [Match(text[1:], rule[1:], bindings)]\n",
     "    else:\n",
-    "        # Unfinished\n",
-    "        pass"
+    "        return []\n"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 213,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['fred'], '?Y': ['jane']}]"
+      ]
+     },
+     "execution_count": 213,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('fred hello jane'.split(), '?X hello ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 214,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': ['jane']}]"
+      ]
+     },
+     "execution_count": 214,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('hello jane'.split(), '?X hello ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 215,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['fred'], '?Y': []}]"
+      ]
+     },
+     "execution_count": 215,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('fred hello'.split(), '?X hello ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 216,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': []}]"
+      ]
+     },
+     "execution_count": 216,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('hello'.split(), '?X hello ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 217,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 217,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('fred jane'.split(), '?X hello ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 218,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['fred']}]"
+      ]
+     },
+     "execution_count": 218,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('fred hello'.split(), '?X hello'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 219,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 219,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('hello fred'.split(), '?X hello'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 220,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['yes'], '?Y': ['rain']}]"
+      ]
+     },
+     "execution_count": 220,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('yes i remember rain'.split(), '?X i remember ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 221,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['no'], '?Y': ['rain']}]"
+      ]
+     },
+     "execution_count": 221,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match('no i remember rain'.split(), '?X i remember ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 222,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 222,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"no remember rain\".split(), '?X i remember ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 223,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': ['rain']}]"
+      ]
+     },
+     "execution_count": 223,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"i remember rain\".split(), '?X i remember ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 241,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': ['hello', 'there', 'hello']},\n",
+       " {'?X': ['hello'], '?Y': ['there']}]"
+      ]
+     },
+     "execution_count": 241,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"hello there hello\".split(), '?X ?Y ?X'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 242,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': ['hello']}]"
+      ]
+     },
+     "execution_count": 242,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"hello there hello\".split(), '?X there ?X'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 244,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': ['hello', 'hello', 'hello']},\n",
+       " {'?X': ['hello'], '?Y': ['hello', 'hello']},\n",
+       " {'?X': ['hello', 'hello'], '?Y': ['hello']},\n",
+       " {'?X': ['hello', 'hello', 'hello'], '?Y': []}]"
+      ]
+     },
+     "execution_count": 244,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"hello hello hello\".split(), '?X ?Y'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 245,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'?X': [], '?Y': ['hello', 'hello', 'hello']},\n",
+       " {'?X': ['hello'], '?Y': ['hello']}]"
+      ]
+     },
+     "execution_count": 245,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "match(\"hello hello hello\".split(), '?X ?Y ?X'.split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 196,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def candidate_rules(rules, comment):\n",
+    "    return [(rule, bindings) \n",
+    "            for rule in rules \n",
+    "            for bindings in match(comment, rule['pattern'])]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 197,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[({'pattern': ['?X', 'i', 'remember', '?Y'],\n",
+       "   'responses': [['do', 'you', 'often', 'think', 'of', '?Y'],\n",
+       "    ['does',\n",
+       "     'thinking',\n",
+       "     'of',\n",
+       "     '?Y',\n",
+       "     'bring',\n",
+       "     'anything',\n",
+       "     'else',\n",
+       "     'to',\n",
+       "     'mind'],\n",
+       "    ['what', 'else', 'do', 'you', 'remember?'],\n",
+       "    ['why', 'do', 'you', 'recall', '?Y', 'right', 'now'],\n",
+       "    ['what',\n",
+       "     'in',\n",
+       "     'this',\n",
+       "     'present',\n",
+       "     'situation',\n",
+       "     'reminds',\n",
+       "     'you',\n",
+       "     'of',\n",
+       "     '?Y'],\n",
+       "    ['what', 'is', 'the', 'connection', 'between', 'me', 'and', '?Y']]},\n",
+       "  {'?X': [], '?Y': ['rain']}),\n",
+       " ({'pattern': ['?X'],\n",
+       "   'responses': [['very', 'interesting'],\n",
+       "    ['i', 'am', 'not', 'sure', 'i', 'understand', 'you', 'fully'],\n",
+       "    ['what', 'does', 'that', 'suggest', 'to', 'you'],\n",
+       "    ['please', 'continue'],\n",
+       "    ['go', 'on'],\n",
+       "    ['do',\n",
+       "     'you',\n",
+       "     'feel',\n",
+       "     'strongly',\n",
+       "     'about',\n",
+       "     'discussing',\n",
+       "     'such',\n",
+       "     'things']]},\n",
+       "  {'?X': ['i', 'remember', 'rain']})]"
+      ]
+     },
+     "execution_count": 197,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "candidate_rules(all_rules, \"i remember rain\".split())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 198,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def fill(response, bindings):\n",
+    "    filled_response = []\n",
+    "    for w in response:\n",
+    "        if is_var(w):\n",
+    "            if w in bindings:\n",
+    "                filled_response += bindings[w]\n",
+    "            else:\n",
+    "                filled_response += ['MISSING']\n",
+    "        else:\n",
+    "            filled_response += [w]\n",
+    "    return filled_response"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 202,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'do you often think of rain'"
+      ]
+     },
+     "execution_count": 202,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bs = match('yes i remember rain'.split(), '?X i remember ?Y'.split())[0]\n",
+    "fr = fill(['do', 'you', 'often', 'think', 'of', '?Y'], bs)\n",
+    "' '.join(fr)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 165,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "pronoun_swaps = {\n",
+    "    'i': 'you',\n",
+    "    'me': 'you',\n",
+    "    'my': 'your',\n",
+    "    'mine': 'yours',\n",
+    "    'am': 'are'\n",
+    "}\n",
+    "\n",
+    "def pronoun_person_swap(bindings):\n",
+    "    def swapped(words):\n",
+    "        sw = []\n",
+    "        for w in words:\n",
+    "            if w in pronoun_swaps:\n",
+    "                sw += [pronoun_swaps[w]]\n",
+    "            else:\n",
+    "                sw += [w]\n",
+    "        return sw\n",
+    "    \n",
+    "    return {var: swapped(bindings[var]) for var in bindings}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 166,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'?X': ['your', 'father'], '?Y': ['you', 'are', 'your', 'brother', 'keeper']}"
+      ]
+     },
+     "execution_count": 166,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pronoun_person_swap({'?X': ['my', 'father'], '?Y': 'i am my brother keeper'.split()})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def respond(rule, bindings):\n",
+    "    return fill(random.choice(rule['responses']), bindings)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 231,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['why', 'do', 'you', 'recall', 'rain', 'right', 'now']"
+      ]
+     },
+     "execution_count": 231,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "r0, b0 = candidate_rules(all_rules, \"i remember rain\".split())[0]\n",
+    "respond(r0, b0)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 167,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def eliza_loop():\n",
+    "    print(\"Hello. I'm Eliza. What seems to be the problem?\")\n",
+    "    while True:\n",
+    "        c = input(\"> \")\n",
+    "        if c.strip() in 'quit halt exit stop'.split(): break\n",
+    "        comment = c.split()\n",
+    "        rule, bindings = candidate_rules(all_rules, comment)[0]\n",
+    "        swapped_bindings = pronoun_person_swap(bindings)\n",
+    "        print(' '.join(respond(rule, swapped_bindings)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 168,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Hello. I'm Eliza. What seems to be the problem?\n",
+      "> this is weird\n",
+      "i am not sure i understand you fully\n",
+      "> i love my father\n",
+      "your father\n",
+      "> yes, my father\n",
+      "what else comes to mind when you think of your father\n",
+      "> i remember my father\n",
+      "does thinking of your father bring anything else to mind\n",
+      "> i remember i am a saint\n",
+      "does thinking of you are a saint bring anything else to mind\n",
+      "> saints are always happy\n",
+      "really -- always\n",
+      "> yes, always\n",
+      "can you think of a specific example\n",
+      "> saint george was happy when he killed the dragon\n",
+      "go on\n",
+      "> i don't think you understand me\n",
+      "perhaps in your fantasies we don't think each other\n",
+      "> i aardvark you understand me\n",
+      "perhaps in your fantasies we aardvark each other\n",
+      "> exit\n"
+     ]
+    }
+   ],
+   "source": [
+    "eliza_loop()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.4.3+"
+   "version": "3.5.2+"
   }
  },
  "nbformat": 4,
diff --git a/eliza.py b/eliza.py
new file mode 100644 (file)
index 0000000..2a3e04c
--- /dev/null
+++ b/eliza.py
@@ -0,0 +1,125 @@
+
+# coding: utf-8
+import yaml
+import collections
+import random
+
+Match = collections.namedtuple('Match', 'text, rule, bindings')
+
+pronoun_swaps = {
+    'i': 'you',
+    'me': 'you',
+    'my': 'your',
+    'mine': 'yours',
+    'am': 'are'
+}
+
+def read_rules(rules_file):
+    with open(rules_file) as f:
+        rules = [{'pattern': r['pattern'].split(),
+                 'responses': [t.split() for t in r['responses']]}
+            for r in yaml.load(f)]
+    return rules
+
+def is_var(word):
+    return word[0] == '?'
+
+
+def splits(item):
+    return [(item[:i], item[i:]) for i in range(len(item)+1)]
+
+def match(text, rule):
+    return all_matches([Match(text, rule, {})])
+
+def all_matches(matches):
+    successes = []
+    while matches:
+        # print(matches, successes)
+        current = matches[0]
+        new_matches = []
+        if successful_match(current):
+            successes += [current.bindings]
+        elif current.rule:
+            new_matches = match_item(current.text, current.rule, current.bindings)
+        matches = matches[1:] + new_matches
+    return successes
+
+def successful_match(match):
+    return match.text == [] and match.rule == []
+
+def match_item(text, rule, bindings):
+    r0 = rule[0]
+    if is_var(r0):
+        if r0 in bindings:
+            # already seen this variable
+            if text[:len(bindings[r0])] == bindings[r0]:
+                return [Match(text[(len(bindings[r0])):], rule[1:], bindings)]
+            else:
+                return []
+        else:
+            # not seen this variable yet
+            matches = []
+            for pre, suf in splits(text):
+                new_bindings = bindings.copy()
+                new_bindings[r0] = pre
+                matches += [Match(suf, rule[1:], new_bindings)]
+            return matches
+    elif text and text[0] == r0:
+        return [Match(text[1:], rule[1:], bindings)]
+    else:
+        return []
+
+def candidate_rules(rules, comment):
+    return [(rule, bindings) 
+            for rule in rules 
+            for bindings in match(comment, rule['pattern'])]
+
+
+def fill(response, bindings):
+    filled_response = []
+    for w in response:
+        if is_var(w):
+            if w in bindings:
+                filled_response += bindings[w]
+            else:
+                filled_response += ['MISSING']
+        else:
+            filled_response += [w]
+    return filled_response
+
+
+def pronoun_person_swap(bindings):
+    def swapped(words):
+        sw = []
+        for w in words:
+            if w in pronoun_swaps:
+                sw += [pronoun_swaps[w]]
+            else:
+                sw += [w]
+        return sw
+    
+    return {var: swapped(bindings[var]) for var in bindings}
+
+def respond(rule, bindings):
+    return fill(random.choice(rule['responses']), bindings)
+
+
+def eliza_loop(rules):
+    print("Hello. I'm Eliza. What seems to be the problem?")
+    while True:
+        c = input("> ")
+        if c.strip() in 'quit halt exit stop'.split(): break
+        comment = c.split()
+        rule, bindings = candidate_rules(rules, comment)[0]
+        swapped_bindings = pronoun_person_swap(bindings)
+        print(' '.join(respond(rule, swapped_bindings)))
+
+
+all_rules = read_rules('rules.yaml')
+eliza_loop(all_rules)
+
+
+
+
+
+
diff --git a/read-yaml-rules.ipynb b/read-yaml-rules.ipynb
deleted file mode 100644 (file)
index 8639bca..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "import yaml"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "[{'pattern': '?X hello ?Y',\n",
-       "  'responses': ['how do you do.  please state your problem']},\n",
-       " {'pattern': '?X computer ?Y',\n",
-       "  'responses': ['do computers worry you',\n",
-       "   'what do you think about machines',\n",
-       "   'why do you mention computers',\n",
-       "   'what do you think machines have to do with your problem']},\n",
-       " {'pattern': '?X name ?Y', 'responses': ['i am not interested in names']},\n",
-       " {'pattern': '?X sorry ?Y',\n",
-       "  'responses': [\"please don't apologize\",\n",
-       "   'apologies are not necessary',\n",
-       "   'what feelings do you have when you apologize']},\n",
-       " {'pattern': '?X i remember ?Y',\n",
-       "  'responses': ['do you often think of ?Y',\n",
-       "   'does thinking of ?Y bring anything else to mind',\n",
-       "   'what else do you remember?',\n",
-       "   'why do you recall ?Y right now',\n",
-       "   'what in this present situation reminds you of ?Y',\n",
-       "   'what is the connection between me and ?Y']},\n",
-       " {'pattern': '?X do you remember ?Y',\n",
-       "  'responses': ['did you think i would forget ?Y',\n",
-       "   'why do you think i should recall ?Y',\n",
-       "   'what about ?Y',\n",
-       "   'you mentioned ?Y']},\n",
-       " {'pattern': '?X if ?Y',\n",
-       "  'responses': ['do you really think it is likely that ?Y',\n",
-       "   'do you wish that ?Y',\n",
-       "   'what do you think about ?Y',\n",
-       "   'really -- if ?Y']},\n",
-       " {'pattern': '?X i dreamt ?Y',\n",
-       "  'responses': ['really -- ?Y',\n",
-       "   'have you ever fantasized ?Y while you were awake',\n",
-       "   'have you dreamt ?Y before']},\n",
-       " {'pattern': '?X i dreamed ?Y',\n",
-       "  'responses': ['really -- ?Y',\n",
-       "   'have you ever fantasized ?Y while you were awake',\n",
-       "   'have you dreamed ?Y before']},\n",
-       " {'pattern': '?X dream ?Y',\n",
-       "  'responses': ['what does this dream suggest to you',\n",
-       "   'do you dream often',\n",
-       "   'what persons appear in your dreams',\n",
-       "   \"don't you believe that dream has to do with your problem\"]},\n",
-       " {'pattern': '?X my mother ?Y',\n",
-       "  'responses': ['who else is in your family ?Y',\n",
-       "   'tell me more about your family']},\n",
-       " {'pattern': '?X my father ?Y',\n",
-       "  'responses': ['your father',\n",
-       "   'does he influence you strongly',\n",
-       "   'what else comes to mind when you think of your father']},\n",
-       " {'pattern': '?X i want ?Y',\n",
-       "  'responses': ['what would it mean if you got ?Y',\n",
-       "   'why do you want ?Y',\n",
-       "   'suppose you got ?Y soon']},\n",
-       " {'pattern': '?X i am glad ?Y',\n",
-       "  'responses': ['how have i helped you to be ?Y',\n",
-       "   'what makes you happy just now',\n",
-       "   'can you explain why you are suddenly ?Y']},\n",
-       " {'pattern': '?X i am happy ?Y',\n",
-       "  'responses': ['how have i helped you to be ?Y',\n",
-       "   'what makes you glad just now',\n",
-       "   'can you explain why you are suddenly ?Y']},\n",
-       " {'pattern': '?X i am sad ?Y',\n",
-       "  'responses': ['i am sorry to hear you are depressed',\n",
-       "   \"i'm sure it's not pleasant to be sad\"]},\n",
-       " {'pattern': '?X i am unhappy ?Y',\n",
-       "  'responses': ['i am sorry to hear you are depressed',\n",
-       "   \"i'm sure it's not pleasant to be unhappy\"]},\n",
-       " {'pattern': '?X are like ?Y',\n",
-       "  'responses': ['what resemblence do you see between ?X and ?Y']},\n",
-       " {'pattern': '?X is like ?Y',\n",
-       "  'responses': ['in what way is it that ?X is like ?Y',\n",
-       "   'what resemblence do you see',\n",
-       "   'could there really be some connection',\n",
-       "   'how']},\n",
-       " {'pattern': '?X alike ?Y',\n",
-       "  'responses': ['in what way', 'what similarities are there']},\n",
-       " {'pattern': '?X same ?Y', 'responses': ['what other connections do you see']},\n",
-       " {'pattern': '?X i was ?Y',\n",
-       "  'responses': ['were you really',\n",
-       "   'perhaps i already knew you were ?Y',\n",
-       "   'why do you tell me you were ?Y now']},\n",
-       " {'pattern': '?X was i ?Y',\n",
-       "  'responses': ['what if you were ?Y',\n",
-       "   'do you think you were ?Y',\n",
-       "   'what would it mean if you were ?Y']},\n",
-       " {'pattern': '?X i am ?Y',\n",
-       "  'responses': ['in what way are you ?Y', 'do you want to be ?Y']},\n",
-       " {'pattern': '?X am i ?Y',\n",
-       "  'responses': ['do you believe you are ?Y',\n",
-       "   'would you want to be ?Y',\n",
-       "   'you wish i would tell you you are ?Y',\n",
-       "   'what would it mean if you were ?Y']},\n",
-       " {'pattern': '?X am ?Y',\n",
-       "  'responses': ['why do you say \"am\"', \"i don't understand that\"]},\n",
-       " {'pattern': '?X are you ?Y',\n",
-       "  'responses': ['why are you interested in whether i am ?Y or not',\n",
-       "   \"would you prefer it if i weren't ?Y\",\n",
-       "   'perhaps i am ?Y in your fantasies']},\n",
-       " {'pattern': '?X you are ?Y', 'responses': ['what makes you think i am ?Y']},\n",
-       " {'pattern': '?X because ?Y',\n",
-       "  'responses': ['is that the real reason',\n",
-       "   'what other reason might there be',\n",
-       "   'does that reason seem to explain anything else']},\n",
-       " {'pattern': '?X were you ?Y',\n",
-       "  'responses': ['perhaps i was ?Y',\n",
-       "   'what do you think',\n",
-       "   'what if i had been ?Y']},\n",
-       " {'pattern': \"?X i can't ?Y\",\n",
-       "  'responses': ['maybe you could ?Y now', 'what if you could ?Y']},\n",
-       " {'pattern': '?X i feel ?Y', 'responses': ['do you often feel ?Y']},\n",
-       " {'pattern': '?X i felt ?Y', 'responses': ['what other feelings do you have']},\n",
-       " {'pattern': '?X i ?Y you ?Z',\n",
-       "  'responses': ['perhaps in your fantasies we ?Y each other']},\n",
-       " {'pattern': \"?X why don't you ?Y\",\n",
-       "  'responses': ['should you ?Y yourself',\n",
-       "   \"do you believe i don't ?Y\",\n",
-       "   'perhaps i will ?Y in good time']},\n",
-       " {'pattern': '?X yes ?Y',\n",
-       "  'responses': ['you seem quite positive', 'you are sure', 'i understand']},\n",
-       " {'pattern': '?X no ?Y',\n",
-       "  'responses': ['why not',\n",
-       "   'you are being a bit negative',\n",
-       "   'are you saying \"no\" just to be negative']},\n",
-       " {'pattern': '?X someone ?Y', 'responses': ['can you be more specific']},\n",
-       " {'pattern': '?X everyone ?Y',\n",
-       "  'responses': ['surely not everyone',\n",
-       "   'can you think of anyone in particular',\n",
-       "   'who for example',\n",
-       "   'you are thinking of a special person']},\n",
-       " {'pattern': '?X always ?Y',\n",
-       "  'responses': ['can you think of a specific example',\n",
-       "   'when',\n",
-       "   'what incident are you thinking of',\n",
-       "   'really -- always']},\n",
-       " {'pattern': '?X what ?Y',\n",
-       "  'responses': ['why do you ask',\n",
-       "   'does that question interest you',\n",
-       "   'what is it you really want to know',\n",
-       "   'what do you think',\n",
-       "   'what comes to your mind when you ask that']},\n",
-       " {'pattern': '?X perhaps ?Y', 'responses': ['you do not seem quite certain']},\n",
-       " {'pattern': '?X are ?Y',\n",
-       "  'responses': ['do you think they might not be ?Y', 'possibly they are ?Y']},\n",
-       " {'pattern': '?X',\n",
-       "  'responses': ['very interesting',\n",
-       "   'i am not sure i understand you fully',\n",
-       "   'what does that suggest to you',\n",
-       "   'please continue',\n",
-       "   'go on',\n",
-       "   'do you feel strongly about discussing such things']}]"
-      ]
-     },
-     "execution_count": 2,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "with open('rules.yaml') as f:\n",
-    "    rules = yaml.load(f)\n",
-    "rules"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.4.3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}