{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The Devil and the Coin Flip Game\n",
    "\n",
    "If the Devil ever challenges me to a [fiddle contest](https://en.wikipedia.org/wiki/The_Devil_Went_Down_to_Georgia), I'm going down. But here is a contest where I'd have a better chance:\n",
    "\n",
    "> *You're playing a game with the Devil, with your soul at stake. You're sitting at a circular table which has 4 coins, arranged in a diamond, at the 12, 3, 6, and 9 o'clock positions. You are blindfolded, and can never see the coins or the table.*\n",
    "\n",
    "> *Your goal is to get all 4 coins showing heads, by telling the devil the position(s) of some coins to flip. We call this a \"move\" on your part. The Devil must faithfully perform the requested flips, but may first sneakily rotate the table any number of quarter-turns, so that the coins are in different positions. You keep making moves, and the Devil keeps rotating and flipping, until all 4 coins show heads.*\n",
    "\n",
    "> *Example: You tell the Devil to flip the 12 o'clock and 6 o'clock positions. The devil might rotate the table a quarter turn clockwiae, and then flip the coins that have moved into the 12 o'clock and 6 o'clock positions (which were formerly at 3 o'clock and 9 o'clock).  Or the Devil could have made any other rotation before flipping.*\n",
    "\n",
    "> *What is a shortest sequence of moves that is **guaranteed** to win, no matter what the initial state of the coins, and no matter what rotations the Devil applies?*\n",
    "\n",
    "# Analysis\n",
    "\n",
    "- We're looking for a \"shortest sequence of moves\" that reaches a goal. That's a [shortest path search problem](https://en.wikipedia.org/wiki/Shortest_path_problem). I've done that before.\n",
    "- Since the Devil gets to make moves too, you might think that this is a [minimax](https://en.wikipedia.org/wiki/Minimax) problem: that we should choose the move that leads to the shortest path, given that the Devil has the option of making moves that lead to the longest path.\n",
    "- But minimax only works when you know what moves the opponent is making: he did *that*, so I'll do *this*. In this problem the player is blinfolded; that makes it a [partially observable problem](https://en.wikipedia.org/wiki/Partially_observable_system) (in this case, not observable at all, but we still say \"partially\").\n",
    "- In such problems, we don't know for sure the true state of the world before or after any move. So we should represent what *is* known: *the set of states that we believe to be possible*. We call this a *belief state*. At the start of the game, each of the four coins could be either heads or tails, so that's 2<sup>4</sup> = 16 possibilities in the initial belief state:\n",
    "       {HHHH, HHHT, HHTH, HHTT, HTHH, HTHT, HTTH, HTTT, \n",
    "        THHH, THHT, THTH, THTT, TTHH, TTHT, TTTH, TTTT}\n",
    "- So we have a single-agent shortest path search in the space of belief states (not the space of physical states of the coins). We search for a path from the inital belief state to the goal belief state, which is `{HHHH}`.\n",
    "- A move updates the belief state as follows: for every four-coin sequence in the current belief state, rotate it in every possible way, and then flip the coins specified by the position(s) in the move. Collect all these results together to form the new belief state. The search space is small (just 2<sup>16</sup> possible belief states), so run time will be fast. \n",
    "- I'll Keep It Simple, and not worry about rotational symmetry  (although we'll come back to that later).\n",
    "\n",
    "\n",
    "# Basic Data Structures and Functions\n",
    "\n",
    "What data structures will I be dealing with?\n",
    "\n",
    "- `Coins`: a *coin sequence* (four coins, in order, on the table) is represented as a `str` of four characters, such as `'HTTT'`. \n",
    "- `Belief`: a *belief state* is a `frozenset` of `Coins` (frozen so it can be hashed), like `{'HHHT', 'TTTH'}`.\n",
    "- `Position`: an integer index into the coin sequence; position `0` selects the `H` in `'HTTT'`\n",
    "and corresponds to the 12 o'clock position; position 1 corresponds to 3 o'clock, and so on.\n",
    "- `Move`: a set of positions to flip, such as `{0, 2}`. \n",
    "- `Strategy`: an ordered list of moves. A\n",
    "blindfolded player has no feedback, there thus no  decision points in the strategy. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import deque\n",
    "from itertools   import product, combinations, chain\n",
    "import random\n",
    "\n",
    "Coins     = ''.join   # A coin sequence; a str: 'HHHT'.\n",
    "Belief    = frozenset # A set of possible coin sequences: {'HHHT', 'TTTH'}.\n",
    "Position  = int       # An index into a coin sequence.\n",
    "Move      = set       # A set of positions to flip: {0, 2}\n",
    "Strategy  = list      # A list of Moves: [{0, 1, 2, 3}, {0, 2}, ...]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What basic functions do I need to manipulate these data structures?\n",
    "\n",
    "- `all_moves()`: returns a list of every possible move a player can make.\n",
    "- `all_coins()`: returns a belief state consisting of the set of all 16 possible coin sequences: `{'HHHH', 'HHHT', ...}`.\n",
    "- `rotations(coins)`: returns a belief set of all 4 rotations of the coin sequence.\n",
    "- `flip(coins, move)`: flips the specified positions within the coin sequence.\n",
    " (But leave `'HHHH'` alone, because it ends the game.)\n",
    "- `update(belief, move)`: returns an updated belief state: all the coin sequences that could result from any rotation followed by the specified flips.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def all_moves() -> [Move]: \n",
    "    \"List of all possible moves.\"\n",
    "    return [set(m) for m in powerset(range(4))]\n",
    "\n",
    "def all_coins() -> Belief:\n",
    "    \"The belief set consisting of all possible coin sequences.\"\n",
    "    return Belief(map(Coins, product('HT', repeat=4)))\n",
    "\n",
    "def rotations(coins) -> {Coins}: \n",
    "    \"A set of all possible rotations of a coin sequence.\"\n",
    "    return {coins[r:] + coins[:r] for r in range(4)}\n",
    "\n",
    "def flip(coins, move) -> Coins:\n",
    "    \"Flip the coins in the positions specified by the move (but leave 'HHHH' alone).\"\n",
    "    if 'T' not in coins: return coins # Don't flip 'HHHH'\n",
    "    coins = list(coins) # Need a mutable sequence\n",
    "    for i in move:\n",
    "        coins[i] = ('H' if coins[i] == 'T' else 'T')\n",
    "    return Coins(coins)\n",
    "\n",
    "def update(belief, move) -> Belief:\n",
    "    \"Update belief: consider all possible rotations, then flip.\"\n",
    "    return Belief(flip(c, move)\n",
    "                  for coins in belief\n",
    "                  for c in rotations(coins))\n",
    "\n",
    "flatten = chain.from_iterable\n",
    "\n",
    "def powerset(iterable): \n",
    "    \"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)\"\n",
    "    # https://docs.python.org/3/library/itertools.html#itertools-recipes\n",
    "    s = list(iterable)\n",
    "    return flatten(combinations(s, r) for r in range(len(s) + 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try out these functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[set(),\n",
       " {0},\n",
       " {1},\n",
       " {2},\n",
       " {3},\n",
       " {0, 1},\n",
       " {0, 2},\n",
       " {0, 3},\n",
       " {1, 2},\n",
       " {1, 3},\n",
       " {2, 3},\n",
       " {0, 1, 2},\n",
       " {0, 1, 3},\n",
       " {0, 2, 3},\n",
       " {1, 2, 3},\n",
       " {0, 1, 2, 3}]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_moves()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'HHHH',\n",
       "           'HHHT',\n",
       "           'HHTH',\n",
       "           'HHTT',\n",
       "           'HTHH',\n",
       "           'HTHT',\n",
       "           'HTTH',\n",
       "           'HTTT',\n",
       "           'THHH',\n",
       "           'THHT',\n",
       "           'THTH',\n",
       "           'THTT',\n",
       "           'TTHH',\n",
       "           'TTHT',\n",
       "           'TTTH',\n",
       "           'TTTT'})"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_coins()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'HHHT', 'HHTH', 'HTHH', 'THHH'}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rotations('HHHT')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'THTT'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "flip('HHHT', {0, 2})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are 16 coin sequences in the `all_coins` belief state. If we update this belief state by flipping all 4 positions, we should get a new belief state where we have eliminated the possibility of 4 tails, leaving 15 possible coin sequences:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'HHHH',\n",
       "           'HHHT',\n",
       "           'HHTH',\n",
       "           'HHTT',\n",
       "           'HTHH',\n",
       "           'HTHT',\n",
       "           'HTTH',\n",
       "           'HTTT',\n",
       "           'THHH',\n",
       "           'THHT',\n",
       "           'THTH',\n",
       "           'THTT',\n",
       "           'TTHH',\n",
       "           'TTHT',\n",
       "           'TTTH'})"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "update(all_coins(), {0, 1, 2, 3})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(powerset([1,2,3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Everything looks good so far. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Search for a Winning Strategy\n",
    "\n",
    "The generic function `search` does a breadth-first search starting\n",
    "from a `start` state, looking for a `goal`  state, considering possible `actions` at each turn,\n",
    "and computing the `result` of each action (`result` is a function such that `result(state, action)` returns the new state that results from executing the action in the current state). `search` works by keeping a `queue` of unexplored possibilities, where each entry in the queue is a pair consisting of a *strategy* (sequence of moves) and a *state* that that strategy leads to. We also keep track of a set of `explored` states, so that we don't repeat ourselves. I've defined this function (or one just like it) multiple times before, for use in different search problems."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def search(start, goal, actions, result) -> Strategy:\n",
    "    \"Breadth-first search from start state to goal; return strategy to get to goal.\"\n",
    "    explored = set()\n",
    "    queue = deque([(Strategy(), start)])\n",
    "    while queue:\n",
    "        (strategy, state) = queue.popleft()\n",
    "        if state == goal:\n",
    "            return strategy\n",
    "        for action in actions:\n",
    "            state2 = result(state, action)\n",
    "            if state2 not in explored:\n",
    "                queue.append((strategy + [action], state2))\n",
    "                explored.add(state2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `search` doesn't know anything about belief states&mdash;it is designed to work on plain-old physical states of the world. But amazingly, we can still use it to search over belief states: it just works, as long as we properly specify the start state, the goal state, and the means of moving between states.\n",
    "\n",
    "The `coin_search` function calls  `search` to solve our specific problem:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0, 1},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0, 1},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3}]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def coin_search() -> Strategy: \n",
    "    \"Use `search` to solve the Coin Flip problem.\"\n",
    "    return search(start=all_coins(), goal={'HHHH'}, actions=all_moves(), result=update)\n",
    "\n",
    "coin_search()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's a 15-move strategy that is guaranteed to lead to a win. **Stop  here** if all you want is the answer to the puzzle. \n",
    "\n",
    "----\n",
    "\n",
    "Or you can continue on ...\n",
    "\n",
    "# Verifying the Winning Strategy\n",
    "\n",
    "I don't have a proof, but I have some evidence that this strategy works:\n",
    "- Exploring with paper and pencil, it looks good. \n",
    "- A colleague did the puzzle and got the same answer. \n",
    "- It passes the `winning` test below.\n",
    "\n",
    "The call `winning(strategy, k)` plays the strategy *k* times against a Devil that chooses starting positions and rotations at random. Note this is dealing with concrete, individual states of the world, like `HTHH`, not belief states. If `winning` returns `False`, then the strategy is *definitely* flawed. If it returns `True`, then the strategy is *probably* good&mdash;it won *k* times in a row&mdash;but that does not prove it will win every time  (and either way `winning` makes no claims about being a *shortest* strategy)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def winning(strategy, k=100000) -> bool:\n",
    "    \"Is this a winning strategy? A probabilistic algorithm.\"\n",
    "    return all(play(strategy) == 'HHHH'\n",
    "               for _ in range(k))\n",
    "\n",
    "def play(strategy, starting_coins=list(all_coins())) -> Coins:\n",
    "    \"Play strategy for one game against a random Devil; return final state of coins.\"\n",
    "    coins = random.choice(starting_coins)\n",
    "    for move in strategy:\n",
    "        if 'T' not in coins: return coins\n",
    "        coins = random.choice(list(rotations(coins)))\n",
    "        coins = flip(coins, move)\n",
    "    return coins\n",
    "\n",
    "winning(strategy=coin_search())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "# Canonical Coin Sequences\n",
    "\n",
    "Consider these coin sequences: `{'HHHT', 'HHTH', 'HTHH', 'THHH'}`. In a sense, these are all the same: they all denote the same sequence of coins with the table rotated to different degrees. Since the devil is free to rotate the table any amount at any time, we could be justified in treating all four of these as equivalent, and collapsing them into one representative member. I will redefine `Coins` so that is stil takes an iterable of `'H'` or `'T'` characters and joins them into a `str`, but I will make it consider all possible rotations of the string and (arbitraily) choose the one that comes first in alphabetical order (which would be `'HHHT'` for the four coin sequences mentioned here)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def Coins(coins) -> str: \n",
    "    \"The canonical representation (after rotation) of the 'H'/'T' sequence.\"\n",
    "    return min(rotations(''.join(coins)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "assert Coins('HHHT') == Coins('HHTH') == Coins('HTHH') == Coins('THHH') == 'HHHT'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With `Coins` redefined, the result of `all_coins()` is different:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'HHHH', 'HHHT', 'HHTT', 'HTHT', 'HTTT', 'TTTT'})"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_coins()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The starting belief set is down from 16  to 6, namely  4 heads, 3 heads, 2 adjacent heads, 2 opposite heads, 1 head, and no heads, respectively. \n",
    "\n",
    "Let's make sure we didn't break anything:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0, 1},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3},\n",
       " {0, 1},\n",
       " {0, 1, 2, 3},\n",
       " {0, 2},\n",
       " {0, 1, 2, 3}]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "coin_search()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Winning Strategies for *N* Coins\n",
    "\n",
    "What if there are 3 coins on the table arranged in a triangle? Or 6 coins in a hexagon? To answer that, I'll generalize all the functions that have a \"4\" in them: `all_moves, all_coins`, `rotations` and `coin_search`.\n",
    "\n",
    "Computing `all_coins(N)` is easy; just take the product, and canonicalize each one with the new definition of `Coins`. For `all_moves(N)` I want canonicalized moves: the moves `{0}` and `{1}` should be considered the same, since they both say \"flip one coin.\" To get that, look at the canonicalized set of `all_coins(N)`, and for each one pull out  the set of positions that have an `H` in them and flip those positions. (The positions with a `T` should be symmetric, so we don't need them as well.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def all_moves(N=4) -> [Move]:\n",
    "    \"All canonical moves for a sequence of N coins.\"\n",
    "    return [set(i for i in range(N) if coins[i] == 'H')\n",
    "            for coins in sorted(all_coins(N))]\n",
    "\n",
    "def all_coins(N=4) -> Belief:\n",
    "    \"Return the belief set consisting of all possible coin sequences.\"\n",
    "    return Belief(map(Coins, product('HT', repeat=N)))\n",
    "\n",
    "def rotations(coins) -> {Coins}: \n",
    "    \"A list of all possible rotations of a coin sequence.\"\n",
    "    return {coins[r:] + coins[:r] for r in range(len(coins))}\n",
    "\n",
    "def coin_search(N=4) -> Strategy: \n",
    "    \"Use the generic `search` function to solve the Coin Flip problem.\"\n",
    "    return search(start=all_coins(N), goal={'H' * N}, actions=all_moves(N), result=update)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's test the new definitions and make sure we haven't broken `update` and `coin_search`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "assert all_moves(3) == [{0, 1, 2}, {0, 1}, {0}, set()]\n",
    "assert all_moves(4) == [{0, 1, 2, 3}, {0, 1, 2}, {0, 1}, {0, 2}, {0}, set()]\n",
    "\n",
    "assert all_coins(4) == {'HHHH', 'HHHT', 'HHTT', 'HTHT', 'HTTT', 'TTTT'}\n",
    "assert all_coins(5) == {'HHHHH','HHHHT', 'HHHTT','HHTHT','HHTTT', 'HTHTT', 'HTTTT', 'TTTTT'}\n",
    "\n",
    "assert rotations('HHHHHT') == {'HHHHHT', 'HHHHTH', 'HHHTHH', 'HHTHHH', 'HTHHHH', 'THHHHH'}\n",
    "assert update({'TTTTTTT'}, {3}) == {'HTTTTTT'}\n",
    "assert (update(rotations('HHHHHT'), {0}) == update({'HHTHHH'}, {1}) == update({'THHHHH'}, {2})\n",
    "        == {'HHHHHH', 'HHHHTT', 'HHHTHT', 'HHTHHT'})\n",
    "\n",
    "assert coin_search(4) == [\n",
    " {0, 1, 2, 3},\n",
    " {0, 2},\n",
    " {0, 1, 2, 3},\n",
    " {0, 1},\n",
    " {0, 1, 2, 3},\n",
    " {0, 2},\n",
    " {0, 1, 2, 3},\n",
    " {0, 1, 2},\n",
    " {0, 1, 2, 3},\n",
    " {0, 2},\n",
    " {0, 1, 2, 3},\n",
    " {0, 1},\n",
    " {0, 1, 2, 3},\n",
    " {0, 2},\n",
    " {0, 1, 2, 3}]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How many distinct canonical coin sequences are there for up to a dozen coins?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 2,\n",
       " 2: 3,\n",
       " 3: 4,\n",
       " 4: 6,\n",
       " 5: 8,\n",
       " 6: 14,\n",
       " 7: 20,\n",
       " 8: 36,\n",
       " 9: 60,\n",
       " 10: 108,\n",
       " 11: 188,\n",
       " 12: 352}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{N: len(all_coins(N))\n",
    " for N in range(1, 13)}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On the one hand this is encouraging; there are only 352 canonical coin sequences of length 10, far less than the 4,096 non-canonical squences. On the other hand, it is discouraging; since we are searching over belief states, that would be 2<sup>352</sup> belief states, which is nore than a googol. However, we should be able to easily handle up to N=7, because 2<sup>20</sup> is only a million.\n",
    "\n",
    "# Winning Strategies for 1 to 7 Coins"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: [{0}],\n",
       " 2: [{0, 1}, {0}, {0, 1}],\n",
       " 3: None,\n",
       " 4: [{0, 1, 2, 3},\n",
       "  {0, 2},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 1},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 2},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 1, 2},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 2},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 1},\n",
       "  {0, 1, 2, 3},\n",
       "  {0, 2},\n",
       "  {0, 1, 2, 3}],\n",
       " 5: None,\n",
       " 6: None,\n",
       " 7: None}"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{N: coin_search(N) for N in range(1, 8)}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Too bad; there are no winning strategies for N = 3, 5, 6, or 7.  \n",
    "\n",
    "There *are* winning strategies for N = 1, 2, 4; they have lengths 1, 3, 15, respectively. Hmm. That suggests ...\n",
    "\n",
    "# A Conjecture\n",
    "\n",
    "> For every *N* that is a power of 2, there will be a shortest winning strategy of length 2<sup>*N*</sup> - 1.\n",
    "\n",
    "> For every *N* that is not a power of 2, there will be no winning strategy. \n",
    "\n",
    "# Winning Strategy for 8 Coins\n",
    "\n",
    "For N = 8, there are 2<sup>36</sup> = 69 billion belief states and if the conjecture is true there will be a shortest winning strategy with 255 steps. All the computations up to now have been instantaneous, but this one should take a few minutes. Let's see:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1min 18s, sys: 118 ms, total: 1min 18s\n",
      "Wall time: 1min 18s\n"
     ]
    }
   ],
   "source": [
    "%time strategy = coin_search(8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "255"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(strategy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Eureka!** That's evidence in favor of the conjecture. But not proof. And it leaves many questions unanswered:\n",
    "- Can you show there are no winning strategies for *N* = 9, 10, 11, ...?\n",
    "- Can you prove there are no winning strategies for any *N* that is not a power of 2?\n",
    "- Can you find a winning strategy of length 65,535 for *N* = 16 and verify that it works?\n",
    "- Can you generate a winning strategy for any power of 2 (without proving it is shortest)?\n",
    "- Can you prove there are no shorter winning strategies for *N* = 16?\n",
    "- Can you prove the conjecture in general?\n",
    "- Can you *understand* and *explain* how the strategy works, rather than just listing the moves?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Visualizing Strategies\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def show(moves, N=4):\n",
    "    \"For each move, print the move number, move, and belief state.\"\n",
    "    belief = all_coins(N)\n",
    "    order = sorted(belief)\n",
    "    for (i, move) in enumerate(moves, 1):\n",
    "        belief = update(belief, move)\n",
    "        print('{:3} | {:8} | {}'.format(\n",
    "              i, movestr(move, N), beliefstr(belief, order)))\n",
    "\n",
    "def beliefstr(belief, order) -> str: \n",
    "    return join(((coins if coins in belief else ' ' * len(coins))\n",
    "                 for coins in order), ' ')\n",
    "\n",
    "def movestr(move, N) -> str: \n",
    "    return join((i if i in move else ' ') \n",
    "                for i in range(N))\n",
    "    \n",
    "def join(items, sep='') -> str: \n",
    "    return sep.join(map(str, items))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following tables shows how moves change the belief state:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1 | 01       | HH HT   \n",
      "  2 | 0        | HH    TT\n",
      "  3 | 01       | HH      \n"
     ]
    }
   ],
   "source": [
    "show(coin_search(2), 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1 | 0123     | HHHH HHHT HHTT HTHT HTTT     \n",
      "  2 | 0 2      | HHHH HHHT HHTT      HTTT TTTT\n",
      "  3 | 0123     | HHHH HHHT HHTT      HTTT     \n",
      "  4 | 01       | HHHH HHHT      HTHT HTTT TTTT\n",
      "  5 | 0123     | HHHH HHHT      HTHT HTTT     \n",
      "  6 | 0 2      | HHHH HHHT           HTTT TTTT\n",
      "  7 | 0123     | HHHH HHHT           HTTT     \n",
      "  8 | 012      | HHHH      HHTT HTHT      TTTT\n",
      "  9 | 0123     | HHHH      HHTT HTHT          \n",
      " 10 | 0 2      | HHHH      HHTT           TTTT\n",
      " 11 | 0123     | HHHH      HHTT               \n",
      " 12 | 01       | HHHH           HTHT      TTTT\n",
      " 13 | 0123     | HHHH           HTHT          \n",
      " 14 | 0 2      | HHHH                     TTTT\n",
      " 15 | 0123     | HHHH                         \n"
     ]
    }
   ],
   "source": [
    "show(coin_search(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that every odd-numbered move flips all four coins to eliminate the possibility of `TTTT`, flipping it to `HHHH`. We can also see that moves 2, 4, and 6 flip two coins and have the effect of eventually eliminating the two \"two heads\" sequences from the belief state, and then move 8 eliminates the \"three heads\" and \"one heads\" sequences, while bringing back the \"two heads\" possibilities. Repeating moves 2, 4, and 6 in moves 10, 12, and 14 then re-eliminates the \"two heads\", and move 15 gets the belief state down to `{'HHHH'}`.\n",
    "\n",
    "You could call `show(strategy, 8)`, but the results look bad unless you have a very wide (345 characters) screen to view it on. So instead I'll add a `verbose` parameter to `play` and play out some games with a trace of each move:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   1: HHTH rot: HHHT  flip: 0123 => HTTT\n",
      "   2: HTTT rot: TTTH  flip: 0 2  => HHHT\n",
      "   3: HHHT rot: HTHH  flip: 0123 => HTTT\n",
      "   4: HTTT rot: HTTT  flip: 01   => HTTT\n",
      "   5: HTTT rot: TTHT  flip: 0123 => HHHT\n",
      "   6: HHHT rot: THHH  flip: 0 2  => HHHT\n",
      "   7: HHHT rot: THHH  flip: 0123 => HTTT\n",
      "   8: HTTT rot: TTTH  flip: 012  => HHHH\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'HHHH'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def play(coins, strategy, verbose=False):\n",
    "    \"Play strategy against a random Devil; return final state of coins.\"\n",
    "    N = len(coins)\n",
    "    for i, move in enumerate(strategy, 1):\n",
    "        if 'T' not in coins: return coins\n",
    "        coins0 = coins\n",
    "        coins1 = random.choice(list(rotations(coins)))\n",
    "        coins  = flip(coins1, move)\n",
    "        if verbose: \n",
    "            print('{:4d}: {} rot: {}  flip: {} => {}'.format(\n",
    "                  i, coins0, coins1, movestr(move, N), coins))\n",
    "    return coins\n",
    "\n",
    "play('HHTH', coin_search(4), True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   1: HTTHTTHT rot: TTHTHTTH  flip: 01234567 => HHTHHTHT\n",
      "   2: HHTHHTHT rot: HHTHTHHT  flip: 0 2 4 6  => HHHHHTTT\n",
      "   3: HHHHHTTT rot: TTHHHHHT  flip: 01234567 => HHHTTTTT\n",
      "   4: HHHTTTTT rot: HTTTTTHH  flip: 01  45   => HHHHTHTT\n",
      "   5: HHHHTHTT rot: HTHTTHHH  flip: 01234567 => HHTTTTHT\n",
      "   6: HHTTTTHT rot: TTTHTHHT  flip: 0 2 4 6  => HHHHTTHT\n",
      "   7: HHHHTTHT rot: TTHTHHHH  flip: 01234567 => HHTHTTTT\n",
      "   8: HHTHTTTT rot: THHTHTTT  flip: 012 456  => HHTHTTTT\n",
      "   9: HHTHTTTT rot: THHTHTTT  flip: 01234567 => HHHHTTHT\n",
      "  10: HHHHTTHT rot: TTHTHHHH  flip: 0 2 4 6  => HHTTTTHT\n",
      "  11: HHTTTTHT rot: HTHHTTTT  flip: 01234567 => HHHHTHTT\n",
      "  12: HHHHTHTT rot: HTTHHHHT  flip: 01  45   => HTHTTHTT\n",
      "  13: HTHTTHTT rot: THTTHTTH  flip: 01234567 => HHTHHTHT\n",
      "  14: HHTHHTHT rot: THHTHTHH  flip: 0 2 4 6  => HHHTTTTT\n",
      "  15: HHHTTTTT rot: TTTTTHHH  flip: 01234567 => HHHHHTTT\n",
      "  16: HHHHHTTT rot: HHHTTTHH  flip: 0123     => HHTTTHTT\n",
      "  17: HHTTTHTT rot: HHTTTHTT  flip: 01234567 => HHHTHHTT\n",
      "  18: HHHTHHTT rot: HHHTHHTT  flip: 0 2 4 6  => HHTTHTTT\n",
      "  19: HHTTHTTT rot: TTHTTTHH  flip: 01234567 => HHHTTHHT\n",
      "  20: HHHTTHHT rot: HHHTTHHT  flip: 01  45   => HTHTHTTT\n",
      "  21: HTHTHTTT rot: TTHTHTHT  flip: 01234567 => HHHTHTHT\n",
      "  22: HHHTHTHT rot: HHHTHTHT  flip: 0 2 4 6  => HTTTTTTT\n",
      "  23: HTTTTTTT rot: TTTTTTTH  flip: 01234567 => HHHHHHHT\n",
      "  24: HHHHHHHT rot: HHHHHHHT  flip: 012 456  => HTTTTTTT\n",
      "  25: HTTTTTTT rot: TTTTTHTT  flip: 01234567 => HHHHHHHT\n",
      "  26: HHHHHHHT rot: HHHHHHHT  flip: 0 2 4 6  => HTHTHTTT\n",
      "  27: HTHTHTTT rot: THTTTHTH  flip: 01234567 => HHHTHTHT\n",
      "  28: HHHTHTHT rot: HHHTHTHT  flip: 01  45   => HHTTTHTT\n",
      "  29: HHTTTHTT rot: TTHHTTTH  flip: 01234567 => HHHTHHTT\n",
      "  30: HHHTHHTT rot: TTHHHTHH  flip: 0 2 4 6  => HHTTHTTT\n",
      "  31: HHTTHTTT rot: HTTHTTTH  flip: 01234567 => HHHTTHHT\n",
      "  32: HHHTTHHT rot: TTHHTHHH  flip: 01234 6  => HHHTTHHT\n",
      "  33: HHHTTHHT rot: THHHTTHH  flip: 01234567 => HHTTHTTT\n",
      "  34: HHTTHTTT rot: TTTHHTTH  flip: 0 2 4 6  => HHHTHHTT\n",
      "  35: HHHTHHTT rot: HTTHHHTH  flip: 01234567 => HHTTTHTT\n",
      "  36: HHTTTHTT rot: TTHHTTTH  flip: 01  45   => HHHHHHHT\n",
      "  37: HHHHHHHT rot: HTHHHHHH  flip: 01234567 => HTTTTTTT\n",
      "  38: HTTTTTTT rot: HTTTTTTT  flip: 0 2 4 6  => HTHTHTTT\n",
      "  39: HTHTHTTT rot: THTHTTTH  flip: 01234567 => HHHTHTHT\n",
      "  40: HHHTHTHT rot: HHHTHTHT  flip: 012 456  => HTTTTTTT\n",
      "  41: HTTTTTTT rot: TTTTTTTH  flip: 01234567 => HHHHHHHT\n",
      "  42: HHHHHHHT rot: HHTHHHHH  flip: 0 2 4 6  => HHHTHTHT\n",
      "  43: HHHTHTHT rot: HTHHHTHT  flip: 01234567 => HTHTHTTT\n",
      "  44: HTHTHTTT rot: HTHTHTTT  flip: 01  45   => HHTTHTTT\n",
      "  45: HHTTHTTT rot: TTHTTTHH  flip: 01234567 => HHHTTHHT\n",
      "  46: HHHTTHHT rot: HTTHHTHH  flip: 0 2 4 6  => HHTTTHTT\n",
      "  47: HHTTTHTT rot: THTTHHTT  flip: 01234567 => HHHTHHTT\n",
      "  48: HHHTHHTT rot: HHTHHTTH  flip: 0123     => HTHTTHTT\n",
      "  49: HTHTTHTT rot: TTHTTHTH  flip: 01234567 => HHTHHTHT\n",
      "  50: HHTHHTHT rot: THTHHTHH  flip: 0 2 4 6  => HHHHHTTT\n",
      "  51: HHHHHTTT rot: HTTTHHHH  flip: 01234567 => HHHTTTTT\n",
      "  52: HHHTTTTT rot: TTHHHTTT  flip: 01  45   => HHHHTHTT\n",
      "  53: HHHHTHTT rot: HHHHTHTT  flip: 01234567 => HHTTTTHT\n",
      "  54: HHTTTTHT rot: TTTTHTHH  flip: 0 2 4 6  => HHTHTTTT\n",
      "  55: HHTHTTTT rot: THTTTTHH  flip: 01234567 => HHHHTTHT\n",
      "  56: HHHHTTHT rot: HHTTHTHH  flip: 012 456  => HTHTTHTT\n",
      "  57: HTHTTHTT rot: THTTHTTH  flip: 01234567 => HHTHHTHT\n",
      "  58: HHTHHTHT rot: HHTHTHHT  flip: 0 2 4 6  => HHHHHTTT\n",
      "  59: HHHHHTTT rot: HHTTTHHH  flip: 01234567 => HHHTTTTT\n",
      "  60: HHHTTTTT rot: TTTTHHHT  flip: 01  45   => HHTTTTHT\n",
      "  61: HHTTTTHT rot: HTTTTHTH  flip: 01234567 => HHHHTHTT\n",
      "  62: HHHHTHTT rot: THHHHTHT  flip: 0 2 4 6  => HHTHTTTT\n",
      "  63: HHTHTTTT rot: THTTTTHH  flip: 01234567 => HHHHTTHT\n",
      "  64: HHHHTTHT rot: HHHTTHTH  flip: 012345   => HHTTHTTT\n",
      "  65: HHTTHTTT rot: HTTHTTTH  flip: 01234567 => HHHTTHHT\n",
      "  66: HHHTTHHT rot: TTHHTHHH  flip: 0 2 4 6  => HHHTHHTT\n",
      "  67: HHHTHHTT rot: HHTHHTTH  flip: 01234567 => HHTTTHTT\n",
      "  68: HHTTTHTT rot: THTTHHTT  flip: 01  45   => HTTTTTTT\n",
      "  69: HTTTTTTT rot: TTTTTTHT  flip: 01234567 => HHHHHHHT\n",
      "  70: HHHHHHHT rot: HHHTHHHH  flip: 0 2 4 6  => HTHTHTTT\n",
      "  71: HTHTHTTT rot: TTHTHTHT  flip: 01234567 => HHHTHTHT\n",
      "  72: HHHTHTHT rot: HTHHHTHT  flip: 012 456  => HTHTHTTT\n",
      "  73: HTHTHTTT rot: TTHTHTHT  flip: 01234567 => HHHTHTHT\n",
      "  74: HHHTHTHT rot: HTHTHTHH  flip: 0 2 4 6  => HTTTTTTT\n",
      "  75: HTTTTTTT rot: TTTTHTTT  flip: 01234567 => HHHHHHHT\n",
      "  76: HHHHHHHT rot: HHTHHHHH  flip: 01  45   => HHTTTHTT\n",
      "  77: HHTTTHTT rot: HTTTHTTH  flip: 01234567 => HHHTHHTT\n",
      "  78: HHHTHHTT rot: HHTTHHHT  flip: 0 2 4 6  => HHTTHTTT\n",
      "  79: HHTTHTTT rot: HHTTHTTT  flip: 01234567 => HHHTTHHT\n",
      "  80: HHHTTHHT rot: HTHHHTTH  flip: 0123     => HTHTTHTT\n",
      "  81: HTHTTHTT rot: THTTHTTH  flip: 01234567 => HHTHHTHT\n",
      "  82: HHTHHTHT rot: HHTHHTHT  flip: 0 2 4 6  => HHHTTTTT\n",
      "  83: HHHTTTTT rot: TTHHHTTT  flip: 01234567 => HHHHHTTT\n",
      "  84: HHHHHTTT rot: TTHHHHHT  flip: 01  45   => HHHHTTHT\n",
      "  85: HHHHTTHT rot: HTTHTHHH  flip: 01234567 => HHTHTTTT\n",
      "  86: HHTHTTTT rot: HTTTTHHT  flip: 0 2 4 6  => HHTTTTHT\n",
      "  87: HHTTTTHT rot: TTTTHTHH  flip: 01234567 => HHHHTHTT\n",
      "  88: HHHHTHTT rot: THHHHTHT  flip: 012 456  => HTHTTHTT\n",
      "  89: HTHTTHTT rot: THTTHTTH  flip: 01234567 => HHTHHTHT\n",
      "  90: HHTHHTHT rot: THTHHTHH  flip: 0 2 4 6  => HHHHHTTT\n",
      "  91: HHHHHTTT rot: TTTHHHHH  flip: 01234567 => HHHTTTTT\n",
      "  92: HHHTTTTT rot: HHHTTTTT  flip: 01  45   => HHTTTTHT\n",
      "  93: HHTTTTHT rot: TTHTHHTT  flip: 01234567 => HHHHTHTT\n",
      "  94: HHHHTHTT rot: HHTHTTHH  flip: 0 2 4 6  => HHHHTTHT\n",
      "  95: HHHHTTHT rot: TTHTHHHH  flip: 01234567 => HHTHTTTT\n",
      "  96: HHTHTTTT rot: TTHHTHTT  flip: 01234 6  => HHHTHHTT\n",
      "  97: HHHTHHTT rot: TTHHHTHH  flip: 01234567 => HHTTTHTT\n",
      "  98: HHTTTHTT rot: TTHTTHHT  flip: 0 2 4 6  => HHTTHTTT\n",
      "  99: HHTTHTTT rot: THTTTHHT  flip: 01234567 => HHHTTHHT\n",
      " 100: HHHTTHHT rot: THHTHHHT  flip: 01  45   => HTHTHTTT\n",
      " 101: HTHTHTTT rot: THTHTTTH  flip: 01234567 => HHHTHTHT\n",
      " 102: HHHTHTHT rot: HTHTHTHH  flip: 0 2 4 6  => HTTTTTTT\n",
      " 103: HTTTTTTT rot: TTTTTHTT  flip: 01234567 => HHHHHHHT\n",
      " 104: HHHHHHHT rot: HHHHHHHT  flip: 012 456  => HTTTTTTT\n",
      " 105: HTTTTTTT rot: TTTHTTTT  flip: 01234567 => HHHHHHHT\n",
      " 106: HHHHHHHT rot: HHHHHHHT  flip: 0 2 4 6  => HTHTHTTT\n",
      " 107: HTHTHTTT rot: THTHTHTT  flip: 01234567 => HHHTHTHT\n",
      " 108: HHHTHTHT rot: HTHTHTHH  flip: 01  45   => HHHTHHTT\n",
      " 109: HHHTHHTT rot: TTHHHTHH  flip: 01234567 => HHTTTHTT\n",
      " 110: HHTTTHTT rot: HTTTHTTH  flip: 0 2 4 6  => HHTTHTTT\n",
      " 111: HHTTHTTT rot: TTTHHTTH  flip: 01234567 => HHHTTHHT\n",
      " 112: HHHTTHHT rot: HHHTTHHT  flip: 0123     => HHTTTTHT\n",
      " 113: HHTTTTHT rot: TTHTHHTT  flip: 01234567 => HHHHTHTT\n",
      " 114: HHHHTHTT rot: HHTHTTHH  flip: 0 2 4 6  => HHHHTTHT\n",
      " 115: HHHHTTHT rot: HHHHTTHT  flip: 01234567 => HHTHTTTT\n",
      " 116: HHTHTTTT rot: HTTTTHHT  flip: 01  45   => HTHTTHTT\n",
      " 117: HTHTTHTT rot: THTHTTHT  flip: 01234567 => HHTHHTHT\n",
      " 118: HHTHHTHT rot: HHTHHTHT  flip: 0 2 4 6  => HHHTTTTT\n",
      " 119: HHHTTTTT rot: HHTTTTTH  flip: 01234567 => HHHHHTTT\n",
      " 120: HHHHHTTT rot: TTTHHHHH  flip: 012 456  => HHHHHTTT\n",
      " 121: HHHHHTTT rot: HTTTHHHH  flip: 01234567 => HHHTTTTT\n",
      " 122: HHHTTTTT rot: HHHTTTTT  flip: 0 2 4 6  => HTHTTHTT\n",
      " 123: HTHTTHTT rot: THTTHTHT  flip: 01234567 => HHTHHTHT\n",
      " 124: HHTHHTHT rot: THHTHHTH  flip: 01  45   => HHTHTTTT\n",
      " 125: HHTHTTTT rot: HHTHTTTT  flip: 01234567 => HHHHTTHT\n",
      " 126: HHHHTTHT rot: THHHHTTH  flip: 0 2 4 6  => HHHHTHTT\n",
      " 127: HHHHTHTT rot: THHHHTHT  flip: 01234567 => HHTTTTHT\n",
      " 128: HHTTTTHT rot: HTTTTHTH  flip: 0123456  => HHHHTHHT\n",
      " 129: HHHHTHHT rot: THHTHHHH  flip: 01234567 => HTTHTTTT\n",
      " 130: HTTHTTTT rot: TTHTTTTH  flip: 0 2 4 6  => HHHTTTHT\n",
      " 131: HHHTTTHT rot: THHHTTTH  flip: 01234567 => HHHTHTTT\n",
      " 132: HHHTHTTT rot: THHHTHTT  flip: 01  45   => HHHTTTHT\n",
      " 133: HHHTTTHT rot: TTTHTHHH  flip: 01234567 => HHHTHTTT\n",
      " 134: HHHTHTTT rot: HTTTHHHT  flip: 0 2 4 6  => HTTHTTTT\n",
      " 135: HTTHTTTT rot: TTTTHTTH  flip: 01234567 => HHHHTHHT\n",
      " 136: HHHHTHHT rot: HHHTHHTH  flip: 012 456  => HHTTTTTT\n",
      " 137: HHTTTTTT rot: TTHHTTTT  flip: 01234567 => HHHHHHTT\n",
      " 138: HHHHHHTT rot: HHTTHHHH  flip: 0 2 4 6  => HHTTHTHT\n",
      " 139: HHTTHTHT rot: HTHTHHTT  flip: 01234567 => HHTHTHTT\n",
      " 140: HHTHTHTT rot: THTTHHTH  flip: 01  45   => HHTTTTTT\n",
      " 141: HHTTTTTT rot: TTTHHTTT  flip: 01234567 => HHHHHHTT\n",
      " 142: HHHHHHTT rot: TTHHHHHH  flip: 0 2 4 6  => HHTTHTHT\n",
      " 143: HHTTHTHT rot: TTHTHTHH  flip: 01234567 => HHTHTHTT\n",
      " 144: HHTHTHTT rot: HTTHHTHT  flip: 0123     => HHTHTHTT\n",
      " 145: HHTHTHTT rot: TTHHTHTH  flip: 01234567 => HHTTHTHT\n",
      " 146: HHTTHTHT rot: HHTTHTHT  flip: 0 2 4 6  => HHTTTTTT\n",
      " 147: HHTTTTTT rot: TTHHTTTT  flip: 01234567 => HHHHHHTT\n",
      " 148: HHHHHHTT rot: HHHHHHTT  flip: 01  45   => HHTTTTTT\n",
      " 149: HHTTTTTT rot: TTTTHHTT  flip: 01234567 => HHHHHHTT\n",
      " 150: HHHHHHTT rot: HHHHTTHH  flip: 0 2 4 6  => HHTTHTHT\n",
      " 151: HHTTHTHT rot: THTHHTTH  flip: 01234567 => HHTHTHTT\n",
      " 152: HHTHTHTT rot: HHTHTHTT  flip: 012 456  => HHHTHTTT\n",
      " 153: HHHTHTTT rot: THTTTHHH  flip: 01234567 => HHHTTTHT\n",
      " 154: HHHTTTHT rot: HHTTTHTH  flip: 0 2 4 6  => HHHHTHHT\n",
      " 155: HHHHTHHT rot: THHTHHHH  flip: 01234567 => HTTHTTTT\n",
      " 156: HTTHTTTT rot: TTHTTTTH  flip: 01  45   => HHHHTHHT\n",
      " 157: HHHHTHHT rot: HHTHHHHT  flip: 01234567 => HTTHTTTT\n",
      " 158: HTTHTTTT rot: TTTHTTHT  flip: 0 2 4 6  => HHHTTTHT\n",
      " 159: HHHTTTHT rot: HHHTTTHT  flip: 01234567 => HHHTHTTT\n",
      " 160: HHHTHTTT rot: TTHHHTHT  flip: 01234 6  => HHTTTTTT\n",
      " 161: HHTTTTTT rot: TTHHTTTT  flip: 01234567 => HHHHHHTT\n",
      " 162: HHHHHHTT rot: HHHHHTTH  flip: 0 2 4 6  => HHTHTHTT\n",
      " 163: HHTHTHTT rot: THTTHHTH  flip: 01234567 => HHTTHTHT\n",
      " 164: HHTTHTHT rot: TTHTHTHH  flip: 01  45   => HHHHHHTT\n",
      " 165: HHHHHHTT rot: HHTTHHHH  flip: 01234567 => HHTTTTTT\n",
      " 166: HHTTTTTT rot: HHTTTTTT  flip: 0 2 4 6  => HHTHTHTT\n",
      " 167: HHTHTHTT rot: THTHTTHH  flip: 01234567 => HHTTHTHT\n",
      " 168: HHTTHTHT rot: HTHHTTHT  flip: 012 456  => HHHTTTHT\n",
      " 169: HHHTTTHT rot: TTTHTHHH  flip: 01234567 => HHHTHTTT\n",
      " 170: HHHTHTTT rot: TTHHHTHT  flip: 0 2 4 6  => HTTHTTTT\n",
      " 171: HTTHTTTT rot: TTTTHTTH  flip: 01234567 => HHHHTHHT\n",
      " 172: HHHHTHHT rot: HTHHTHHH  flip: 01  45   => HHHHTHHT\n",
      " 173: HHHHTHHT rot: THHTHHHH  flip: 01234567 => HTTHTTTT\n",
      " 174: HTTHTTTT rot: TTHTTHTT  flip: 0 2 4 6  => HHHTHTTT\n",
      " 175: HHHTHTTT rot: THTTTHHH  flip: 01234567 => HHHTTTHT\n",
      " 176: HHHTTTHT rot: HHHTTTHT  flip: 0123     => HTTHTTTT\n",
      " 177: HTTHTTTT rot: TTHTTTTH  flip: 01234567 => HHHHTHHT\n",
      " 178: HHHHTHHT rot: HHTHHTHH  flip: 0 2 4 6  => HHHTTTHT\n",
      " 179: HHHTTTHT rot: HHHTTTHT  flip: 01234567 => HHHTHTTT\n",
      " 180: HHHTHTTT rot: TTTHHHTH  flip: 01  45   => HHHTHTTT\n",
      " 181: HHHTHTTT rot: HTTTHHHT  flip: 01234567 => HHHTTTHT\n",
      " 182: HHHTTTHT rot: HHTTTHTH  flip: 0 2 4 6  => HHHHTHHT\n",
      " 183: HHHHTHHT rot: THHHHTHH  flip: 01234567 => HTTHTTTT\n",
      " 184: HTTHTTTT rot: HTTTTHTT  flip: 012 456  => HHTHTHTT\n",
      " 185: HHTHTHTT rot: THHTHTHT  flip: 01234567 => HHTTHTHT\n",
      " 186: HHTTHTHT rot: HTTHTHTH  flip: 0 2 4 6  => HHHHHHTT\n",
      " 187: HHHHHHTT rot: TTHHHHHH  flip: 01234567 => HHTTTTTT\n",
      " 188: HHTTTTTT rot: TTTTTTHH  flip: 01  45   => HHHHHHTT\n",
      " 189: HHHHHHTT rot: HHHHHTTH  flip: 01234567 => HHTTTTTT\n",
      " 190: HHTTTTTT rot: HHTTTTTT  flip: 0 2 4 6  => HHTHTHTT\n",
      " 191: HHTHTHTT rot: HTHTTHHT  flip: 01234567 => HHTTHTHT\n",
      " 192: HHTTHTHT rot: HTHTHHTT  flip: 012345   => HTHTTTTT\n",
      " 193: HTHTTTTT rot: HTHTTTTT  flip: 01234567 => HHHHHTHT\n",
      " 194: HHHHHTHT rot: THHHHHTH  flip: 0 2 4 6  => HHHHHTHT\n",
      " 195: HHHHHTHT rot: HTHTHHHH  flip: 01234567 => HTHTTTTT\n",
      " 196: HTHTTTTT rot: TTTTHTHT  flip: 01  45   => HHTHHTTT\n",
      " 197: HHTHHTTT rot: HTHHTTTH  flip: 01234567 => HHHTTHTT\n",
      " 198: HHHTTHTT rot: HTTHHHTT  flip: 0 2 4 6  => HHTHHTTT\n",
      " 199: HHTHHTTT rot: THHTHHTT  flip: 01234567 => HHHTTHTT\n",
      " 200: HHHTTHTT rot: HTTHHHTT  flip: 012 456  => HHHTTHTT\n",
      " 201: HHHTTHTT rot: HHHTTHTT  flip: 01234567 => HHTHHTTT\n",
      " 202: HHTHHTTT rot: HTHHTTTH  flip: 0 2 4 6  => HHTHHTTT\n",
      " 203: HHTHHTTT rot: TTTHHTHH  flip: 01234567 => HHHTTHTT\n",
      " 204: HHHTTHTT rot: TTHTTHHH  flip: 01  45   => HHHHHTHT\n",
      " 205: HHHHHTHT rot: HHHHHTHT  flip: 01234567 => HTHTTTTT\n",
      " 206: HTHTTTTT rot: TTHTHTTT  flip: 0 2 4 6  => HTHTTTTT\n",
      " 207: HTHTTTTT rot: TTTHTHTT  flip: 01234567 => HHHHHTHT\n",
      " 208: HHHHHTHT rot: THHHHHTH  flip: 0123     => HHTHHTTT\n",
      " 209: HHTHHTTT rot: HTTTHHTH  flip: 01234567 => HHHTTHTT\n",
      " 210: HHHTTHTT rot: TTHHHTTH  flip: 0 2 4 6  => HHHTTHTT\n",
      " 211: HHHTTHTT rot: HTTHHHTT  flip: 01234567 => HHTHHTTT\n",
      " 212: HHTHHTTT rot: TTTHHTHH  flip: 01  45   => HHHHHTHT\n",
      " 213: HHHHHTHT rot: HHHHHTHT  flip: 01234567 => HTHTTTTT\n",
      " 214: HTHTTTTT rot: THTHTTTT  flip: 0 2 4 6  => HHHHHTHT\n",
      " 215: HHHHHTHT rot: THTHHHHH  flip: 01234567 => HTHTTTTT\n",
      " 216: HTHTTTTT rot: HTTTTTHT  flip: 012 456  => HHTHHTTT\n",
      " 217: HHTHHTTT rot: THHTTTHH  flip: 01234567 => HHHTTHTT\n",
      " 218: HHHTTHTT rot: THTTHHHT  flip: 0 2 4 6  => HHHTTHTT\n",
      " 219: HHHTTHTT rot: TTHTTHHH  flip: 01234567 => HHTHHTTT\n",
      " 220: HHTHHTTT rot: THHTHHTT  flip: 01  45   => HTHTTTTT\n",
      " 221: HTHTTTTT rot: TTHTHTTT  flip: 01234567 => HHHHHTHT\n",
      " 222: HHHHHTHT rot: HHHTHTHH  flip: 0 2 4 6  => HTHTTTTT\n",
      " 223: HTHTTTTT rot: TTTTHTHT  flip: 01234567 => HHHHHTHT\n",
      " 224: HHHHHTHT rot: THTHHHHH  flip: 01234 6  => HHTHTTHT\n",
      " 225: HHTHTTHT rot: HTHTTHTH  flip: 01234567 => HHTHTTHT\n",
      " 226: HHTHTTHT rot: HTTHTHHT  flip: 0 2 4 6  => HHHHTTTT\n",
      " 227: HHHHTTTT rot: HHTTTTHH  flip: 01234567 => HHHHTTTT\n",
      " 228: HHHHTTTT rot: TTHHHHTT  flip: 01  45   => HHHHTTTT\n",
      " 229: HHHHTTTT rot: TTHHHHTT  flip: 01234567 => HHHHTTTT\n",
      " 230: HHHHTTTT rot: TTHHHHTT  flip: 0 2 4 6  => HHTHTTHT\n",
      " 231: HHTHTTHT rot: HHTHTTHT  flip: 01234567 => HHTHTTHT\n",
      " 232: HHTHTTHT rot: HHTHTTHT  flip: 012 456  => HHHHTTTT\n",
      " 233: HHHHTTTT rot: TTHHHHTT  flip: 01234567 => HHHHTTTT\n",
      " 234: HHHHTTTT rot: TTHHHHTT  flip: 0 2 4 6  => HHTHTTHT\n",
      " 235: HHTHTTHT rot: TTHTHHTH  flip: 01234567 => HHTHTTHT\n",
      " 236: HHTHTTHT rot: THTHHTHT  flip: 01  45   => HHTHTTHT\n",
      " 237: HHTHTTHT rot: THTHHTHT  flip: 01234567 => HHTHTTHT\n",
      " 238: HHTHTTHT rot: TTHTHHTH  flip: 0 2 4 6  => HHHHTTTT\n",
      " 239: HHHHTTTT rot: TTTHHHHT  flip: 01234567 => HHHHTTTT\n",
      " 240: HHHHTTTT rot: TTTHHHHT  flip: 0123     => HHHTHHHT\n",
      " 241: HHHTHHHT rot: HHHTHHHT  flip: 01234567 => HTTTHTTT\n",
      " 242: HTTTHTTT rot: TTHTTTHT  flip: 0 2 4 6  => HTTTHTTT\n",
      " 243: HTTTHTTT rot: HTTTHTTT  flip: 01234567 => HHHTHHHT\n",
      " 244: HHHTHHHT rot: HHTHHHTH  flip: 01  45   => HTTTHTTT\n",
      " 245: HTTTHTTT rot: TTHTTTHT  flip: 01234567 => HHHTHHHT\n",
      " 246: HHHTHHHT rot: HHHTHHHT  flip: 0 2 4 6  => HTTTHTTT\n",
      " 247: HTTTHTTT rot: THTTTHTT  flip: 01234567 => HHHTHHHT\n",
      " 248: HHHTHHHT rot: HHTHHHTH  flip: 012 456  => HHTTHHTT\n",
      " 249: HHTTHHTT rot: HHTTHHTT  flip: 01234567 => HHTTHHTT\n",
      " 250: HHTTHHTT rot: HHTTHHTT  flip: 0 2 4 6  => HHTTHHTT\n",
      " 251: HHTTHHTT rot: HHTTHHTT  flip: 01234567 => HHTTHHTT\n",
      " 252: HHTTHHTT rot: THHTTHHT  flip: 01  45   => HTHTHTHT\n",
      " 253: HTHTHTHT rot: HTHTHTHT  flip: 01234567 => HTHTHTHT\n",
      " 254: HTHTHTHT rot: HTHTHTHT  flip: 0 2 4 6  => TTTTTTTT\n",
      " 255: TTTTTTTT rot: TTTTTTTT  flip: 01234567 => HHHHHHHH\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'HHHHHHHH'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "play('HTTHTTHT', strategy, True)"
   ]
  }
 ],
 "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.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
