{ "metadata": { "name": "", "signature": "sha256:8dfb2bb1cf596c711c837f4c7c2d8706f9dcacc1a0ffc3dc21c1d0fedd3fc6bf" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "#Putting both halves together\n", "We now have systems that can do both halves of the Hangman game. Now it's time to put them together so that we can get a machine to play itself. At the moment, let's concentrate on just the plumbing: let's get the two halves working together. In the next step, we'll think about different strategies and compare their effectiveness.\n", "\n", "The word of this section is \"encapsulation.\" \n", "\n", "First, a change in terminology. We'll call a `player` the thing that makes the guesses (the guesser player from before). We'll call a `game` the thing that handles receiving guesses, updating `discovered` words, updating lives and all of that. That's what was the setting player from before, but without the bit about picking a random word. We'll have the `game` accept the `target` as a parameter, so that we can test everything more easily (if we know what word the `player` is trying to guess, we can predict what it should do).\n", "\n", "Back to encapsulation.\n", "\n", "We want to bundle all the state information for a `game` into one 'thing' so that we don't need to worry about global variables. We will also want to bundle up everything to do with a `player` into one 'thing' so we can tell the game about it. For the `player`, the thing will include both any state it needs and the definition of that `player`'s guessing strategy. We're also going to have a bunch of related players, all doing much the same thing but with different strategies.\n", "\n", "In this case, objects seem like a natural fit.\n", "\n", "(Insert Neil's aikido instructor story here.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Object-orientation in Python\n", "There are a few things to remember about object orientation in Python.\n", "\n", "1. It's an ugly kludge that was bolted on long after the language was defined.\n", "\n", "2. `self` needs to be passed in to all object methods as the first parameter, though it doesn't appear when you call the method.\n", "\n", "3. Use `self.whatever` to refer to the instance variable `whatever`\n", "\n", "4. Use `self.however(arg1, arg2)` when one method calls another in the same object.\n", "\n", "Apart from that, it's pretty straightforward." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import re\n", "import random\n", "import string\n", "import collections" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 43 }, { "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": 44 }, { "cell_type": "code", "collapsed": false, "input": [ "STARTING_LIVES = 10" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 45 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is pretty much the same code as for the `setter` part, just with plenty of `self` statements scatter around. A few things to note:\n", "\n", "* `initialise()` is now named `__init__()` (note the double underscores fore and aft).\n", "* `player` and `lives` are parameters to the `game`, but with default values.\n", "* I've added two new flags, `game_won` and `game_lost`.\n", "* `do_turn` asks the player for a guess, if there is a player.\n", "* The `guess()` method of the `player` is passed the `lives`, in case the guess should change depending on the progress of the game (the `player` can always ignore it).\n", "* After a guess has been processed, `do_turn` has a few more statements to set the relevant flags to represent the state of the game.\n", "* `report_on_game()` has been added for when the game is being played against a human." ] }, { "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", " self.do_turn()\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": 46 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's test it!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 47 }, { "cell_type": "code", "collapsed": false, "input": [ "g.target" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 48, "text": [ "'distension'" ] } ], "prompt_number": 48 }, { "cell_type": "code", "collapsed": false, "input": [ "g.discovered" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 49, "text": [ "['_', '_', '_', '_', '_', '_', '_', '_', '_', '_']" ] } ], "prompt_number": 49 }, { "cell_type": "code", "collapsed": false, "input": [ "g.do_turn()" ], "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" ] } ], "prompt_number": 50 }, { "cell_type": "code", "collapsed": false, "input": [ "g.lives" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 51, "text": [ "10" ] } ], "prompt_number": 51 }, { "cell_type": "code", "collapsed": false, "input": [ "g.wrong_letters" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 52, "text": [ "[]" ] } ], "prompt_number": 52 }, { "cell_type": "code", "collapsed": false, "input": [ "g.do_turn()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ _ _ e _ _ _ _ _ : Lives = 10 , wrong guesses: \n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: q\n" ] } ], "prompt_number": 53 }, { "cell_type": "code", "collapsed": false, "input": [ "g.lives" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 54, "text": [ "9" ] } ], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": [ "g.discovered" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 55, "text": [ "['_', '_', '_', '_', 'e', '_', '_', '_', '_', '_']" ] } ], "prompt_number": 55 }, { "cell_type": "code", "collapsed": false, "input": [ "g.wrong_letters" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 56, "text": [ "['q']" ] } ], "prompt_number": 56 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS))\n", "g.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 _ e _ _ _ _ e : Lives = 10 , wrong guesses: \n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: x\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 9 , wrong guesses: x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: s\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 8 , wrong guesses: s x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: l\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 7 , wrong guesses: l s x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: t\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 6 , wrong guesses: l s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: m\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 5 , wrong guesses: l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: h\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 4 , wrong guesses: h l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: i\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 3 , wrong guesses: h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: a\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ _ _ e : Lives = 2 , wrong guesses: a h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: o\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ o _ e : Lives = 2 , wrong guesses: a h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: n\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e _ _ o n e : Lives = 2 , wrong guesses: a h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e _ e r _ o n e : Lives = 2 , wrong guesses: a h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: v\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: e v e r _ o n e : Lives = 2 , wrong guesses: a h i l m s t x\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: y\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "You won! The word was everyone\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 57, "text": [ "True" ] } ], "prompt_number": 57 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS))\n", "g.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: q\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ _ _ _ _ _ _ _ : Lives = 9 , wrong guesses: q\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: z\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ _ _ _ _ _ _ _ : Lives = 8 , wrong guesses: q z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: x\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ _ _ _ _ _ _ _ : Lives = 7 , wrong guesses: q x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: e\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ _ _ _ _ _ _ _ : Lives = 6 , wrong guesses: e q x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: a\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ _ _ _ _ _ : Lives = 6 , wrong guesses: e q x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: v\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ _ _ _ _ _ : Lives = 5 , wrong guesses: e q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: b\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ _ _ _ _ _ : Lives = 4 , wrong guesses: b e q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: k\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ k _ k _ _ : Lives = 4 , wrong guesses: b e q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: l\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ k _ k _ _ : Lives = 3 , wrong guesses: b e l q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: j\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ k _ k _ _ : Lives = 2 , wrong guesses: b e j l q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: p\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Word: _ _ a _ k _ k _ _ : Lives = 1 , wrong guesses: b e j l p q v x z\n" ] }, { "name": "stdout", "output_type": "stream", "stream": "stdout", "text": [ "Enter letter: d\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "You lost. The word was sharkskin\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 58, "text": [ "False" ] } ], "prompt_number": 58 }, { "cell_type": "code", "collapsed": false, "input": [ "g.target" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 59, "text": [ "'sharkskin'" ] } ], "prompt_number": 59 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Player objects\n", "Let's work ourselves gently into this.\n", "\n", "In the first instance, the only thing a `player` needs is to respond to the `guess` method. Let's make objects with just this method. Let's even make it simpler than the player from the `guesser` stage, and have it just guess letters in alphabetical order." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class PlayerAlphabetical:\n", " def guess(self, discovered, missed, lives):\n", " return [l for l in string.ascii_lowercase if l not in discovered + missed][0]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ "That wasn't too hard, was it?\n", "\n", "Let's use it to play a game." ] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerAlphabetical())" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 69 }, { "cell_type": "code", "collapsed": false, "input": [ "g.play_game()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 70, "text": [ "False" ] } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "g.discovered" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 71, "text": [ "['c', 'e', '_', '_', 'i', 'f', 'i', 'c', 'a', '_', 'e', '_']" ] } ], "prompt_number": 71 }, { "cell_type": "code", "collapsed": false, "input": [ "g.target" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 72, "text": [ "'certificates'" ] } ], "prompt_number": 72 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bored with looking at all the state of the game with different cells. Let's have a `print()` statement that tells us what we need." ] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerAlphabetical())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: turnoffs ; Discovered: ['_', '_', '_', '_', '_', 'f', 'f', '_'] ; Lives remaining: 0\n" ] } ], "prompt_number": 74 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Another player\n", "Let's reimplement our player that does letters in frequency order. Again, this is essentially code reused from earlier." ] }, { "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()]\n", "\n", "class PlayerFreqOrdered:\n", " def guess(self, discovered, missed, lives):\n", " return [l for l in LETTERS_IN_ORDER if l not in discovered + missed][0]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 76 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: cartons ; Discovered: ['c', 'a', 'r', 't', 'o', 'n', 's'] ; Lives remaining: 2\n" ] } ], "prompt_number": 77 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: douching ; Discovered: ['d', 'o', 'u', 'c', 'h', 'i', 'n', '_'] ; Lives remaining: 0\n" ] } ], "prompt_number": 78 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: minimisation ; Discovered: ['m', 'i', 'n', 'i', 'm', 'i', 's', 'a', 't', 'i', 'o', 'n'] ; Lives remaining: 4\n" ] } ], "prompt_number": 79 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Player subclasses and inheritance\n", "Time to DRY the code a little. Both of these players (`PlayerAlphabetical` and `PlayerFreqOrdered`) are essentially the same. The only difference is the set of letters used in the middle of the `guess` method. \n", "\n", "Let's create a generic \"letters in a fixed order\" class that has that implementation of `guess` and is passed in a set of letters in order. The two players we already have are subclasses of that, where we have pre-packaged letter orders.\n", "\n", "Here's the generic player. Note that the ordered letters are passed in as a parameter to the `__init__()` method, and `guess()` uses that letter sequence." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class PlayerFixedOrder:\n", " def __init__(self, ordered_letters):\n", " self.ordered_letters = ordered_letters\n", " \n", " def guess(self, discovered, missed, lives):\n", " return [l for l in self.ordered_letters if l not in discovered + missed][0]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 85 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now specify the subclasses, using the fixed order. The initialisation of the subclasses now takes no additional parameter, but we pass the hardcoded order to the superclass's `__init__()`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class PlayerAlphabetical(PlayerFixedOrder):\n", " def __init__(self):\n", " super().__init__(string.ascii_lowercase)\n", "\n", "class PlayerFreqOrdered(PlayerFixedOrder):\n", " def __init__(self):\n", " super().__init__(LETTERS_IN_ORDER)\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 86 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Does it work?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: yogi ; Discovered: ['_', 'o', '_', 'i'] ; Lives remaining: 0\n" ] } ], "prompt_number": 87 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: slimmest ; Discovered: ['s', 'l', 'i', 'm', 'm', 'e', 's', 't'] ; Lives remaining: 3\n" ] } ], "prompt_number": 88 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerAlphabetical())\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: diseases ; Discovered: ['d', 'i', '_', 'e', 'a', '_', 'e', '_'] ; Lives remaining: 0\n" ] } ], "prompt_number": 89 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Can we use the generic version directly?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFixedOrder(list(reversed(string.ascii_lowercase))))\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: pardon ; Discovered: ['p', '_', 'r', '_', 'o', 'n'] ; Lives remaining: 0\n" ] } ], "prompt_number": 90 }, { "cell_type": "code", "collapsed": false, "input": [ "g = Game(random.choice(WORDS), player=PlayerFixedOrder(list(reversed(string.ascii_lowercase))))\n", "g.play_game()\n", "print('Target:', g.target, '; Discovered:', g.discovered, '; Lives remaining:', g.lives)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Target: grouchier ; Discovered: ['_', 'r', 'o', 'u', '_', '_', '_', '_', 'r'] ; Lives remaining: 0\n" ] } ], "prompt_number": 91 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Mass gaming\n", "Now we can get machines playing each other, we get get them playing *lots* of games and just tell us the summaries. \n", "\n", "Which of these three methods (alphabetical, frequency ordered, reverse alphabetical) is the best? Let's get each player to play 100 random games and see which gets the most wins." ] }, { "cell_type": "code", "collapsed": false, "input": [ "wins = 0\n", "for _ in range(1000):\n", " g = Game(random.choice(WORDS), player=PlayerAlphabetical())\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": [ "49\n" ] } ], "prompt_number": 92 }, { "cell_type": "code", "collapsed": false, "input": [ "wins = 0\n", "for _ in range(1000):\n", " g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\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": [ "309\n" ] } ], "prompt_number": 96 }, { "cell_type": "code", "collapsed": false, "input": [ "wins = 0\n", "for _ in range(1000):\n", " g = Game(random.choice(WORDS), player=PlayerFixedOrder(list(reversed(string.ascii_lowercase))))\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": [ "6\n" ] } ], "prompt_number": 94 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Frequency ordered is much better than the others, but still only wins about 30% of the time. I'm sure we can do better.\n", "\n", "That's the next part..." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }