Added split-candidate player
[cas-master-teacher-training.git] / hangman / hangman-split-player.ipynb
diff --git a/hangman/hangman-split-player.ipynb b/hangman/hangman-split-player.ipynb
new file mode 100644 (file)
index 0000000..a4a9fc8
--- /dev/null
@@ -0,0 +1,1841 @@
+{
+ "metadata": {
+  "name": "",
+  "signature": "sha256:5a2b414ce60f525ddfcbb85f2b57ef6ecf5d08662151337bdc833cd40f541f71"
+ },
+ "nbformat": 3,
+ "nbformat_minor": 0,
+ "worksheets": [
+  {
+   "cells": [
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "import re\n",
+      "import random\n",
+      "import string\n",
+      "import collections"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 4
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "WORDS = [w.strip() for w in open('/usr/share/dict/british-english').readlines() \n",
+      "         if re.match(r'^[a-z]*$', w.strip())]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 5
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "LETTER_COUNTS = collections.Counter(l.lower() for l in open('../sherlock-holmes.txt').read() if l in string.ascii_letters)\n",
+      "LETTERS_IN_ORDER = [p[0] for p in LETTER_COUNTS.most_common()]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 6
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "STARTING_LIVES = 10"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 7
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class Game:\n",
+      "    def __init__(self, target, player=None, lives=STARTING_LIVES):\n",
+      "        self.lives = lives\n",
+      "        self.player = player\n",
+      "        self.target = target\n",
+      "        self.discovered = list('_' * len(target))\n",
+      "        self.wrong_letters = []\n",
+      "        self.game_finished = False\n",
+      "        self.game_won = False\n",
+      "        self.game_lost = False\n",
+      "    \n",
+      "    def find_all(self, letter):\n",
+      "        return [p for p, l in enumerate(self.target) if l == letter]\n",
+      "    \n",
+      "    def update_discovered_word(self, guessed_letter):\n",
+      "        locations = self.find_all(guessed_letter)\n",
+      "        for location in locations:\n",
+      "            self.discovered[location] = guessed_letter\n",
+      "        return self.discovered\n",
+      "    \n",
+      "    def do_turn(self):\n",
+      "        if self.player:\n",
+      "            guess = self.player.guess(self.discovered, self.wrong_letters, self.lives)\n",
+      "        else:\n",
+      "            guess = self.ask_for_guess()\n",
+      "        if guess in self.target:\n",
+      "            self.update_discovered_word(guess)\n",
+      "        else:\n",
+      "            self.lives -= 1\n",
+      "            if guess not in self.wrong_letters:\n",
+      "                self.wrong_letters += [guess]\n",
+      "        if self.lives == 0:\n",
+      "            self.game_finished = True\n",
+      "            self.game_lost = True\n",
+      "        if '_' not in self.discovered:\n",
+      "            self.game_finished = True\n",
+      "            self.game_won = True\n",
+      "            \n",
+      "    def ask_for_guess(self):\n",
+      "        print('Word:', ' '.join(self.discovered), \n",
+      "              ' : Lives =', self.lives, \n",
+      "              ', wrong guesses:', ' '.join(sorted(self.wrong_letters)))\n",
+      "        guess = input('Enter letter: ').strip().lower()[0]\n",
+      "        return guess\n",
+      "    \n",
+      "    def play_game(self):\n",
+      "        while not self.game_finished:\n",
+      "            self.do_turn()\n",
+      "        if not self.player:\n",
+      "            self.report_on_game()\n",
+      "        return self.game_won\n",
+      "    \n",
+      "    def report_on_game(self):\n",
+      "        if self.game_won:\n",
+      "            print('You won! The word was', self.target)\n",
+      "        else:\n",
+      "            print('You lost. The word was', self.target)\n",
+      "        return self.game_won"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 8
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "DICT_COUNTS = collections.Counter(l.lower() for l in open('/usr/share/dict/british-english').read() if l in string.ascii_letters)\n",
+      "DICT_LETTERS_IN_ORDER = [p[0] for p in DICT_COUNTS.most_common()]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 9
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptiveNoRegex:\n",
+      "    def __init__(self, words):\n",
+      "        self.candidate_words = words\n",
+      "        \n",
+      "    def guess(self, discovered, missed, lives):\n",
+      "        self.filter_candidate_words(discovered, missed)\n",
+      "        self.set_ordered_letters()\n",
+      "        guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
+      "        return [l for l in self.ordered_letters if l not in guessed_letters][0]\n",
+      "    \n",
+      "    def filter_candidate_words(self, discovered, missed):\n",
+      "        pass\n",
+      "        \n",
+      "    def set_ordered_letters(self):\n",
+      "        counts = collections.Counter(l.lower() \n",
+      "                                     for l in ''.join(self.candidate_words) + string.ascii_lowercase \n",
+      "                                     if l in string.ascii_letters)\n",
+      "        self.ordered_letters = [p[0] for p in counts.most_common()]\n",
+      "\n",
+      "    def match(self, pattern, target, excluded=None):\n",
+      "        if not excluded:\n",
+      "            excluded = ''\n",
+      "        if len(pattern) != len(target):\n",
+      "            return False\n",
+      "        for m, c in zip(pattern, target):\n",
+      "            if m == '_' and c not in excluded:\n",
+      "                # true\n",
+      "                pass\n",
+      "            elif m != '_' and m == c:\n",
+      "                # true\n",
+      "                pass\n",
+      "            else:\n",
+      "                return False\n",
+      "        return True        "
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 10
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptiveLengthNoRegex(PlayerAdaptiveNoRegex):\n",
+      "    def __init__(self, words):\n",
+      "        super().__init__(words)\n",
+      "        self.word_len = None\n",
+      "        self.ordered_letters = None\n",
+      "        \n",
+      "    def filter_candidate_words(self, discovered, missed):\n",
+      "        if not self.word_len:\n",
+      "            self.word_len = len(discovered)\n",
+      "            self.candidate_words = [w for w in self.candidate_words if len(w) == self.word_len]\n",
+      "    \n",
+      "    def set_ordered_letters(self):\n",
+      "        if not self.ordered_letters:\n",
+      "            super().set_ordered_letters()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 11
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptiveIncludedLettersNoRegex(PlayerAdaptiveNoRegex):\n",
+      "    def filter_candidate_words(self, discovered, missed):\n",
+      "        self.candidate_words = [w for w in self.candidate_words if self.match(discovered, w)]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 12
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptiveExcludedLettersNoRegex(PlayerAdaptiveNoRegex):\n",
+      "    def filter_candidate_words(self, discovered, missed):\n",
+      "        if missed:\n",
+      "            empty_target = '_' * len(discovered)\n",
+      "            self.candidate_words = [w for w in self.candidate_words if self.match(empty_target, w, missed)]        "
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 13
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptivePatternNoRegex(PlayerAdaptiveNoRegex):\n",
+      "    def filter_candidate_words(self, discovered, missed):\n",
+      "        attempted_letters = [l for l in discovered if l != '_'] + missed\n",
+      "        self.candidate_words = [w for w in self.candidate_words if self.match(discovered, w, attempted_letters)]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 14
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "\n",
+      "wins = 0\n",
+      "for _ in range(1000):\n",
+      "    g = Game(random.choice(WORDS), player=PlayerAdaptivePatternNoRegex(WORDS))\n",
+      "    g.play_game()\n",
+      "    if g.game_won:\n",
+      "        wins += 1\n",
+      "print(wins)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "993\n",
+        "992"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "994"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "991"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 48.2 s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 15
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "len([w for w in WORDS if 'r' in w])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 21,
+       "text": [
+        "31398"
+       ]
+      }
+     ],
+     "prompt_number": 21
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "len([w for w in WORDS if 'r' not in w])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 22,
+       "text": [
+        "31458"
+       ]
+      }
+     ],
+     "prompt_number": 22
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "letter_diffs = []\n",
+      "for l in string.ascii_lowercase:\n",
+      "    n = 0\n",
+      "    for w in WORDS:\n",
+      "        if l in w:\n",
+      "            n += 1\n",
+      "        else:\n",
+      "            n -=1\n",
+      "    letter_diffs += [(l, abs(n))]\n",
+      "sorted(letter_diffs, key=lambda p: p[1])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 19,
+       "text": [
+        "[('r', 60),\n",
+        " ('a', 98),\n",
+        " ('n', 3720),\n",
+        " ('t', 4728),\n",
+        " ('i', 6136),\n",
+        " ('s', 8662),\n",
+        " ('o', 12788),\n",
+        " ('l', 17878),\n",
+        " ('e', 22936),\n",
+        " ('c', 26102),\n",
+        " ('d', 26368),\n",
+        " ('u', 30282),\n",
+        " ('g', 33260),\n",
+        " ('p', 35960),\n",
+        " ('m', 37904),\n",
+        " ('h', 41134),\n",
+        " ('b', 44784),\n",
+        " ('y', 47462),\n",
+        " ('f', 49626),\n",
+        " ('v', 52502),\n",
+        " ('k', 53616),\n",
+        " ('w', 53688),\n",
+        " ('x', 60010),\n",
+        " ('q', 60816),\n",
+        " ('j', 60938),\n",
+        " ('z', 61244)]"
+       ]
+      }
+     ],
+     "prompt_number": 19
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "def letter_diff(l):\n",
+      "    return abs(sum(1 if l in w else -1 for w in WORDS))\n",
+      "\n",
+      "letter_diffs = [(l, letter_diff(l)) \n",
+      "                for l in string.ascii_lowercase]\n",
+      "sorted(letter_diffs, key=lambda p: p[1])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 23,
+       "text": [
+        "[('r', 60),\n",
+        " ('a', 98),\n",
+        " ('n', 3720),\n",
+        " ('t', 4728),\n",
+        " ('i', 6136),\n",
+        " ('s', 8662),\n",
+        " ('o', 12788),\n",
+        " ('l', 17878),\n",
+        " ('e', 22936),\n",
+        " ('c', 26102),\n",
+        " ('d', 26368),\n",
+        " ('u', 30282),\n",
+        " ('g', 33260),\n",
+        " ('p', 35960),\n",
+        " ('m', 37904),\n",
+        " ('h', 41134),\n",
+        " ('b', 44784),\n",
+        " ('y', 47462),\n",
+        " ('f', 49626),\n",
+        " ('v', 52502),\n",
+        " ('k', 53616),\n",
+        " ('w', 53688),\n",
+        " ('x', 60010),\n",
+        " ('q', 60816),\n",
+        " ('j', 60938),\n",
+        " ('z', 61244)]"
+       ]
+      }
+     ],
+     "prompt_number": 23
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "class PlayerAdaptiveSplit(PlayerAdaptivePatternNoRegex):\n",
+      "    def set_ordered_letters(self):\n",
+      "        def letter_diff(l):\n",
+      "            return abs(sum(1 if l in w else -1 for w in self.candidate_words))\n",
+      "        possible_letters = set(''.join(self.candidate_words))\n",
+      "        # if len(self.candidate_words) > 1:\n",
+      "        letter_diffs = [(l, letter_diff(l)) for l in possible_letters]\n",
+      "        self.ordered_letters = [p[0] for p in sorted(letter_diffs, key=lambda p: p[1])]\n",
+      "        # else:\n",
+      "        #    self.ordered_letters = list(self.candidate_words[0])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 71
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
+      "g.play_game()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 72,
+       "text": [
+        "True"
+       ]
+      }
+     ],
+     "prompt_number": 72
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.target"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 73,
+       "text": [
+        "'baste'"
+       ]
+      }
+     ],
+     "prompt_number": 73
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.discovered"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 74,
+       "text": [
+        "['b', 'a', 's', 't', 'e']"
+       ]
+      }
+     ],
+     "prompt_number": 74
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.wrong_letters"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 75,
+       "text": [
+        "['c', 'h']"
+       ]
+      }
+     ],
+     "prompt_number": 75
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "\n",
+      "wins = 0\n",
+      "for _ in range(1000):\n",
+      "    g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
+      "    g.play_game()\n",
+      "    if g.game_won:\n",
+      "        wins += 1\n",
+      "print(wins)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "983\n",
+        "982"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "981"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "987"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 55.6 s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 78
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p=PlayerAdaptiveSplit(WORDS)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 54
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "dsc = ['_'] * len('recognition')\n",
+      "dsc"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 55,
+       "text": [
+        "['_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_']"
+       ]
+      }
+     ],
+     "prompt_number": 55
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.guess(dsc, [], 10)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 56,
+       "text": [
+        "'o'"
+       ]
+      }
+     ],
+     "prompt_number": 56
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "len(p.candidate_words)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 57,
+       "text": [
+        "5027"
+       ]
+      }
+     ],
+     "prompt_number": 57
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.guess(['_', '_', '_', 'o', '_', '_', '_', '_', '_', 'o', '_'], [], 10)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 58,
+       "text": [
+        "'c'"
+       ]
+      }
+     ],
+     "prompt_number": 58
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.candidate_words"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 59,
+       "text": [
+        "['association',\n",
+        " 'defoliation',\n",
+        " 'deformation',\n",
+        " 'denominator',\n",
+        " 'deportation',\n",
+        " 'excoriation',\n",
+        " 'exhortation',\n",
+        " 'exportation',\n",
+        " 'importation',\n",
+        " 'information',\n",
+        " 'liposuction',\n",
+        " 'negotiation',\n",
+        " 'recognition',\n",
+        " 'recondition',\n",
+        " 'reformation',\n",
+        " 'subornation']"
+       ]
+      }
+     ],
+     "prompt_number": 59
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], [], 10)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 60,
+       "text": [
+        "'a'"
+       ]
+      }
+     ],
+     "prompt_number": 60
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.candidate_words"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 61,
+       "text": [
+        "['excoriation', 'recognition', 'recondition']"
+       ]
+      }
+     ],
+     "prompt_number": 61
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], ['a'], 9)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 62,
+       "text": [
+        "'d'"
+       ]
+      }
+     ],
+     "prompt_number": 62
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.candidate_words"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 63,
+       "text": [
+        "['recognition', 'recondition']"
+       ]
+      }
+     ],
+     "prompt_number": 63
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], ['a', 'd'], 8)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 64,
+       "text": [
+        "'r'"
+       ]
+      }
+     ],
+     "prompt_number": 64
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "p.candidate_words"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 65,
+       "text": [
+        "['recognition']"
+       ]
+      }
+     ],
+     "prompt_number": 65
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g = Game('recognition', player=PlayerAdaptiveSplit(WORDS))\n",
+      "g.play_game()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 67,
+       "text": [
+        "True"
+       ]
+      }
+     ],
+     "prompt_number": 67
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.discovered"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 68,
+       "text": [
+        "['r', 'e', 'c', 'o', 'g', 'n', 'i', 't', 'i', 'o', 'n']"
+       ]
+      }
+     ],
+     "prompt_number": 68
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.lives"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 69,
+       "text": [
+        "8"
+       ]
+      }
+     ],
+     "prompt_number": 69
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "\n",
+      "wins = 0\n",
+      "for _ in range(10000):\n",
+      "    g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
+      "    g.play_game()\n",
+      "    if g.game_won:\n",
+      "        wins += 1\n",
+      "print(wins)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "9857\n",
+        "9862"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "9844"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "9860"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 9min 15s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 79
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "\n",
+      "wins = 0\n",
+      "for _ in range(10000):\n",
+      "    g = Game(random.choice(WORDS), player=PlayerAdaptivePatternNoRegex(WORDS))\n",
+      "    g.play_game()\n",
+      "    if g.game_won:\n",
+      "        wins += 1\n",
+      "print(wins)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "9934\n",
+        "9916"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "9921"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "9932"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 8min 12s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 81
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "for w in random.sample(WORDS, 5000):\n",
+      "    gp = Game(w, player=PlayerAdaptivePatternNoRegex(WORDS))\n",
+      "    gp.play_game()\n",
+      "    gs = Game(w, player=PlayerAdaptiveSplit(WORDS))\n",
+      "    gs.play_game()\n",
+      "    if not gp.game_won and not gs.game_won:\n",
+      "        print('Both:::::', gp.target, 'Pattern:', '[' + ' '.join(gp.discovered) + ']', ''.join(gp.wrong_letters), \n",
+      "              ':: Split:', '[' + ' '.join(gs.discovered) + ']', ''.join(gs.wrong_letters))\n",
+      "    if not gp.game_won and gs.game_won:\n",
+      "        print('Pattern::', gp.target, '[' + ' '.join(gp.discovered) + ']', ''.join(gp.wrong_letters))\n",
+      "    if gp.game_won and not gs.game_won:\n",
+      "        print('Split::::', gs.target, '[' + ' '.join(gs.discovered) + ']', ''.join(gs.wrong_letters))"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "Split:::: cut [_ _ t] aoeiybgnpj\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " reviewers [_ _ _ _ _ _ _ _ _] taoldgnupc\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " piped [_ i _ e d] saolrnkvbm\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " joying Pattern: [_ o _ i n g] esapwdtrkm :: Split: [_ o _ _ n _] srdatpwhvk\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " duck Pattern: [_ u _ _] esoailfrnm :: Split: [_ u _ _] esaorlnfmt\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " bum [b _ _] aoeiyrtgns\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " jibing [_ i _ i n g] esrldmpkvt\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " begged [_ _ _ _ _ d] srlnoauipt\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " bucked [b u _ _ e d] aoilstfgpr\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " bunk [_ u n k] esoailfrgp\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " dumping [_ u _ p _ _ g] srlaoecjhb\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " meekest [_ _ _ _ _ s _] iaournlpdw\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " wove [_ o v e] arnldptkmc\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " finking [_ _ _ _ _ _ g] srlaoeutpd\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fan Pattern: [_ a _] tpgwdmrbys :: Split: [_ a n] tpgwmbyrdv\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " hug [_ u g] aoeibpdmtj\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " feminism [_ _ _ _ _ _ _ _] ratlogdcuh\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " effect [_ _ _ _ c t] srdnaioulp\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " puff [_ u f f] esaorlnmgc\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " skivvies [_ _ _ _ _ _ _ _] ratlogdcuh\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " miffing [_ _ _ _ _ _ g] srlaoeutpd\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " dung Pattern: [_ u n _] esoailfrkt :: Split: [_ u n g] esaorlkthb\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " gibed [_ i _ e d] saomlprkvn\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " rubs [_ u b s] eaoicpdtnh\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " bat [_ a t] ecpsofmvhr\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " boobs [_ o o _ s] eatdklmpfn\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " yon Pattern: [_ o n] atbdwpiecs :: Split: [_ o n] atbdwpiesc\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " firs Pattern: [f i _ s] eaoptgbdmn :: Split: [_ i _ s] eaotpgbdmn\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " quipping [_ _ _ _ _ _ _ g] ratloscedh\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " ragging [r a _ _ _ n _] seotzclpdm\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fuddled [_ u _ _ l _ _] sraoibzmgc\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " yack Pattern: [_ a c k] esolrntmpj :: Split: [_ a c k] esrlntmjhb\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " vanning [_ a _ _ _ _ g] srltpbwmck\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fizziest [_ _ _ _ _ _ _ t] rauonlphdk\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " rug [_ u g] aoeibpdmtj\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fixed Pattern: [_ i _ e d] saomlprkvn :: Split: [_ i _ e d] saolrnkvbm\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " mop [_ o p] atbdwchlsf\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " separatists [_ _ p _ _ _ _ _ _ _ _] oldcgnymbx\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " miff [_ _ _ _] esaoutnlrc\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " putty [p u _ _ y] seaoimlnrf\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " mice [_ i _ e] aorlnvtdkw\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fixing Pattern: [_ i _ i n g] esrldmpkvt :: Split: [_ _ _ _ n _] srdaoeulbp\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " gaged [_ a _ e d] srwctpmzbh\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fag [_ a g] tpjnhrlbsw\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " woeful [_ o _ _ _ _] srdnaictyb\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " pauper [_ a _ _ _ r] sntlmidkvj\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " faxing Pattern: [f a _ i n g] esrwtlcdkz :: Split: [_ a _ _ n _] srdtwmpczh\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " yoking Pattern: [_ o k i n g] esapwdtrcj :: Split: [_ o k _ n _] srdatpwhvj\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " cox Pattern: [_ o _] atbdwpnsge :: Split: [_ o _] atbdwpngse\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " doff [_ o _ _] esalrnctyb\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " puck Pattern: [_ u _ _] esoailfrnm :: Split: [_ u _ _] esaorlnfmt\n",
+        "Pattern::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " tuck [_ u _ _] esoailfrnm\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " kerchiefs [_ _ _ c _ _ _ _ _] taoldgnupv\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " members [_ _ _ _ _ r s] aoiutdpcgv\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " foxing Pattern: [_ o _ i n g] esapwdtrkm :: Split: [_ o _ _ n _] srdatpwhvk\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " anaesthetises [_ _ _ _ _ _ _ _ _ _ _ _ _] clgmpdvuro\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " versifies [_ _ _ _ _ _ _ _ _] taoldgnupc\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " babes Pattern: [_ a _ e s] rltngcdkzv :: Split: [_ a _ e s] rltngcdkzv\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " huffing [_ u f f _ _ g] srlaoecpbm\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " weeper [_ _ _ p _ r] saioutdhbk\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " buffering [_ u _ _ _ _ _ _ g] taoldsphmv\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " dills [_ _ l l s] eaountghrb\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " wigging [_ _ g g _ _ g] srlaouejpd\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " indenting [_ _ d _ _ t _ _ _] aoscrlbvhf\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " morn [_ o r n] esaltchbpw\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " buff Pattern: [_ u f f] esoailgcpd :: Split: [_ u f f] esaorlnmgc\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " zero [_ e r _] satlbnhpyg\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " jazz Pattern: [_ a _ _] esolrntmky :: Split: [_ a _ _] esrlntmkdw\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " k [_] geopdtuyiz\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " find [_ _ n d] esaoutkhrb\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " happy [_ a _ _ y] sentdrglcz\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fibbing [_ _ _ _ _ _ g] srlaoeutpd\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " wifeliest [_ _ _ _ _ _ _ _ t] nroacmhpgu\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " r Pattern: [_] giecposdwk :: Split: [_] geopdtuyiz\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " businesses [_ _ _ _ n _ _ _ _ _] olatdgcphr\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fife Pattern: [_ i _ e] aorlndvtpm :: Split: [_ i _ e] aorlnvtdkw\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " fix Pattern: [_ i _] aoeptdngsb :: Split: [_ i _] aoetndpgbs\n",
+        "Both:::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " mil Pattern: [_ i _] aoeptdngsb :: Split: [_ i _] aoetndpgbs\n",
+        "Split::::"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " wetted [_ _ t t _ d] srlnoauipj\n"
+       ]
+      }
+     ],
+     "prompt_number": 90
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "gs = Game('businesses', player=PlayerAdaptiveSplit(WORDS))"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 91
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g = Game('feminism', player=PlayerAdaptiveSplit(WORDS))\n",
+      "while not g.game_finished:\n",
+      "    guess = g.player.guess(g.discovered, g.wrong_letters, g.lives)\n",
+      "    print(g.target, '(' + str(g.lives) + ')', \n",
+      "          '[' + ' '.join(g.discovered) + ']', ''.join(g.wrong_letters), \n",
+      "          ';', len(g.player.candidate_words), 'candidate words')\n",
+      "    print('Guess = ', guess)\n",
+      "    g.do_turn()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "feminism (10) [_ _ _ _ _ _ _ _]  ; 10328 candidate words\n",
+        "Guess =  r\n",
+        "feminism"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " (9) [_ _ _ _ _ _ _ _] r ; 5102 candidate words\n",
+        "Guess =  a\n",
+        "feminism (8) [_ _ _ _ _ _ _ _] ra ; 2673 candidate words\n",
+        "Guess =  t\n",
+        "feminism"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " (7) [_ _ _ _ _ _ _ _] rat ; 1466 candidate words\n",
+        "Guess =  l\n",
+        "feminism (6) [_ _ _ _ _ _ _ _] ratl ; 704 candidate words\n",
+        "Guess =  o\n",
+        "feminism (5) [_ _ _ _ _ _ _ _] ratlo ; 359 candidate words\n",
+        "Guess =  g\n",
+        "feminism (4) [_ _ _ _ _ _ _ _] ratlog ; 189 candidate words\n",
+        "Guess =  d\n",
+        "feminism (3) [_ _ _ _ _ _ _ _] ratlogd ; 94 candidate words\n",
+        "Guess =  c\n",
+        "feminism (2) [_ _ _ _ _ _ _ _] ratlogdc ; 50 candidate words\n",
+        "Guess =  u\n",
+        "feminism (1) [_ _ _ _ _ _ _ _] ratlogdcu ; 31 candidate words\n",
+        "Guess =  h\n"
+       ]
+      }
+     ],
+     "prompt_number": 170
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g = Game('feminism', player=PlayerAdaptivePatternNoRegex(WORDS))\n",
+      "while not g.game_finished:\n",
+      "    guess = g.player.guess(g.discovered, g.wrong_letters, g.lives)\n",
+      "    print(g.target, '(' + str(g.lives) + ')', \n",
+      "          '[' + ' '.join(g.discovered) + ']', ''.join(g.wrong_letters), \n",
+      "          ';', len(g.player.candidate_words), 'candidate words')\n",
+      "    print('Guess = ', guess)\n",
+      "    g.do_turn()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "feminism (10) [_ _ _ _ _ _ _ _]  ; 10328 candidate words\n",
+        "Guess =  e\n",
+        "feminism"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        " (10) [_ e _ _ _ _ _ _]  ; 540 candidate words\n",
+        "Guess =  i\n",
+        "feminism (10) [_ e _ i _ i _ _]  ; 42 candidate words\n",
+        "Guess =  n\n",
+        "feminism (10) [_ e _ i n i _ _]  ; 3 candidate words\n",
+        "Guess =  s\n",
+        "feminism (10) [_ e _ i n i s _]  ; 3 candidate words\n",
+        "Guess =  f\n",
+        "feminism (10) [f e _ i n i s _]  ; 2 candidate words\n",
+        "Guess =  m\n"
+       ]
+      }
+     ],
+     "prompt_number": 172
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "g.player.candidate_words"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 171,
+       "text": [
+        "['beehives',\n",
+        " 'enmeshes',\n",
+        " 'evenness',\n",
+        " 'expenses',\n",
+        " 'feminine',\n",
+        " 'feminism',\n",
+        " 'fineness',\n",
+        " 'finesses',\n",
+        " 'finishes',\n",
+        " 'fishwife',\n",
+        " 'inkiness',\n",
+        " 'keenness',\n",
+        " 'meekness',\n",
+        " 'minibike',\n",
+        " 'minimise',\n",
+        " 'missives',\n",
+        " 'ninepins',\n",
+        " 'penknife',\n",
+        " 'sexiness',\n",
+        " 'sheepish',\n",
+        " 'shimmies',\n",
+        " 'shinnies',\n",
+        " 'skivvies',\n",
+        " 'sphinxes',\n",
+        " 'vivifies',\n",
+        " 'vixenish',\n",
+        " 'whimseys',\n",
+        " 'whimsies',\n",
+        " 'whinnies',\n",
+        " 'whiskeys',\n",
+        " 'whiskies']"
+       ]
+      }
+     ],
+     "prompt_number": 171
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    }
+   ],
+   "metadata": {}
+  }
+ ]
+}
\ No newline at end of file