Added MENACE learning game for Nim
authorNeil Smith <neil.git@njae.me.uk>
Mon, 27 Jul 2015 15:50:04 +0000 (16:50 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 27 Jul 2015 15:50:04 +0000 (16:50 +0100)
.gitignore [new file with mode: 0644]
SIGNED.md [new file with mode: 0644]
nim-menace-learning.ipynb [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0546add
--- /dev/null
@@ -0,0 +1,45 @@
+*.py[cod]
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+__pycache__
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# IPython
+.ipynb*
+
+# Sublime text
+*.sublime-workspace
+
+# Logs
+*.log
diff --git a/SIGNED.md b/SIGNED.md
new file mode 100644 (file)
index 0000000..7b81393
--- /dev/null
+++ b/SIGNED.md
@@ -0,0 +1,71 @@
+##### Signed by https://keybase.io/neilnjae
+```
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iQIcBAABAgAGBQJVtlMvAAoJEJPB2e07Pgbqi4QQAKLPu4LQCCX4SCSBMRqbmeUt
+zEn5Epz0RUjSBvfcwo44tbpNt/zHQKG3nff7xTQ9IgL2FX218fuGOkWALPgy94UU
+kYNdx00ZoaD/q7LLJyvXIaT+NVHIVqNvkD1Knjigoa0s7LgvmsfLfKJ+1ncU1ici
+OLSMBWPYZ9wIc3QSho57WMIr1j2Y6PPwgh8Cy+roB976kzph2Jzy/uF+ih0+S5fe
+9uy1ZHP7RM5VrRt9hxCCj8SeUVfC+J+UvTDYT2Bx8VVgJjLhpo1clXWtCO6Yn0OK
+62ZGtmu0lf4Bp2QYRzFc42kbuIVhxM00ZgP2MluQq31yuLJ2gE/tFYd3uib2m56E
+mONhXvdS5CjllHAf5VnjpbTBj3goTQ9VG4liA+AkzJCjx1RKkpnKb9IR50HURpMA
+hkmD8Nr1zmhzRo0OMFX95AotPRnhl3vPvLm8KYLWJflXFE+3ohefmEor/m06JYsd
+KagzwLUCsmz3E3OvrRSSR+O8PYbeLENEnf8uHFSWua5z3eUh9FQRCC8bYKhOfGb3
+PFuNkoNdSEwES2PTdcHQPtbqD408XfUoarIUfNr8dsjmDzAqNa1xxblcI7c/o+PH
+A1aln1HIbyPh3VqRX20XC/5BOsDYG5cL9Nk/ELrnhwV4KmFxlV89qP5M5o3G6RTj
+hFZVracXKEeZqwFEE3ks
+=94iF
+-----END PGP SIGNATURE-----
+
+```
+
+<!-- END SIGNATURES -->
+
+### Begin signed statement 
+
+#### Expect
+
+```
+size   exec  file                         contents                                                        
+             ./                                                                                           
+384            .gitignore                 a93de2ae5c2a47a38599751d1f914566569dfa09dd1778e207117db6c71421dd
+28564          nim-menace-learning.ipynb  e13cd187b5785516ade802d71674ff682da7315da1a5ef82d2fe66d3ff8675bf
+```
+
+#### Ignore
+
+```
+/SIGNED.md
+```
+
+#### Presets
+
+```
+git  # ignore .git and anything as described by .gitignore files
+```
+
+<!-- summarize version = 0.0.9 -->
+
+### End signed statement
+
+<hr>
+
+#### Notes
+
+With keybase you can sign any directory's contents, whether it's a git repo,
+source code distribution, or a personal documents folder. It aims to replace the drudgery of:
+
+  1. comparing a zipped file to a detached statement
+  2. downloading a public key
+  3. confirming it is in fact the author's by reviewing public statements they've made, using it
+
+All in one simple command:
+
+```bash
+keybase dir verify
+```
+
+There are lots of options, including assertions for automating your checks.
+
+For more info, check out https://keybase.io/docs/command_line/code_signing
\ No newline at end of file
diff --git a/nim-menace-learning.ipynb b/nim-menace-learning.ipynb
new file mode 100644 (file)
index 0000000..a400301
--- /dev/null
@@ -0,0 +1,1007 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# MENACE for Nim\n",
+    "http://shorttermmemoryloss.com/menace/\n",
+    "\n",
+    "https://en.wikipedia.org/wiki/Donald_Michie\n",
+    "\n",
+    "https://en.wikipedia.org/wiki/Nim\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Data structures\n",
+    "\n",
+    "* Menace state: a `list` of boxes, one for each number of starting stones. 1-based indexing.\n",
+    "* Menace box: a `list` of beads\n",
+    "* Game: a `dict`, containing a `list` of moves taken, a count of stones left, player names, and current player.\n",
+    "* Move: a `dict` of player, number\n",
+    "\n",
+    "# Operations\n",
+    "* Pick a random bead from a box\n",
+    "* Apply a move to a game\n",
+    "* Update Menace depending on win or loss"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 159,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import enum\n",
+    "import random\n",
+    "import collections"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 133,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "STARTING_STONES = 9\n",
+    "MAX_STONES_PER_MOVE = 3\n",
+    "INITIAL_BEADS_PER_MOVE = 4\n",
+    "PLAYER_POOL_SIZE = 10\n",
+    "TOURNAMENT_ROUNDS = 100"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "Players = enum.Enum('Player', 'player1 player2')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def new_menace(beads_per_move=INITIAL_BEADS_PER_MOVE, starting_stones=STARTING_STONES):\n",
+    "    return [[bead \n",
+    "             for beadset in [[m] * beads_per_move for m in range(1, MAX_STONES_PER_MOVE+1)]\n",
+    "             for bead in beadset\n",
+    "           ] for _ in range(starting_stones+1)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]"
+      ]
+     },
+     "execution_count": 42,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "new_menace()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "player1 = new_menace()\n",
+    "player2 = new_menace()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def new_game(first_player, second_player, stones=STARTING_STONES):\n",
+    "    return {'moves': [],\n",
+    "            'stones': stones,\n",
+    "            'current_player': Players.player1,\n",
+    "            Players.player1: first_player,\n",
+    "            Players.player2: second_player}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{<Player.player1: 1>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " 'stones': 9,\n",
+       " 'moves': [],\n",
+       " <Player.player2: 2>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " 'current_player': <Player.player1: 1>}"
+      ]
+     },
+     "execution_count": 46,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "game = new_game(player1, player2)\n",
+    "game"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 96,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def next_player(player):\n",
+    "    if player == Players.player1:\n",
+    "        return Players.player2\n",
+    "    else:\n",
+    "        return Players.player1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 97,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[<Player.player1: 1>, <Player.player2: 2>]"
+      ]
+     },
+     "execution_count": 97,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[p for p in Players]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 98,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Player.player2: 2>"
+      ]
+     },
+     "execution_count": 98,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "next_player(Players.player1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def pick_move(player, stones):\n",
+    "    move = stones + 1\n",
+    "    while move > stones:\n",
+    "        move = random.choice(player[stones])\n",
+    "    return move"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 70,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1"
+      ]
+     },
+     "execution_count": 70,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pick_move(player1, 9)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1"
+      ]
+     },
+     "execution_count": 85,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pick_move(player1, 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 114,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def apply_move(game, move):\n",
+    "    if move > game['stones']:\n",
+    "        raise Exception('Too many stones removed')\n",
+    "    game['stones'] -= move\n",
+    "    game['moves'].append((game['current_player'], move))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 90,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def game_finished(game):\n",
+    "    return game['stones'] == 0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def play_game(game):\n",
+    "    while not game_finished(game):\n",
+    "        move = pick_move(game[game['current_player']], game['stones'])\n",
+    "        apply_move(game, move)\n",
+    "        game['current_player'] = next_player(game['current_player'])\n",
+    "    return game"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 126,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{<Player.player1: 1>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " 'stones': 0,\n",
+       " 'moves': [(<Player.player1: 1>, 3),\n",
+       "  (<Player.player2: 2>, 3),\n",
+       "  (<Player.player1: 1>, 1),\n",
+       "  (<Player.player2: 2>, 2)],\n",
+       " <Player.player2: 2>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " 'current_player': <Player.player1: 1>}"
+      ]
+     },
+     "execution_count": 126,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "player1 = new_menace()\n",
+    "player2 = new_menace()\n",
+    "game = new_game(player1, player2)\n",
+    "play_game(game)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 151,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def update_players(game):\n",
+    "    stones = 0\n",
+    "    loser = game['moves'][-1][0]\n",
+    "    winner = next_player(loser)\n",
+    "    updating = loser\n",
+    "    for move in reversed(game['moves']):\n",
+    "        stones += move[1]\n",
+    "        if updating == loser:\n",
+    "            game[loser][stones].remove(move[1])\n",
+    "            if game[loser][stones].count(1) == 0:\n",
+    "                game[loser][stones].append(1)\n",
+    "            updating = winner\n",
+    "        else:\n",
+    "            game[winner][stones].append(move[1])\n",
+    "            updating = loser    \n",
+    "    return game[winner], game[loser]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 127,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "([[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]])"
+      ]
+     },
+     "execution_count": 127,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "player1, player2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 128,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "([[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 1],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3]],\n",
+       " [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]])"
+      ]
+     },
+     "execution_count": 128,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "update_players(game)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 129,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{<Player.player1: 1>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 1],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3]],\n",
+       " 'stones': 0,\n",
+       " 'moves': [(<Player.player1: 1>, 3),\n",
+       "  (<Player.player2: 2>, 3),\n",
+       "  (<Player.player1: 1>, 1),\n",
+       "  (<Player.player2: 2>, 2)],\n",
+       " <Player.player2: 2>: [[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       "  [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]],\n",
+       " 'current_player': <Player.player1: 1>}"
+      ]
+     },
+     "execution_count": 129,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "game"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 152,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "10"
+      ]
+     },
+     "execution_count": 152,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "player_pool = [new_menace() for _ in range(PLAYER_POOL_SIZE)]\n",
+    "len(player_pool)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 153,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],\n",
+       " [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]"
+      ]
+     },
+     "execution_count": 153,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "player_pool[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 165,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def show_player(player):\n",
+    "    show = ''\n",
+    "    for i, s in enumerate(player):\n",
+    "        show += \"{}: {}\\n\".format(i, collections.Counter(s))\n",
+    "    return show"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 167,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 15, 3: 4})\n",
+      "3: Counter({2: 22, 3: 2, 1: 1})\n",
+      "4: Counter({3: 79, 1: 1, 2: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 15, 3: 5})\n",
+      "7: Counter({2: 14, 3: 3, 1: 1})\n",
+      "8: Counter({3: 54, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_player(player_pool[0]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 169,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 15, 3: 4})\n",
+      "3: Counter({2: 22, 3: 2, 1: 1})\n",
+      "4: Counter({3: 79, 1: 1, 2: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 15, 3: 5})\n",
+      "7: Counter({2: 14, 3: 3, 1: 1})\n",
+      "8: Counter({3: 54, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 19, 3: 4, 2: 1})\n",
+      "3: Counter({2: 17, 1: 1})\n",
+      "4: Counter({3: 93, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 21})\n",
+      "7: Counter({2: 21, 1: 3})\n",
+      "8: Counter({3: 65, 1: 4})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 17, 3: 4, 2: 2})\n",
+      "3: Counter({2: 21, 3: 2, 1: 1})\n",
+      "4: Counter({3: 55, 1: 2})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 20, 3: 3, 2: 1})\n",
+      "7: Counter({2: 10, 1: 1})\n",
+      "8: Counter({3: 15, 1: 7})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 24, 3: 4, 2: 1})\n",
+      "3: Counter({2: 8, 3: 3, 1: 2})\n",
+      "4: Counter({3: 79, 1: 1, 2: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 22, 2: 3})\n",
+      "7: Counter({2: 19, 1: 1, 3: 1})\n",
+      "8: Counter({3: 49, 2: 2, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 19, 3: 4})\n",
+      "3: Counter({2: 17, 1: 2, 3: 1})\n",
+      "4: Counter({3: 91, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 25, 3: 3, 2: 1})\n",
+      "7: Counter({2: 10, 1: 1})\n",
+      "8: Counter({3: 57, 1: 2, 2: 2})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 12, 3: 4, 2: 1})\n",
+      "3: Counter({2: 14, 1: 1, 3: 1})\n",
+      "4: Counter({3: 88, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 7, 3: 2})\n",
+      "7: Counter({2: 8, 1: 1, 3: 1})\n",
+      "8: Counter({3: 57, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 13, 3: 4, 2: 2})\n",
+      "3: Counter({2: 33, 1: 1})\n",
+      "4: Counter({3: 90, 1: 1, 2: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 31})\n",
+      "7: Counter({2: 28, 1: 2, 3: 1})\n",
+      "8: Counter({3: 48, 1: 6, 2: 2})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 15, 3: 4, 2: 1})\n",
+      "3: Counter({2: 21, 1: 1, 3: 1})\n",
+      "4: Counter({3: 75, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 14, 3: 2})\n",
+      "7: Counter({2: 18, 1: 7, 3: 1})\n",
+      "8: Counter({3: 39, 1: 3, 2: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 21, 3: 4})\n",
+      "3: Counter({2: 21, 1: 2})\n",
+      "4: Counter({3: 64, 1: 2, 2: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 18, 2: 1})\n",
+      "7: Counter({2: 7, 1: 5})\n",
+      "8: Counter({3: 39, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 24, 3: 4, 2: 1})\n",
+      "3: Counter({2: 29, 1: 1})\n",
+      "4: Counter({3: 63, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 17, 2: 1})\n",
+      "7: Counter({2: 16, 1: 2})\n",
+      "8: Counter({3: 35, 1: 1, 2: 1})\n",
+      "9: Counter({1: 2})\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "for p in player_pool:\n",
+    "    print(show_player(p))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 197,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def play_tournament(no_of_players=PLAYER_POOL_SIZE, rounds=TOURNAMENT_ROUNDS, stones=STARTING_STONES):\n",
+    "    players = [new_menace(starting_stones=stones) for _ in range(no_of_players)]\n",
+    "    for r in range(rounds):\n",
+    "        random.shuffle(players)\n",
+    "        game = new_game(players[0], players[1], stones)\n",
+    "        play_game(game)\n",
+    "        update_players(game)\n",
+    "    return players"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 200,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 7, 3: 4, 2: 1})\n",
+      "3: Counter({2: 5, 1: 3, 3: 2})\n",
+      "4: Counter({3: 6, 1: 5, 2: 3})\n",
+      "5: Counter({1: 5, 2: 4, 3: 3})\n",
+      "6: Counter({1: 6, 3: 3, 2: 1})\n",
+      "7: Counter({1: 5, 3: 4, 2: 3})\n",
+      "8: Counter({1: 5, 2: 5, 3: 4})\n",
+      "9: Counter({2: 7, 1: 3, 3: 2})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 13, 3: 4, 2: 1})\n",
+      "3: Counter({2: 6, 1: 4, 3: 3})\n",
+      "4: Counter({3: 6, 1: 4, 2: 3})\n",
+      "5: Counter({2: 7, 1: 4, 3: 4})\n",
+      "6: Counter({1: 5, 3: 5, 2: 3})\n",
+      "7: Counter({1: 2, 2: 2, 3: 2})\n",
+      "8: Counter({3: 6, 1: 4, 2: 4})\n",
+      "9: Counter({2: 7, 3: 7, 1: 2})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 6, 3: 4, 2: 2})\n",
+      "3: Counter({2: 5, 3: 4, 1: 3})\n",
+      "4: Counter({2: 5, 3: 5, 1: 3})\n",
+      "5: Counter({1: 4, 2: 4, 3: 1})\n",
+      "6: Counter({1: 4, 2: 3, 3: 2})\n",
+      "7: Counter({1: 6, 2: 5, 3: 3})\n",
+      "8: Counter({2: 5, 3: 4, 1: 3})\n",
+      "9: Counter({2: 4, 1: 3, 3: 2})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 7, 3: 4, 2: 3})\n",
+      "3: Counter({2: 6, 3: 3, 1: 1})\n",
+      "4: Counter({3: 7, 1: 3, 2: 2})\n",
+      "5: Counter({2: 7, 3: 4, 1: 3})\n",
+      "6: Counter({2: 4, 3: 4, 1: 3})\n",
+      "7: Counter({3: 5, 1: 3, 2: 2})\n",
+      "8: Counter({1: 6, 3: 4, 2: 3})\n",
+      "9: Counter({1: 5, 3: 5, 2: 4})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 7, 3: 4, 2: 3})\n",
+      "3: Counter({2: 5, 1: 4, 3: 3})\n",
+      "4: Counter({1: 4, 3: 4, 2: 3})\n",
+      "5: Counter({2: 5, 1: 4, 3: 3})\n",
+      "6: Counter({3: 5, 1: 4, 2: 3})\n",
+      "7: Counter({1: 4, 2: 3, 3: 3})\n",
+      "8: Counter({3: 5, 1: 4, 2: 4})\n",
+      "9: Counter({3: 4, 2: 3, 1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 5, 3: 4, 2: 2})\n",
+      "3: Counter({2: 5, 1: 4, 3: 1})\n",
+      "4: Counter({1: 5, 3: 5, 2: 3})\n",
+      "5: Counter({1: 5, 2: 4, 3: 4})\n",
+      "6: Counter({1: 5, 2: 2, 3: 2})\n",
+      "7: Counter({1: 6, 3: 2, 2: 1})\n",
+      "8: Counter({2: 5, 3: 5, 1: 4})\n",
+      "9: Counter({2: 4, 3: 4, 1: 2})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 7, 3: 4, 2: 1})\n",
+      "3: Counter({2: 6, 1: 5, 3: 3})\n",
+      "4: Counter({1: 5, 2: 5, 3: 5})\n",
+      "5: Counter({1: 4, 2: 3, 3: 2})\n",
+      "6: Counter({1: 5, 3: 4, 2: 2})\n",
+      "7: Counter({3: 5, 1: 4, 2: 2})\n",
+      "8: Counter({2: 4, 3: 4, 1: 2})\n",
+      "9: Counter({3: 10, 2: 3, 1: 2})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 8, 3: 4, 2: 3})\n",
+      "3: Counter({2: 6, 1: 5, 3: 1})\n",
+      "4: Counter({3: 6, 1: 5, 2: 4})\n",
+      "5: Counter({3: 5, 1: 4, 2: 3})\n",
+      "6: Counter({3: 5, 1: 3, 2: 3})\n",
+      "7: Counter({1: 4, 2: 4, 3: 4})\n",
+      "8: Counter({2: 5, 3: 4, 1: 2})\n",
+      "9: Counter({2: 6, 3: 6, 1: 3})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 10, 3: 4, 2: 2})\n",
+      "3: Counter({2: 5, 1: 3, 3: 3})\n",
+      "4: Counter({3: 7, 1: 4, 2: 4})\n",
+      "5: Counter({2: 6, 1: 5, 3: 4})\n",
+      "6: Counter({1: 4, 2: 4, 3: 4})\n",
+      "7: Counter({3: 5, 1: 4, 2: 3})\n",
+      "8: Counter({1: 7, 3: 6, 2: 4})\n",
+      "9: Counter({2: 7, 1: 3, 3: 3})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 5, 3: 4, 2: 3})\n",
+      "3: Counter({2: 6, 3: 3, 1: 1})\n",
+      "4: Counter({3: 6, 2: 4, 1: 3})\n",
+      "5: Counter({3: 5, 1: 4, 2: 4})\n",
+      "6: Counter({3: 4, 1: 2, 2: 2})\n",
+      "7: Counter({1: 7, 2: 4, 3: 4})\n",
+      "8: Counter({1: 4, 2: 4, 3: 4})\n",
+      "9: Counter({1: 6, 2: 3, 3: 3})\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "players = play_tournament()\n",
+    "for p in players:\n",
+    "    print(show_player(p))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 201,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 19, 3: 4, 2: 2})\n",
+      "3: Counter({2: 22, 1: 1})\n",
+      "4: Counter({3: 50082, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 20, 2: 1, 3: 1})\n",
+      "7: Counter({2: 27, 1: 1, 3: 1})\n",
+      "8: Counter({3: 50026, 1: 2})\n",
+      "9: Counter({1: 1})\n",
+      "\n",
+      "0: Counter({1: 4, 2: 4, 3: 4})\n",
+      "1: Counter({2: 4, 3: 4, 1: 1})\n",
+      "2: Counter({1: 16, 3: 4, 2: 3})\n",
+      "3: Counter({2: 32, 1: 1, 3: 1})\n",
+      "4: Counter({3: 49843, 1: 1})\n",
+      "5: Counter({1: 1})\n",
+      "6: Counter({1: 24})\n",
+      "7: Counter({2: 23, 1: 2})\n",
+      "8: Counter({3: 49799, 1: 1})\n",
+      "9: Counter({1: 1})\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "players = play_tournament(no_of_players=2, rounds=100000)\n",
+    "for p in players:\n",
+    "    print(show_player(p))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "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.4.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}