Updated notebook versions
[cas-master-teacher-training.git] / hangman / 01-hangman-setter.ipynb
index e3a7c15c44ef42a25ddafc0701686657e3e36eea..c2c790553729ceadc7a01a56f3fefacda23e1eb1 100644 (file)
 {
- "metadata": {
-  "name": "",
-  "signature": "sha256:374900202f4f7c3f157762c0d012b597cc502efce4de220013e3cc9cd8dfc896"
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
+ "cells": [
   {
-   "cells": [
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "# Hangman 1: set a puzzle\n",
-      "\n",
-      "A fairly traditional hangman game. The computer chooses a word, the (human) player has to guess it without making too many wrong guesses. You'll need to find a list of words to chose from and develop a simple UI for the game (e.g. text only: display the target word with underscores and letters, lives left, and maybe incorrect guesses). \n",
-      "\n",
-      "## Data structures\n",
-      "\n",
-      "* What do we need to track?\n",
-      "* What operations do we need to perform on it?\n",
-      "* How to store it?\n",
-      "\n",
-      "## Creating a game\n",
-      "* 'List' of words to choose from\n",
-      "    * Pick one at random\n",
-      "\n",
-      "## Game state\n",
-      "\n",
-      "<table>\n",
-      "<tr valign=\"top\">\n",
-      "<th>Data</th>\n",
-      "<th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>\n",
-      "<th>Operations</th>\n",
-      "</tr>\n",
-      "<tr valign=\"top\">\n",
-      "<td>\n",
-      "\n",
-      "* Target word\n",
-      "* Discovered letters\n",
-      "    * In order in the word\n",
-      "* Lives left\n",
-      "* Wrong letters?\n",
-      "\n",
-      "</td>\n",
-      "<td></td>\n",
-      "<td>\n",
-      "\n",
-      "* Get a guess\n",
-      "* Update discovered letters\n",
-      "* Update lives\n",
-      "* Show discovered word\n",
-      "* Detect game end, report\n",
-      "* Detect game win or loss, report\n",
-      "\n",
-      "</td>\n",
-      "</tr>\n",
-      "</table>"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "import re\n",
-      "import random"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 3
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Get the words\n",
-      "Read the words the game setter can choose from. The list contains all sorts of hangman-illegal words, such as proper nouns and abbreviations. We'll remove them by taking the pragmatic approach that if a word contains a non-lowercase letter (capital letters, full stops, apostrophes, etc.), it's illegal. "
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "# Just use a regex to filter the words. There are other ways to do this, as you know.\n",
-      "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": 4
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "A few quick looks at the list of words, to make sure it's sensible."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "len(WORDS)"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 5,
-       "text": [
-        "62856"
-       ]
-      }
-     ],
-     "prompt_number": 5
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "WORDS[30000:30010]"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 6,
-       "text": [
-        "['jotted',\n",
-        " 'jotting',\n",
-        " 'jottings',\n",
-        " 'joule',\n",
-        " 'joules',\n",
-        " 'jounce',\n",
-        " 'jounced',\n",
-        " 'jounces',\n",
-        " 'jouncing',\n",
-        " 'journal']"
-       ]
-      }
-     ],
-     "prompt_number": 6
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Constants and game states"
-     ]
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## The target word"
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "target = random.choice(WORDS)\n",
-      "target"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 7,
-       "text": [
-        "'rocketing'"
-       ]
-      }
-     ],
-     "prompt_number": 7
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "STARTING_LIVES = 10\n",
-      "lives = 0"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 8
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "wrong_letters = []"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 9
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "We'll represent the partially-discovered word as a list of characters. Each character is either the letter in the target (if it's been discovered) or an underscore if it's not.\n",
-      "\n",
-      "Use a `list` as it's a mutable data structure. That means we can change individual elements of a list, which we couldn't if we represented it as a `string`.\n",
-      "\n",
-      "We can also use `discovered` to check of a game win. If `discovered` contains an underscore, the player hasn't won the game."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "discovered = list('_' * len(target))\n",
-      "discovered"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 10,
-       "text": [
-        "['_', '_', '_', '_', '_', '_', '_', '_', '_']"
-       ]
-      }
-     ],
-     "prompt_number": 10
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "We can use `' '.join(discovered)` to display it nicely."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "' '.join(discovered)"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 11,
-       "text": [
-        "'_ _ _ _ _ _ _ _ _'"
-       ]
-      }
-     ],
-     "prompt_number": 11
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Read a letter\n",
-      "Get rid of fluff and make sure we only get one letter."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "letter = input('Enter letter: ').strip().lower()[0]\n",
-      "letter"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: r\n"
-       ]
-      },
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 9,
-       "text": [
-        "'r'"
-       ]
-      }
-     ],
-     "prompt_number": 9
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "# Finding a letter in a word\n",
-      "One operation we want to to is to update `discovered` when we get a `letter`. The trick is that we want to update every occurrence of the `letter` in `discovered`. \n",
-      "\n",
-      "We'll do it in two phases. In the first phase, we'll find all the occurences of the `letter` in the `target` and return a list of those locations. In the second phase, we'll update all those positions in `discovered` with the `letter`. \n",
-      "\n",
-      "There's probaby a clever way of doing this in one pass, but it's complicated (or at least not obvious), so let's just do it the easy way."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "# Note that find returns either the first occurrence of a substring, or -1 if it doesn't exist.\n",
-      "def find_all_explicit(string, letter):\n",
-      "    locations = []\n",
-      "    starting=0\n",
-      "    location = string.find(letter)\n",
-      "    while location > -1:\n",
-      "        locations += [location]\n",
-      "        starting = location + 1\n",
-      "        location = string.find(letter, starting)\n",
-      "    return locations"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 25
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "# A simpler way using a list comprehension and the built-in enumerate()\n",
-      "def find_all(string, letter):\n",
-      "    return [p for p, l in enumerate(string) if l == letter]"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 12
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "find_all('happy', 'p')"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 13,
-       "text": [
-        "[2, 3]"
-       ]
-      }
-     ],
-     "prompt_number": 13
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Updating the discovered word\n",
-      "Now we can update `discovered`. We'll look through the `locations` list and update that element of `discovered`."
-     ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "guessed_letter = 'e'\n",
-      "locations = find_all(target, guessed_letter)\n",
-      "for location in locations:\n",
-      "    discovered[location] = guessed_letter\n",
-      "discovered"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 15,
-       "text": [
-        "['_', '_', '_', '_', 'e', '_', '_', '_', '_']"
-       ]
-      }
-     ],
-     "prompt_number": 15
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Putting it all together\n",
-      "We've not got quite a few bits and pieces of how the game should work. Now it's time to start putting them together into the game.\n",
-      "\n",
-      "```\n",
-      "to play a game:\n",
-      "    initialise lives, target, etc.\n",
-      "    finished? = False\n",
-      "    handle a turn\n",
-      "    while not finished?:\n",
-      "        if guessed all letters:\n",
-      "            report success\n",
-      "            finished? = True\n",
-      "        elif run out of lives:\n",
-      "            report failure\n",
-      "            finished? = True\n",
-      "        else:\n",
-      "            handle a turn\n",
-      "```\n",
-      "\n",
-      "```\n",
-      "to handle a turn:\n",
-      "    print the challenge\n",
-      "    get the letter\n",
-      "    if letter in target:\n",
-      "        update discovered\n",
-      "    else:\n",
-      "        update lives, wrong_letters\n",
-      "```\n",
-      "\n",
-      "```\n",
-      "to update discovered:\n",
-      "    find all the locations of letter in target\n",
-      "    replace the appropriate underscores in discovered\n",
-      "```\n",
-      "\n",
-      "We pretty much know how to do all these bits, so let's just start at the bottom and off we go!\n",
-      "\n",
-      "###Syntax note\n",
-      "Note the use of Python's `global` statement, to tell Python that we're updating the global variables in each procedure. We'll fix that later."
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Hangman 1: set a puzzle\n",
+    "\n",
+    "A fairly traditional hangman game. The computer chooses a word, the (human) player has to guess it without making too many wrong guesses. You'll need to find a list of words to chose from and develop a simple UI for the game (e.g. text only: display the target word with underscores and letters, lives left, and maybe incorrect guesses). \n",
+    "\n",
+    "## Data structures\n",
+    "\n",
+    "* What do we need to track?\n",
+    "* What operations do we need to perform on it?\n",
+    "* How to store it?\n",
+    "\n",
+    "## Creating a game\n",
+    "* 'List' of words to choose from\n",
+    "    * Pick one at random\n",
+    "\n",
+    "## Game state\n",
+    "\n",
+    "### Data\n",
+    "* Target word\n",
+    "* Discovered letters\n",
+    "    * In order in the word\n",
+    "* Lives left\n",
+    "* Wrong letters?\n",
+    "\n",
+    "### Operations\n",
+    "* Get a guess\n",
+    "* Update discovered letters\n",
+    "* Update lives\n",
+    "* Show discovered word\n",
+    "* Detect game end, report\n",
+    "* Detect game win or loss, report\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import re\n",
+    "import random"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Get the words\n",
+    "Read the words the game setter can choose from. The list contains all sorts of hangman-illegal words, such as proper nouns and abbreviations. We'll remove them by taking the pragmatic approach that if a word contains a non-lowercase letter (capital letters, full stops, apostrophes, etc.), it's illegal. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Just use a regex to filter the words. There are other ways to do this, as you know.\n",
+    "WORDS = [w.strip() for w in open('/usr/share/dict/british-english').readlines() \n",
+    "         if re.match(r'^[a-z]*$', w.strip())]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A few quick looks at the list of words, to make sure it's sensible."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "62856"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(WORDS)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['jotted',\n",
+       " 'jotting',\n",
+       " 'jottings',\n",
+       " 'joule',\n",
+       " 'joules',\n",
+       " 'jounce',\n",
+       " 'jounced',\n",
+       " 'jounces',\n",
+       " 'jouncing',\n",
+       " 'journal']"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "WORDS[30000:30010]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Constants and game states"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## The target word"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'rocketing'"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "target = random.choice(WORDS)\n",
+    "target"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "STARTING_LIVES = 10\n",
+    "lives = 0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "wrong_letters = []"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We'll represent the partially-discovered word as a list of characters. Each character is either the letter in the target (if it's been discovered) or an underscore if it's not.\n",
+    "\n",
+    "Use a `list` as it's a mutable data structure. That means we can change individual elements of a list, which we couldn't if we represented it as a `string`.\n",
+    "\n",
+    "We can also use `discovered` to check for a game win. If `discovered` contains an underscore, the player hasn't won the game."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['_', '_', '_', '_', '_', '_', '_', '_', '_']"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "discovered = list('_' * len(target))\n",
+    "discovered"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can use `' '.join(discovered)` to display it nicely."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'_ _ _ _ _ _ _ _ _'"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "' '.join(discovered)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Read a letter\n",
+    "Get rid of fluff and make sure we only get one letter."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Enter letter: r\n"
      ]
     },
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def updated_discovered_word(discovered, guessed_letter):\n",
-      "    locations = find_all(target, guessed_letter)\n",
-      "    for location in locations:\n",
-      "        discovered[location] = guessed_letter\n",
-      "    return discovered"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 16
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def initialise():\n",
-      "    global lives, target, discovered, wrong_letters\n",
-      "    lives = STARTING_LIVES\n",
-      "    target = random.choice(WORDS)\n",
-      "    discovered = list('_' * len(target))\n",
-      "    wrong_letters = []"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'r'"
+      ]
+     },
+     "execution_count": 9,
      "metadata": {},
-     "outputs": [],
-     "prompt_number": 17
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def do_turn():\n",
-      "    global discovered, lives, wrong_letters\n",
-      "    print('Word:', ' '.join(discovered), ' : Lives =', lives, ', wrong guesses:', ' '.join(sorted(wrong_letters)))\n",
-      "    guess = input('Enter letter: ').strip().lower()[0]\n",
-      "    if guess in target:\n",
-      "        updated_discovered_word(discovered, guess)\n",
-      "    else:\n",
-      "        lives -= 1\n",
-      "        if guess not in wrong_letters:\n",
-      "            wrong_letters += [guess]"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 18
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def play_game():\n",
-      "    global discovered, lives\n",
-      "    initialise()\n",
-      "    game_finished = False\n",
-      "    do_turn()\n",
-      "    while not game_finished:\n",
-      "        if '_' not in discovered:\n",
-      "            print('You won! The word was', target)\n",
-      "            game_finished = True\n",
-      "        elif lives <= 0:\n",
-      "            print('You lost. The word was', target)\n",
-      "            game_finished = True\n",
-      "        else:\n",
-      "            do_turn()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 19
-    },
-    {
-     "cell_type": "markdown",
-     "metadata": {},
-     "source": [
-      "## Playing the game\n",
-      "That seemed straightforward. Let's see if it works!"
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "letter = input('Enter letter: ').strip().lower()[0]\n",
+    "letter"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Finding a letter in a word\n",
+    "One operation we want to to is to update `discovered` when we get a `letter`. The trick is that we want to update every occurrence of the `letter` in `discovered`. \n",
+    "\n",
+    "We'll do it in two phases. In the first phase, we'll find all the occurences of the `letter` in the `target` and return a list of those locations. In the second phase, we'll update all those positions in `discovered` with the `letter`. \n",
+    "\n",
+    "There's probaby a clever way of doing this in one pass, but it's complicated (or at least not obvious), so let's just do it the easy way."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Note that find returns either the first occurrence of a substring, or -1 if it doesn't exist.\n",
+    "def find_all_explicit(string, letter):\n",
+    "    locations = []\n",
+    "    starting=0\n",
+    "    location = string.find(letter)\n",
+    "    while location > -1:\n",
+    "        locations += [location]\n",
+    "        starting = location + 1\n",
+    "        location = string.find(letter, starting)\n",
+    "    return locations"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# A simpler way using a list comprehension and the built-in enumerate()\n",
+    "def find_all(string, letter):\n",
+    "    return [p for p, l in enumerate(string) if l == letter]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2, 3]"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "find_all('happy', 'p')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Updating the discovered word\n",
+    "Now we can update `discovered`. We'll look through the `locations` list and update that element of `discovered`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['_', '_', '_', '_', 'e', '_', '_', '_', '_']"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "guessed_letter = 'e'\n",
+    "locations = find_all(target, guessed_letter)\n",
+    "for location in locations:\n",
+    "    discovered[location] = guessed_letter\n",
+    "discovered"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Putting it all together\n",
+    "We've not got quite a few bits and pieces of how the game should work. Now it's time to start putting them together into the game.\n",
+    "\n",
+    "```\n",
+    "to play a game:\n",
+    "    initialise lives, target, etc.\n",
+    "    finished? = False\n",
+    "    handle a turn\n",
+    "    while not finished?:\n",
+    "        if guessed all letters:\n",
+    "            report success\n",
+    "            finished? = True\n",
+    "        elif run out of lives:\n",
+    "            report failure\n",
+    "            finished? = True\n",
+    "        else:\n",
+    "            handle a turn\n",
+    "```\n",
+    "\n",
+    "```\n",
+    "to handle a turn:\n",
+    "    print the challenge\n",
+    "    get the letter\n",
+    "    if letter in target:\n",
+    "        update discovered\n",
+    "    else:\n",
+    "        update lives, wrong_letters\n",
+    "```\n",
+    "\n",
+    "```\n",
+    "to update discovered:\n",
+    "    find all the locations of letter in target\n",
+    "    replace the appropriate underscores in discovered\n",
+    "```\n",
+    "\n",
+    "We pretty much know how to do all these bits, so let's just start at the bottom and off we go!\n",
+    "\n",
+    "###Syntax note\n",
+    "Note the use of Python's `global` statement, to tell Python that we're updating the global variables in each procedure. We'll fix that later."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def updated_discovered_word(discovered, guessed_letter):\n",
+    "    locations = find_all(target, guessed_letter)\n",
+    "    for location in locations:\n",
+    "        discovered[location] = guessed_letter\n",
+    "    return discovered"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def initialise():\n",
+    "    global lives, target, discovered, wrong_letters\n",
+    "    lives = STARTING_LIVES\n",
+    "    target = random.choice(WORDS)\n",
+    "    discovered = list('_' * len(target))\n",
+    "    wrong_letters = []"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def do_turn():\n",
+    "    global discovered, lives, wrong_letters\n",
+    "    print('Word:', ' '.join(discovered), ' : Lives =', lives, ', wrong guesses:', ' '.join(sorted(wrong_letters)))\n",
+    "    guess = input('Enter letter: ').strip().lower()[0]\n",
+    "    if guess in target:\n",
+    "        updated_discovered_word(discovered, guess)\n",
+    "    else:\n",
+    "        lives -= 1\n",
+    "        if guess not in wrong_letters:\n",
+    "            wrong_letters += [guess]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def play_game():\n",
+    "    global discovered, lives\n",
+    "    initialise()\n",
+    "    game_finished = False\n",
+    "    do_turn()\n",
+    "    while not game_finished:\n",
+    "        if '_' not in discovered:\n",
+    "            print('You won! The word was', target)\n",
+    "            game_finished = True\n",
+    "        elif lives <= 0:\n",
+    "            print('You lost. The word was', target)\n",
+    "            game_finished = True\n",
+    "        else:\n",
+    "            do_turn()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Playing the game\n",
+    "That seemed straightforward. Let's see if it works!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Word: _ _ _ _ _ _ _  : Lives = 10 , wrong guesses: \n",
+      "Enter letter: e\n",
+      "Word: _ _ _ _ _ _ e  : Lives = 10 , wrong guesses: \n",
+      "Enter letter: a\n",
+      "Word: _ _ _ _ _ _ e  : Lives = 9 , wrong guesses: a\n",
+      "Enter letter: i\n",
+      "Word: _ _ _ _ i _ e  : Lives = 9 , wrong guesses: a\n",
+      "Enter letter: o\n",
+      "Word: _ o _ _ i _ e  : Lives = 9 , wrong guesses: a\n",
+      "Enter letter: n\n",
+      "Word: _ o n _ i _ e  : Lives = 9 , wrong guesses: a\n",
+      "Enter letter: v\n",
+      "Word: _ o n _ i _ e  : Lives = 8 , wrong guesses: a v\n",
+      "Enter letter: t\n",
+      "Word: _ o n _ i _ e  : Lives = 7 , wrong guesses: a t v\n",
+      "Enter letter: s\n",
+      "Word: _ o n _ i _ e  : Lives = 6 , wrong guesses: a s t v\n",
+      "Enter letter: h\n",
+      "Word: _ o n _ i _ e  : Lives = 5 , wrong guesses: a h s t v\n",
+      "Enter letter: f\n",
+      "Word: _ o n f i _ e  : Lives = 5 , wrong guesses: a h s t v\n",
+      "Enter letter: b\n",
+      "Word: b o n f i _ e  : Lives = 5 , wrong guesses: a h s t v\n",
+      "Enter letter: r\n",
+      "You won! The word was bonfire\n"
      ]
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "play_game()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ _ _ _ _ _ _  : Lives = 10 , wrong guesses: \n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: e\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ _ _ _ _ _ e  : Lives = 10 , wrong guesses: \n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: a\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ _ _ _ _ _ e  : Lives = 9 , wrong guesses: a\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: i\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ _ _ _ i _ e  : Lives = 9 , wrong guesses: a\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: o\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o _ _ i _ e  : Lives = 9 , wrong guesses: a\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: n\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n _ i _ e  : Lives = 9 , wrong guesses: a\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: v\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n _ i _ e  : Lives = 8 , wrong guesses: a v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: t\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n _ i _ e  : Lives = 7 , wrong guesses: a t v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: s\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n _ i _ e  : Lives = 6 , wrong guesses: a s t v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: h\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n _ i _ e  : Lives = 5 , wrong guesses: a h s t v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: f\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: _ o n f i _ e  : Lives = 5 , wrong guesses: a h s t v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: b\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Word: b o n f i _ e  : Lives = 5 , wrong guesses: a h s t v\n"
-       ]
-      },
-      {
-       "name": "stdout",
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "Enter letter: r\n"
-       ]
-      },
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "You won! The word was bonfire\n"
-       ]
-      }
-     ],
-     "prompt_number": 22
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 17
     }
    ],
-   "metadata": {}
+   "source": [
+    "play_game()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.5.2+"
   }
- ]
-}
\ No newline at end of file
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}