diff --git a/ipynb/Coin Flip.ipynb b/ipynb/Coin Flip.ipynb
index 40f91c8..820a8c7 100644
--- a/ipynb/Coin Flip.ipynb
+++ b/ipynb/Coin Flip.ipynb
@@ -18,35 +18,35 @@
"\n",
"# Analysis\n",
"\n",
- "Here are my thoughts:\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",
- "- However, we are \"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 coins. So we should represent what is known: the *set of possible states* of the coins. 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 24 = 16 possibilities in the belief state:\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",
+ "- In fact, the Devil would do well to determine his best move using a minimax search.\n",
+ "- However, the player can't do that, because minimax only works when you know what moves the opponent is making. Here 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 24 = 16 possibilities in the belief state:\n",
" {HHHH, HHHT, HHTH, HHTT, HTHH, HTHT, HTTH, HTTT, \n",
" THHH, THHT, THTH, THTT, TTHH, TTHT, TTTH, TTTT}\n",
- "\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 (or not; the problem doesn't say for sure). We could in fact model things this way.\n",
- "- However, since we are already dealing with belief states, I think it is simpler to model this as 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, `{HHHH}`.\n",
- "\n",
- "- A move updates the belief state as follows: for every 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 216 possible belief states), so run time will be fast; the only issue is specifying the domain correctly. To increase the chance of getting it right, I won't try to do anything fancy, such as noticing that some coin sequences are rotational variants of other sequences (although we'll come back to that later).\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 216 possible belief states), so run time will be fast; the only issue is specifying the domain correctly. \n",
+ "- To increase the chance of getting it right, I won't do anything fancy, such as noticing rotational symmetry (although we'll come back to that later).\n",
"\n",
"\n",
- "# Implementation Choices\n",
+ "# Vocabulary and Implementation Choices\n",
"\n",
- "Here is the vocabulary of the problem, and my implementation choices:\n",
- "\n",
- "- `Coins`: A *coin sequence* (on the table) is represented as a `str` of four characters, such as `'HTTT'`. \n",
- "- `Belief`: A *belief state* is represented as a `frozenset` of `Coins` (frozen so that it can be hashed).\n",
- "- `Position`: A position is an integer index into the coin sequence; position `0` selects the `H` in `'HTTT'`\n",
+ "- `Coins`: a *coin sequence* (on the table) is represented as a `str` of four characters, such as `'HTTT'`. \n",
+ "- `Belief`: a *belief state* is represented as a `frozenset` of `Coins` (frozen so that it can be hashed).\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 *move* is a set of positions to flip, such as `{0, 1}`. \n",
- "- `Strategy`: A strategy for playing the game is a list of moves. Since there is no feedback while playing\n",
- "(the player is blindfolded) there is no need for decision points in the strategy.\n",
+ "- `Move`: a set of positions to flip, such as `{0, 2}`. \n",
+ "- `Strategy`: an ordered list of moves. Since there is no feedback while playing\n",
+ "(blindfolded) there are no decision points in the strategy. \n",
+ "- `winning(strategy)`: a winning strategy is one that takes us from the initial state to the goal, regardless\n",
+ "of what rotations the Devil chooses.\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 set of all 4 rotations of the coin sequence.\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",
"- `flip(coins, move)`: flips the specified positions within the coin sequence.\n",
- " (But don't flip `'HHHH'`, because the game would have already ended if this were the coin sequence.)"
+ " (But don't flip `'HHHH'`, because the game would have already ended if this were the coin sequence.)\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"
]
},
{
@@ -57,15 +57,25 @@
},
"outputs": [],
"source": [
- "from collections import deque, Counter\n",
+ "from collections import deque\n",
"from itertools import product, combinations\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",
- "Move = set # A set of positions to flip: {0, 1}\n",
+ "Move = set # A set of positions to flip: {0, 2}\n",
"Strategy = list # A list of Moves: [{0, 1, 2, 3}, {0, 2}, ...]\n",
"\n",
+ "# TODO: winning(strategy)\n",
+ "\n",
+ "def all_moves(): return powerset(range(4))\n",
+ "\n",
+ "def powerset(sequence): \n",
+ " \"All subsets of a sequence.\"\n",
+ " return [set(c) \n",
+ " for r in range(len(sequence) + 1)\n",
+ " for c in combinations(sequence, r)]\n",
+ "\n",
"def all_coins() -> Belief:\n",
" \"Return the belief set consisting of all possible coin sequences.\"\n",
" return Belief(map(Coins, product('HT', repeat=4)))\n",
@@ -74,19 +84,19 @@
" \"A list 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' in coins: \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",
- "def flip(coins, move) -> Coins:\n",
- " \"Flip the coins in the positions specified by the move (but leave 'HHHH' alone).\"\n",
- " if coins == 'HHHH': return coins\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)"
+ " for c in rotations(coins))"
]
},
{
@@ -104,7 +114,22 @@
{
"data": {
"text/plain": [
- "'THTT'"
+ "[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": 2,
@@ -113,7 +138,7 @@
}
],
"source": [
- "flip('HHHT', {0, 2})"
+ "all_moves()"
]
},
{
@@ -124,7 +149,14 @@
{
"data": {
"text/plain": [
- "{'HHHT', 'HHTH', 'HTHH', 'THHH'}"
+ "[set(),\n",
+ " {'a'},\n",
+ " {'b'},\n",
+ " {'c'},\n",
+ " {'a', 'b'},\n",
+ " {'a', 'c'},\n",
+ " {'b', 'c'},\n",
+ " {'a', 'b', 'c'}]"
]
},
"execution_count": 3,
@@ -133,7 +165,7 @@
}
],
"source": [
- "rotations('HHHT')"
+ "powerset('abc')"
]
},
{
@@ -172,15 +204,55 @@
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 5,
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'HHHT', 'HHTH', 'HTHH', 'THHH'}"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "We see there are 16 coin sequences in the `all_coins` belief state. Now 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:"
+ "rotations('HHHT')"
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "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": [
{
@@ -203,7 +275,7 @@
" 'TTTH'})"
]
},
- "execution_count": 5,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
@@ -216,64 +288,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Everything looks good so far. One more thing: we need to find all subsets of the 4 positions; these are the possible moves:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def powerset(sequence): \n",
- " \"All subsets of a sequence.\"\n",
- " return [set(c) \n",
- " for r in range(len(sequence) + 1)\n",
- " for c in combinations(sequence, r)]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "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": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "powerset(range(4))"
+ "Everything looks good so far. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Search for a Solution\n",
+ "# 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",
@@ -307,7 +329,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Now, `search` doesn't know anything about belief states—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",
+ "Note that `search` doesn't know anything about belief states—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:"
]
@@ -315,26 +337,6 @@
{
"cell_type": "code",
"execution_count": 9,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def coin_search() -> Strategy: \n",
- " \"Use `search` to solve the Coin Flip problem.\"\n",
- " return search(start=all_coins(), goal={'HHHH'}, actions=powerset(range(4)), result=update)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# A Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
"metadata": {},
"outputs": [
{
@@ -357,12 +359,16 @@
" {0, 1, 2, 3}]"
]
},
- "execution_count": 10,
+ "execution_count": 9,
"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()"
]
},
@@ -370,91 +376,58 @@
"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. Or you can continue on ...\n",
+ "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. Or you can continue on ...\n",
"\n",
"----\n",
"\n",
- "# Verifying the Solution\n",
+ "# Verifying the Winning Strategy\n",
"\n",
- "I don't have a proof, but I have some evidence that the solution is correct:\n",
+ "I don't have a proof, but I have some evidence that the strategy inevitably leads to the goal:\n",
"- Exploring with paper and pencil, it does appear to work. \n",
"- A colleague did the puzzle and got the same answer. \n",
- "- Running the function `random_devil` below is consistent with it working.\n",
+ "- It passes the `winning` test below.\n",
"\n",
- "The function `random_devil` takes an initial coin sequence and a sequence of moves, and plays those moves with a devil that chooses rotations randomly, returning the number of moves it takes until the player wins. Note this is dealing with concrete, individual states of the world, like `HTHH`, not belief states."
+ "The function `winning` takes a strategy and plays it against a Devil that chooses rotations at random, repeating play 10,000 times (by default) for each possible starting coin sequence. Note this is dealing with concrete, individual states of the world, like `HTHH`, not belief states."
]
},
{
"cell_type": "code",
- "execution_count": 11,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def random_devil(coins, strategy) -> int or None:\n",
- " \"\"\"A random devil responds to moves starting from coins; \n",
- " return the number of moves until win, or None.\"\"\"\n",
- " if coins == 'HHHH': return 0\n",
- " for (i, move) in enumerate(strategy, 1):\n",
- " coins = flip(random.choice(list(rotations(coins))), move)\n",
- " if coins == 'HHHH': \n",
- " return i\n",
- " return None"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "I will let the `random_devil` play 10,000 times from each possible starting coin sequence:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "Counter({0: 10000,\n",
- " 1: 10000,\n",
- " 2: 10105,\n",
- " 3: 9895,\n",
- " 4: 9817,\n",
- " 5: 10166,\n",
- " 6: 9928,\n",
- " 7: 10089,\n",
- " 8: 10028,\n",
- " 9: 10082,\n",
- " 10: 9991,\n",
- " 11: 10105,\n",
- " 12: 9976,\n",
- " 13: 9970,\n",
- " 14: 9948,\n",
- " 15: 9900})"
+ "True"
]
},
- "execution_count": 12,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "strategy = coin_search()\n",
+ "def winning(strategy, repeat=10000):\n",
+ " \"Is this a winning strategy? A probabilistic algorithm.\"\n",
+ " return all(play(coins, strategy) == 'HHHH'\n",
+ " for coins in all_coins() for _ in range(repeat))\n",
"\n",
- "Counter(random_devil(coins, strategy) \n",
- " for coins in all_coins()\n",
- " for _ in range(10000))"
+ "def play(coins, strategy):\n",
+ " \"Play strategy against a random Devil; return final state of coins.\"\n",
+ " for move in strategy:\n",
+ " if 'T' in 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": [
- "This says that the player won all 160,000 times. (If the player had ever lost, there would have been an entry for `None` in the Counter.) This suggests the strategy is likely to win, but doesn't prove it will always win, and doesn't say anything about the possibility of a shorter solution.\n",
- "The remarkable thing, which I can't explain, is that there are very nearly exactly 10,000 results for each of the move counts from 0 to 15. Can you explain that?\n",
+ "This says that we played 16 × 10,000 games, and the strategy won every time. It does not say it will always win against other rotation choices, and it does not make any claims about being a shortest strategy.\n",
"\n",
"# Canonical Coin Sequences\n",
"\n",
@@ -463,7 +436,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 11,
"metadata": {
"collapsed": true
},
@@ -485,7 +458,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 12,
"metadata": {},
"outputs": [
{
@@ -494,7 +467,7 @@
"frozenset({'HHHH', 'HHHT', 'HHTT', 'HTHT', 'HTTT', 'TTTT'})"
]
},
- "execution_count": 14,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -514,7 +487,7 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
@@ -537,7 +510,7 @@
" {0, 1, 2, 3}]"
]
},
- "execution_count": 15,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@@ -550,19 +523,26 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Solutions for *N* Coins\n",
+ "# 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_coins`, `rotations` and `coin_search`, as well as `flip`, which has `'HHHH'` in it, and introduce `all_moves(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",
+ "To compute `all_moves()` for 4 coins, I previously used `powerset(range(4))`, and got 16 possible moves. Now I want the set of all *canonicalized* moves for any *N*: the moves `{0}` and `{1}` should be considered the same, since they both say \"flip one coin.\" 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,
+ "execution_count": 14,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
+ "def all_moves(N=4) -> [Move]:\n",
+ " \"All rotationally invariant 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",
@@ -573,15 +553,7 @@
"\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)\n",
- "\n",
- "def flip(coins, move) -> Coins:\n",
- " \"Flip the coins in the positions specified by the move (but leave all 'H' alone).\"\n",
- " if 'T' not in coins: return coins\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)"
+ " return search(start=all_coins(N), goal={'H' * N}, actions=all_moves(N), result=update)"
]
},
{
@@ -593,121 +565,87 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 15,
"metadata": {},
"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",
"assert all_coins(4) == {'HHHH', 'HHHT', 'HHTT', 'HTHT', 'HTTT', 'TTTT'}\n",
"assert all_coins(5) == {'HHHHH','HHHHT', 'HHHTT','HHTHT','HHTTT', 'HTHTT', 'HTTTT', 'TTTTT'}\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'})"
+ " == {'HHHHHH', 'HHHHTT', 'HHHTHT', 'HHTHHT'})\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": [
- "To compute the set of all possible moves for 4 coins, I used `powerset(range(4))`, and got 16 possible moves. Now I want to know the set of all *canonicalized* moves for any *N*: the moves `{0}` and `{1}` should be considered the same, since they both say \"flip one coin.\" I'll 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.)"
+ "How many distinct canonical coin sequences are there for up to a dozen coins?"
]
},
{
"cell_type": "code",
- "execution_count": 18,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def all_moves(N) -> [Move]:\n",
- " \"All rotationally invariant 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))]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
+ "execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "[{0, 1, 2}, {0, 1}, {0}, set()]"
+ "{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": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "all_moves(3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[{0, 1, 2, 3}, {0, 1, 2}, {0, 1}, {0, 2}, {0}, set()]"
- ]
- },
- "execution_count": 20,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "all_moves(4)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "With 4 coins we can flip 4, flip 3, flip 2 adjacent, flip 2 opposite, flip 1, or flip nothing.\n",
- "\n",
- "How many distinct canonical coin sequences are there for *N* coins from 1 to 10?"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{1: 2, 2: 3, 3: 4, 4: 6, 5: 8, 6: 14, 7: 20, 8: 36, 9: 60, 10: 108}"
- ]
- },
- "execution_count": 21,
+ "execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{N: len(all_coins(N))\n",
- " for N in range(1, 11)}"
+ " for N in range(1, 13)}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "On the one hand this is encouraging; there are only 108 canonical coin sequences of length 10, far less than the 1,024 non-canonical squences. On the other hand, it is discouraging; since we are searching over belief states, that would be 2108 ≌ 1032 belief states, which is not feasible. However, we should be able to easily handle up to N=7, because 220 is only a million.\n",
+ "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 2352 belief states, which is nore than a googol. However, we should be able to easily handle up to N=7, because 220 is only a million.\n",
"\n",
- "# Solutions for 1 to 7 Coins"
+ "# Winning Strategies for 1 to 7 Coins"
]
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 18,
"metadata": {},
"outputs": [
{
@@ -736,7 +674,7 @@
" 7: None}"
]
},
- "execution_count": 22,
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -749,40 +687,40 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Too bad; there are no solutions for N = 3, 5, 6, or 7. \n",
+ "Too bad; there are no winning strategies for N = 3, 5, 6, or 7. \n",
"\n",
- "There *are* solutions for N = 1, 2, 4; they have lengths 1, 3, 15, respectively. That suggests the conjecture: \n",
+ "There *are* winning strategies for N = 1, 2, 4; they have lengths 1, 3, 15, respectively. That suggests the conjecture: \n",
"\n",
- "> For every *N* that is a power of 2, there will be a shortest solution of length 2*N* - 1.\n",
+ "> For every *N* that is a power of 2, there will be a shortest winning strategy of length 2*N* - 1.\n",
"\n",
- "> For every *N* that is not a power of 2, there will be no solution. \n",
+ "> For every *N* that is not a power of 2, there will be no winning strategy. \n",
"\n",
- "# Solution for 8 Coins\n",
+ "# Winning Strategy for 8 Coins\n",
"\n",
- "For N = 8, there are 236 = 69 billion belief states and the desired solution has 255 steps. All the computations up to now have been instantaneous, but this one should take a few minutes. Let's see:"
+ "For N = 8, there are 236 = 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": 23,
+ "execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 1min 22s, sys: 287 ms, total: 1min 22s\n",
+ "CPU times: user 1min 22s, sys: 250 ms, total: 1min 22s\n",
"Wall time: 1min 23s\n"
]
}
],
"source": [
- "%time solution8 = coin_search(8)"
+ "%time strategy = coin_search(8)"
]
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": 20,
"metadata": {},
"outputs": [
{
@@ -791,13 +729,13 @@
"255"
]
},
- "execution_count": 24,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "len(solution8)"
+ "len(strategy)"
]
},
{
@@ -805,27 +743,26 @@
"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 solutions for *N* = 9, 10, 11, ...?\n",
- "- Can you prove there are no solutions for any *N* that is not a power of 2?\n",
- "- Can you find a solution of length 65,535 for *N* = 16 and verify that it works?\n",
- "- Can you generate a solution for any power of 2 (without proving it is shortest)?\n",
- "- Can you prove there are no shorter solutions for *N* = 16?\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 solution works, rather than just listing the moves?"
+ "- Can you *understand* and *explain* how the strategy works, rather than just listing the moves?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Visualizing the Solution\n",
- "\n",
- "To aid understanding, I'll print a table showing the belief state after each move, using the canonicalized `Belief` form, lined up neatly in columns."
+ "# Visualizing Strategies\n",
+ "\n"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 21,
"metadata": {
"collapsed": true
},
@@ -844,26 +781,34 @@
" \"Print the move number, move, and belief state.\"\n",
" ordered_belief = [(coins if coins in belief else ' ' * len(coins))\n",
" for coins in order]\n",
- " movestr = join((i if i in move else ' ') for i in range(N))\n",
- " print('{:3} | {:8} | {} | {}'\n",
- " .format(i, movestr, join(ordered_belief, ' '), i))\n",
+ " print('{:3} | {:8} | {}'\n",
+ " .format(i, movestr(move, N), join(ordered_belief, ' ')))\n",
+ " \n",
+ "def movestr(move, N): return join((i if i in move else ' ') for i in range(N))\n",
" \n",
"def join(items, sep='') -> str: return sep.join(map(str, items))"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The following table shows the move number, the move (e.g. \"01\" to flip positions 0 and 1), and all the canonical coin sequences in the belief state after the move:"
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- " 0 | | HH HT TT | 0\n",
- " 1 | 01 | HH HT | 1\n",
- " 2 | 0 | HH TT | 2\n",
- " 3 | 01 | HH | 3\n"
+ " 0 | | HH HT TT\n",
+ " 1 | 01 | HH HT \n",
+ " 2 | 0 | HH TT\n",
+ " 3 | 01 | HH \n"
]
}
],
@@ -873,29 +818,29 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- " 0 | | HHHH HHHT HHTT HTHT HTTT TTTT | 0\n",
- " 1 | 0123 | HHHH HHHT HHTT HTHT HTTT | 1\n",
- " 2 | 0 2 | HHHH HHHT HHTT HTTT TTTT | 2\n",
- " 3 | 0123 | HHHH HHHT HHTT HTTT | 3\n",
- " 4 | 01 | HHHH HHHT HTHT HTTT TTTT | 4\n",
- " 5 | 0123 | HHHH HHHT HTHT HTTT | 5\n",
- " 6 | 0 2 | HHHH HHHT HTTT TTTT | 6\n",
- " 7 | 0123 | HHHH HHHT HTTT | 7\n",
- " 8 | 012 | HHHH HHTT HTHT TTTT | 8\n",
- " 9 | 0123 | HHHH HHTT HTHT | 9\n",
- " 10 | 0 2 | HHHH HHTT TTTT | 10\n",
- " 11 | 0123 | HHHH HHTT | 11\n",
- " 12 | 01 | HHHH HTHT TTTT | 12\n",
- " 13 | 0123 | HHHH HTHT | 13\n",
- " 14 | 0 2 | HHHH TTTT | 14\n",
- " 15 | 0123 | HHHH | 15\n"
+ " 0 | | HHHH HHHT HHTT HTHT HTTT TTTT\n",
+ " 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"
]
}
],
@@ -909,282 +854,311 @@
"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(solution8, 8)`, but the results look bad unless you have a very wide (345 characters) screen to view it on. So I'll just show `solution8` itself, with move numbers:\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": 28,
+ "execution_count": 24,
"metadata": {},
"outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 1: HHTH rot: HTHH flip: 0123 => THTT\n",
+ " 2: THTT rot: HTTT flip: 0 2 => TTHT\n",
+ " 3: TTHT rot: THTT flip: 0123 => HTHH\n",
+ " 4: HTHH rot: THHH flip: 01 => HTHH\n",
+ " 5: HTHH rot: HHHT flip: 0123 => TTTH\n",
+ " 6: TTTH rot: HTTT flip: 0 2 => TTHT\n",
+ " 7: TTHT rot: THTT flip: 0123 => HTHH\n",
+ " 8: HTHH rot: HHHT flip: 012 => TTTT\n",
+ " 9: TTTT rot: TTTT flip: 0123 => HHHH\n"
+ ]
+ },
{
"data": {
"text/plain": [
- "{1: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 2: {0, 2, 4, 6},\n",
- " 3: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 4: {0, 1, 4, 5},\n",
- " 5: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 6: {0, 2, 4, 6},\n",
- " 7: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 8: {0, 1, 2, 4, 5, 6},\n",
- " 9: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 10: {0, 2, 4, 6},\n",
- " 11: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 12: {0, 1, 4, 5},\n",
- " 13: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 14: {0, 2, 4, 6},\n",
- " 15: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 16: {0, 1, 2, 3},\n",
- " 17: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 18: {0, 2, 4, 6},\n",
- " 19: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 20: {0, 1, 4, 5},\n",
- " 21: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 22: {0, 2, 4, 6},\n",
- " 23: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 24: {0, 1, 2, 4, 5, 6},\n",
- " 25: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 26: {0, 2, 4, 6},\n",
- " 27: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 28: {0, 1, 4, 5},\n",
- " 29: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 30: {0, 2, 4, 6},\n",
- " 31: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 32: {0, 1, 2, 3, 4, 6},\n",
- " 33: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 34: {0, 2, 4, 6},\n",
- " 35: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 36: {0, 1, 4, 5},\n",
- " 37: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 38: {0, 2, 4, 6},\n",
- " 39: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 40: {0, 1, 2, 4, 5, 6},\n",
- " 41: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 42: {0, 2, 4, 6},\n",
- " 43: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 44: {0, 1, 4, 5},\n",
- " 45: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 46: {0, 2, 4, 6},\n",
- " 47: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 48: {0, 1, 2, 3},\n",
- " 49: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 50: {0, 2, 4, 6},\n",
- " 51: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 52: {0, 1, 4, 5},\n",
- " 53: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 54: {0, 2, 4, 6},\n",
- " 55: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 56: {0, 1, 2, 4, 5, 6},\n",
- " 57: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 58: {0, 2, 4, 6},\n",
- " 59: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 60: {0, 1, 4, 5},\n",
- " 61: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 62: {0, 2, 4, 6},\n",
- " 63: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 64: {0, 1, 2, 3, 4, 5},\n",
- " 65: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 66: {0, 2, 4, 6},\n",
- " 67: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 68: {0, 1, 4, 5},\n",
- " 69: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 70: {0, 2, 4, 6},\n",
- " 71: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 72: {0, 1, 2, 4, 5, 6},\n",
- " 73: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 74: {0, 2, 4, 6},\n",
- " 75: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 76: {0, 1, 4, 5},\n",
- " 77: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 78: {0, 2, 4, 6},\n",
- " 79: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 80: {0, 1, 2, 3},\n",
- " 81: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 82: {0, 2, 4, 6},\n",
- " 83: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 84: {0, 1, 4, 5},\n",
- " 85: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 86: {0, 2, 4, 6},\n",
- " 87: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 88: {0, 1, 2, 4, 5, 6},\n",
- " 89: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 90: {0, 2, 4, 6},\n",
- " 91: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 92: {0, 1, 4, 5},\n",
- " 93: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 94: {0, 2, 4, 6},\n",
- " 95: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 96: {0, 1, 2, 3, 4, 6},\n",
- " 97: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 98: {0, 2, 4, 6},\n",
- " 99: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 100: {0, 1, 4, 5},\n",
- " 101: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 102: {0, 2, 4, 6},\n",
- " 103: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 104: {0, 1, 2, 4, 5, 6},\n",
- " 105: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 106: {0, 2, 4, 6},\n",
- " 107: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 108: {0, 1, 4, 5},\n",
- " 109: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 110: {0, 2, 4, 6},\n",
- " 111: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 112: {0, 1, 2, 3},\n",
- " 113: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 114: {0, 2, 4, 6},\n",
- " 115: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 116: {0, 1, 4, 5},\n",
- " 117: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 118: {0, 2, 4, 6},\n",
- " 119: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 120: {0, 1, 2, 4, 5, 6},\n",
- " 121: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 122: {0, 2, 4, 6},\n",
- " 123: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 124: {0, 1, 4, 5},\n",
- " 125: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 126: {0, 2, 4, 6},\n",
- " 127: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 128: {0, 1, 2, 3, 4, 5, 6},\n",
- " 129: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 130: {0, 2, 4, 6},\n",
- " 131: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 132: {0, 1, 4, 5},\n",
- " 133: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 134: {0, 2, 4, 6},\n",
- " 135: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 136: {0, 1, 2, 4, 5, 6},\n",
- " 137: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 138: {0, 2, 4, 6},\n",
- " 139: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 140: {0, 1, 4, 5},\n",
- " 141: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 142: {0, 2, 4, 6},\n",
- " 143: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 144: {0, 1, 2, 3},\n",
- " 145: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 146: {0, 2, 4, 6},\n",
- " 147: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 148: {0, 1, 4, 5},\n",
- " 149: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 150: {0, 2, 4, 6},\n",
- " 151: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 152: {0, 1, 2, 4, 5, 6},\n",
- " 153: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 154: {0, 2, 4, 6},\n",
- " 155: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 156: {0, 1, 4, 5},\n",
- " 157: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 158: {0, 2, 4, 6},\n",
- " 159: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 160: {0, 1, 2, 3, 4, 6},\n",
- " 161: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 162: {0, 2, 4, 6},\n",
- " 163: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 164: {0, 1, 4, 5},\n",
- " 165: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 166: {0, 2, 4, 6},\n",
- " 167: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 168: {0, 1, 2, 4, 5, 6},\n",
- " 169: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 170: {0, 2, 4, 6},\n",
- " 171: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 172: {0, 1, 4, 5},\n",
- " 173: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 174: {0, 2, 4, 6},\n",
- " 175: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 176: {0, 1, 2, 3},\n",
- " 177: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 178: {0, 2, 4, 6},\n",
- " 179: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 180: {0, 1, 4, 5},\n",
- " 181: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 182: {0, 2, 4, 6},\n",
- " 183: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 184: {0, 1, 2, 4, 5, 6},\n",
- " 185: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 186: {0, 2, 4, 6},\n",
- " 187: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 188: {0, 1, 4, 5},\n",
- " 189: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 190: {0, 2, 4, 6},\n",
- " 191: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 192: {0, 1, 2, 3, 4, 5},\n",
- " 193: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 194: {0, 2, 4, 6},\n",
- " 195: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 196: {0, 1, 4, 5},\n",
- " 197: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 198: {0, 2, 4, 6},\n",
- " 199: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 200: {0, 1, 2, 4, 5, 6},\n",
- " 201: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 202: {0, 2, 4, 6},\n",
- " 203: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 204: {0, 1, 4, 5},\n",
- " 205: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 206: {0, 2, 4, 6},\n",
- " 207: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 208: {0, 1, 2, 3},\n",
- " 209: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 210: {0, 2, 4, 6},\n",
- " 211: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 212: {0, 1, 4, 5},\n",
- " 213: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 214: {0, 2, 4, 6},\n",
- " 215: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 216: {0, 1, 2, 4, 5, 6},\n",
- " 217: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 218: {0, 2, 4, 6},\n",
- " 219: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 220: {0, 1, 4, 5},\n",
- " 221: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 222: {0, 2, 4, 6},\n",
- " 223: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 224: {0, 1, 2, 3, 4, 6},\n",
- " 225: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 226: {0, 2, 4, 6},\n",
- " 227: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 228: {0, 1, 4, 5},\n",
- " 229: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 230: {0, 2, 4, 6},\n",
- " 231: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 232: {0, 1, 2, 4, 5, 6},\n",
- " 233: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 234: {0, 2, 4, 6},\n",
- " 235: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 236: {0, 1, 4, 5},\n",
- " 237: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 238: {0, 2, 4, 6},\n",
- " 239: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 240: {0, 1, 2, 3},\n",
- " 241: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 242: {0, 2, 4, 6},\n",
- " 243: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 244: {0, 1, 4, 5},\n",
- " 245: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 246: {0, 2, 4, 6},\n",
- " 247: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 248: {0, 1, 2, 4, 5, 6},\n",
- " 249: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 250: {0, 2, 4, 6},\n",
- " 251: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 252: {0, 1, 4, 5},\n",
- " 253: {0, 1, 2, 3, 4, 5, 6, 7},\n",
- " 254: {0, 2, 4, 6},\n",
- " 255: {0, 1, 2, 3, 4, 5, 6, 7}}"
+ "'HHHH'"
]
},
- "execution_count": 28,
+ "execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "dict(zip(range(1, 256), solution8))"
+ "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' in 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": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 1: HTTHTTHT rot: TTHTTHTH flip: 01234567 => HHTHHTHT\n",
+ " 2: HHTHHTHT rot: THTHHTHH flip: 0 2 4 6 => HHHHTTTH\n",
+ " 3: HHHHTTTH rot: HHHHTTTH flip: 01234567 => TTTTHHHT\n",
+ " 4: TTTTHHHT rot: HHHTTTTT flip: 01 45 => TTHTHHTT\n",
+ " 5: TTHTHHTT rot: THHTTTTH flip: 01234567 => HTTHHHHT\n",
+ " 6: HTTHHHHT rot: THTTHHHH flip: 0 2 4 6 => HHHTTHTH\n",
+ " 7: HHHTTHTH rot: TTHTHHHH flip: 01234567 => HHTHTTTT\n",
+ " 8: HHTHTTTT rot: THTTTTHH flip: 012 456 => HTHTHHTH\n",
+ " 9: HTHTHHTH rot: HHTHHTHT flip: 01234567 => TTHTTHTH\n",
+ " 10: TTHTTHTH rot: HTTHTHTT flip: 0 2 4 6 => TTHHHHHT\n",
+ " 11: TTHHHHHT rot: THHHHHTT flip: 01234567 => HTTTTTHH\n",
+ " 12: HTTTTTHH rot: TTTHHHTT flip: 01 45 => HHTHTTTT\n",
+ " 13: HHTHTTTT rot: THTTTTHH flip: 01234567 => HTHHHHTT\n",
+ " 14: HTHHHHTT rot: TTHTHHHH flip: 0 2 4 6 => HTTTTHTH\n",
+ " 15: HTTTTHTH rot: TTHTHHTT flip: 01234567 => HHTHTTHH\n",
+ " 16: HHTHTTHH rot: THHHHTHT flip: 0123 => HTTTHTHT\n",
+ " 17: HTTTHTHT rot: HTHTHTTT flip: 01234567 => THTHTHHH\n",
+ " 18: THTHTHHH rot: HTHTHTHH flip: 0 2 4 6 => TTTTTTTH\n",
+ " 19: TTTTTTTH rot: TTTTTTTH flip: 01234567 => HHHHHHHT\n",
+ " 20: HHHHHHHT rot: THHHHHHH flip: 01 45 => HTHHTTHH\n",
+ " 21: HTHHTTHH rot: HHTHHTTH flip: 01234567 => TTHTTHHT\n",
+ " 22: TTHTTHHT rot: THHTTTHT flip: 0 2 4 6 => HHTTHTTT\n",
+ " 23: HHTTHTTT rot: HTTTHHTT flip: 01234567 => THHHTTHH\n",
+ " 24: THHHTTHH rot: THHTHHHT flip: 012 456 => HTTTTTTT\n",
+ " 25: HTTTTTTT rot: TTTTTHTT flip: 01234567 => HHHHHTHH\n",
+ " 26: HHHHHTHH rot: HHTHHHHH flip: 0 2 4 6 => THHHTHTH\n",
+ " 27: THHHTHTH rot: HTHTHTHH flip: 01234567 => THTHTHTT\n",
+ " 28: THTHTHTT rot: TTHTHTHT flip: 01 45 => HHHTTHHT\n",
+ " 29: HHHTTHHT rot: TTHHTHHH flip: 01234567 => HHTTHTTT\n",
+ " 30: HHTTHTTT rot: HTTTHHTT flip: 0 2 4 6 => TTHTTHHT\n",
+ " 31: TTHTTHHT rot: HTTHHTTT flip: 01234567 => THHTTHHH\n",
+ " 32: THHTTHHH rot: HTTHHHTH flip: 01234 6 => THHTTHHH\n",
+ " 33: THHTTHHH rot: TTHHHTHH flip: 01234567 => HHTTTHTT\n",
+ " 34: HHTTTHTT rot: TTHHTTTH flip: 0 2 4 6 => HTTHHTHH\n",
+ " 35: HTTHHTHH rot: TTHHTHHH flip: 01234567 => HHTTHTTT\n",
+ " 36: HHTTHTTT rot: HTTHTTTH flip: 01 45 => THTHHHTH\n",
+ " 37: THTHHHTH rot: HTHTHHHT flip: 01234567 => THTHTTTH\n",
+ " 38: THTHTTTH rot: HTHTTTHT flip: 0 2 4 6 => TTTTHTTT\n",
+ " 39: TTTTHTTT rot: THTTTTTT flip: 01234567 => HTHHHHHH\n",
+ " 40: HTHHHHHH rot: HHHHHHTH flip: 012 456 => TTTHTTHH\n",
+ " 41: TTTHTTHH rot: TTHTTHHT flip: 01234567 => HHTHHTTH\n",
+ " 42: HHTHHTTH rot: THHTTHHH flip: 0 2 4 6 => HHTTHHTH\n",
+ " 43: HHTTHHTH rot: HHHTTHHT flip: 01234567 => TTTHHTTH\n",
+ " 44: TTTHHTTH rot: HHTTHTTT flip: 01 45 => TTTTTHTT\n",
+ " 45: TTTTTHTT rot: TTTTTTHT flip: 01234567 => HHHHHHTH\n",
+ " 46: HHHHHHTH rot: HHHHHHHT flip: 0 2 4 6 => THTHTHTT\n",
+ " 47: THTHTHTT rot: THTHTTTH flip: 01234567 => HTHTHHHT\n",
+ " 48: HTHTHHHT rot: HTHHHTHT flip: 0123 => THTTHTHT\n",
+ " 49: THTTHTHT rot: TTHTHTTH flip: 01234567 => HHTHTHHT\n",
+ " 50: HHTHTHHT rot: THTHHTHH flip: 0 2 4 6 => HHHHTTTH\n",
+ " 51: HHHHTTTH rot: HHHHTTTH flip: 01234567 => TTTTHHHT\n",
+ " 52: TTTTHHHT rot: TTHHHTTT flip: 01 45 => HHHHTHTT\n",
+ " 53: HHHHTHTT rot: TTHHHHTH flip: 01234567 => HHTTTTHT\n",
+ " 54: HHTTTTHT rot: THHTTTTH flip: 0 2 4 6 => HHTTHTHH\n",
+ " 55: HHTTHTHH rot: HHTTHTHH flip: 01234567 => TTHHTHTT\n",
+ " 56: TTHHTHTT rot: TTTTHHTH flip: 012 456 => HHHTTTHH\n",
+ " 57: HHHTTTHH rot: HHHHTTTH flip: 01234567 => TTTTHHHT\n",
+ " 58: TTTTHHHT rot: TTTTTHHH flip: 0 2 4 6 => HTHTHHTH\n",
+ " 59: HTHTHHTH rot: THHTHHTH flip: 01234567 => HTTHTTHT\n",
+ " 60: HTTHTTHT rot: THTHTTHT flip: 01 45 => HTTHHHHT\n",
+ " 61: HTTHHHHT rot: THTTHHHH flip: 01234567 => HTHHTTTT\n",
+ " 62: HTHHTTTT rot: TTHTHHTT flip: 0 2 4 6 => HTTTTHHT\n",
+ " 63: HTTTTHHT rot: HHTHTTTT flip: 01234567 => TTHTHHHH\n",
+ " 64: TTHTHHHH rot: TTHTHHHH flip: 012345 => HHTHTTHH\n",
+ " 65: HHTHTTHH rot: TTHHHHTH flip: 01234567 => HHTTTTHT\n",
+ " 66: HHTTTTHT rot: THTHHTTT flip: 0 2 4 6 => HHHHTTHT\n",
+ " 67: HHHHTTHT rot: THTHHHHT flip: 01234567 => HTHTTTTH\n",
+ " 68: HTHTTTTH rot: THTTTTHH flip: 01 45 => HTTTHHHH\n",
+ " 69: HTTTHHHH rot: TTTHHHHH flip: 01234567 => HHHTTTTT\n",
+ " 70: HHHTTTTT rot: TTTTTHHH flip: 0 2 4 6 => HTHTHHTH\n",
+ " 71: HTHTHHTH rot: HHTHHTHT flip: 01234567 => TTHTTHTH\n",
+ " 72: TTHTTHTH rot: TTHTHTTH flip: 012 456 => HHTTTHHH\n",
+ " 73: HHTTTHHH rot: TTHHHHHT flip: 01234567 => HHTTTTTH\n",
+ " 74: HHTTTTTH rot: TTTTHHHT flip: 0 2 4 6 => HTHTTHTT\n",
+ " 75: HTHTTHTT rot: TTHTHTTH flip: 01234567 => HHTHTHHT\n",
+ " 76: HHTHTHHT rot: HTHHTHTH flip: 01 45 => THHHHTTH\n",
+ " 77: THHHHTTH rot: THTHHHHT flip: 01234567 => HTHTTTTH\n",
+ " 78: HTHTTTTH rot: TTTTHHTH flip: 0 2 4 6 => HTHTTHHH\n",
+ " 79: HTHTTHHH rot: HTTHHHHT flip: 01234567 => THHTTTTH\n",
+ " 80: THHTTTTH rot: TTTHTHHT flip: 0123 => HHHTTHHT\n",
+ " 81: HHHTTHHT rot: HTHHHTTH flip: 01234567 => THTTTHHT\n",
+ " 82: THTTTHHT rot: TTHHTTHT flip: 0 2 4 6 => HTTHHTTT\n",
+ " 83: HTTHHTTT rot: TTTHTTHH flip: 01234567 => HHHTHHTT\n",
+ " 84: HHHTHHTT rot: THHTTHHH flip: 01 45 => HTHTHTHH\n",
+ " 85: HTHTHTHH rot: HTHHHTHT flip: 01234567 => THTTTHTH\n",
+ " 86: THTTTHTH rot: THTHTHTT flip: 0 2 4 6 => HHHHHHHT\n",
+ " 87: HHHHHHHT rot: HHHHHHTH flip: 01234567 => TTTTTTHT\n",
+ " 88: TTTTTTHT rot: THTTTTTT flip: 012 456 => HTHTHHHT\n",
+ " 89: HTHTHHHT rot: HHTHTHTH flip: 01234567 => TTHTHTHT\n",
+ " 90: TTHTHTHT rot: TTHTHTHT flip: 0 2 4 6 => HTTTTTTT\n",
+ " 91: HTTTTTTT rot: TTTTTHTT flip: 01234567 => HHHHHTHH\n",
+ " 92: HHHHHTHH rot: HHHTHHHH flip: 01 45 => TTHTTTHH\n",
+ " 93: TTHTTTHH rot: THTTTHHT flip: 01234567 => HTHHHTTH\n",
+ " 94: HTHHHTTH rot: HTTHHTHH flip: 0 2 4 6 => TTHHTTTH\n",
+ " 95: TTHHTTTH rot: HHTTTHTT flip: 01234567 => TTHHHTHH\n",
+ " 96: TTHHHTHH rot: HTHHTTHH flip: 01234 6 => THTTHTTH\n",
+ " 97: THTTHTTH rot: HTTHTHTT flip: 01234567 => THHTHTHH\n",
+ " 98: THHTHTHH rot: HHTHTHHT flip: 0 2 4 6 => THHHHHTT\n",
+ " 99: THHHHHTT rot: HHHHHTTT flip: 01234567 => TTTTTHHH\n",
+ " 100: TTTTTHHH rot: TTTHHHTT flip: 01 45 => HHTHTTTT\n",
+ " 101: HHTHTTTT rot: HTHTTTTH flip: 01234567 => THTHHHHT\n",
+ " 102: THTHHHHT rot: THTHHHHT flip: 0 2 4 6 => HHHHTHTT\n",
+ " 103: HHHHTHTT rot: HTHTTHHH flip: 01234567 => THTHHTTT\n",
+ " 104: THTHHTTT rot: TTTTHTHH flip: 012 456 => HHHTTHTH\n",
+ " 105: HHHTTHTH rot: TTHTHHHH flip: 01234567 => HHTHTTTT\n",
+ " 106: HHTHTTTT rot: HHTHTTTT flip: 0 2 4 6 => THHHHTHT\n",
+ " 107: THHHHTHT rot: HHHTHTTH flip: 01234567 => TTTHTHHT\n",
+ " 108: TTTHTHHT rot: TTTHTHHT flip: 01 45 => HHTHHTHT\n",
+ " 109: HHTHHTHT rot: HHTHTHHT flip: 01234567 => TTHTHTTH\n",
+ " 110: TTHTHTTH rot: THTHTTHT flip: 0 2 4 6 => HHHHHTTT\n",
+ " 111: HHHHHTTT rot: HTTTHHHH flip: 01234567 => THHHTTTT\n",
+ " 112: THHHTTTT rot: TTTTTHHH flip: 0123 => HHHHTHHH\n",
+ " 113: HHHHTHHH rot: HTHHHHHH flip: 01234567 => THTTTTTT\n",
+ " 114: THTTTTTT rot: THTTTTTT flip: 0 2 4 6 => HHHTHTHT\n",
+ " 115: HHHTHTHT rot: HHTHTHTH flip: 01234567 => TTHTHTHT\n",
+ " 116: TTHTHTHT rot: HTHTHTTT flip: 01 45 => THHTTHTT\n",
+ " 117: THHTTHTT rot: THTTTHHT flip: 01234567 => HTHHHTTH\n",
+ " 118: HTHHHTTH rot: HHTHHHTT flip: 0 2 4 6 => THHHTHHT\n",
+ " 119: THHHTHHT rot: THHHTHHT flip: 01234567 => HTTTHTTH\n",
+ " 120: HTTTHTTH rot: THHTTTHT flip: 012 456 => HTTTHHTT\n",
+ " 121: HTTTHHTT rot: HHTTHTTT flip: 01234567 => TTHHTHHH\n",
+ " 122: TTHHTHHH rot: HTHHHTTH flip: 0 2 4 6 => TTTHTTHH\n",
+ " 123: TTTHTTHH rot: THHTTTHT flip: 01234567 => HTTHHHTH\n",
+ " 124: HTTHHHTH rot: HHTTHHHT flip: 01 45 => TTTTTTHT\n",
+ " 125: TTTTTTHT rot: TTTTTHTT flip: 01234567 => HHHHHTHH\n",
+ " 126: HHHHHTHH rot: HHHHHHTH flip: 0 2 4 6 => THTHTHHH\n",
+ " 127: THTHTHHH rot: THHHTHTH flip: 01234567 => HTTTHTHT\n",
+ " 128: HTTTHTHT rot: TTHTHTHT flip: 0123456 => HHTHTHTT\n",
+ " 129: HHTHTHTT rot: HTHTTHHT flip: 01234567 => THTHHTTH\n",
+ " 130: THTHHTTH rot: THTHTHHT flip: 0 2 4 6 => HHHHHHTT\n",
+ " 131: HHHHHHTT rot: TTHHHHHH flip: 01234567 => HHTTTTTT\n",
+ " 132: HHTTTTTT rot: THHTTTTT flip: 01 45 => HTHTHHTT\n",
+ " 133: HTHTHHTT rot: TTHTHTHH flip: 01234567 => HHTHTHTT\n",
+ " 134: HHTHTHTT rot: THTTHHTH flip: 0 2 4 6 => HHHTTHHH\n",
+ " 135: HHHTTHHH rot: THHHHHHT flip: 01234567 => HTTTTTTH\n",
+ " 136: HTTTTTTH rot: TTTTTHHT flip: 012 456 => HHHTHTTT\n",
+ " 137: HHHTHTTT rot: HTHTTTHH flip: 01234567 => THTHHHTT\n",
+ " 138: THTHHHTT rot: TTTHTHHH flip: 0 2 4 6 => HTHHHHTH\n",
+ " 139: HTHHHHTH rot: HTHHTHHH flip: 01234567 => THTTHTTT\n",
+ " 140: THTTHTTT rot: TTHTTHTT flip: 01 45 => HHHTHTTT\n",
+ " 141: HHHTHTTT rot: HHTHTTTH flip: 01234567 => TTHTHHHT\n",
+ " 142: TTHTHHHT rot: THTHHHTT flip: 0 2 4 6 => HHHHTHHT\n",
+ " 143: HHHHTHHT rot: HTHHTHHH flip: 01234567 => THTTHTTT\n",
+ " 144: THTTHTTT rot: HTTHTTTT flip: 0123 => THHTTTTT\n",
+ " 145: THHTTTTT rot: THHTTTTT flip: 01234567 => HTTHHHHH\n",
+ " 146: HTTHHHHH rot: HHHTTHHH flip: 0 2 4 6 => THTTHHTH\n",
+ " 147: THTTHHTH rot: HTHTTHHT flip: 01234567 => THTHHTTH\n",
+ " 148: THTHHTTH rot: THTHTHHT flip: 01 45 => HTTHHTHT\n",
+ " 149: HTTHHTHT rot: HHTHTHTT flip: 01234567 => TTHTHTHH\n",
+ " 150: TTHTHTHH rot: HTTHTHTH flip: 0 2 4 6 => TTHHHHHH\n",
+ " 151: TTHHHHHH rot: HHHTTHHH flip: 01234567 => TTTHHTTT\n",
+ " 152: TTTHHTTT rot: TTHHTTTT flip: 012 456 => HHTHHHHT\n",
+ " 153: HHTHHHHT rot: HTHHHHTH flip: 01234567 => THTTTTHT\n",
+ " 154: THTTTTHT rot: HTTHTTTT flip: 0 2 4 6 => TTHHHTHT\n",
+ " 155: TTHHHTHT rot: HHHTHTTT flip: 01234567 => TTTHTHHH\n",
+ " 156: TTTHTHHH rot: THTHHHTT flip: 01 45 => HTTHTTTT\n",
+ " 157: HTTHTTTT rot: THTTHTTT flip: 01234567 => HTHHTHHH\n",
+ " 158: HTHHTHHH rot: THHTHHHH flip: 0 2 4 6 => HHTTTHTH\n",
+ " 159: HHTTTHTH rot: HHHTTTHT flip: 01234567 => TTTHHHTH\n",
+ " 160: TTTHHHTH rot: HTHTTTHH flip: 01234 6 => THTHHTTH\n",
+ " 161: THTHHTTH rot: HTHHTTHT flip: 01234567 => THTTHHTH\n",
+ " 162: THTTHHTH rot: HTHTTHHT flip: 0 2 4 6 => TTTTHHTT\n",
+ " 163: TTTTHHTT rot: TTHHTTTT flip: 01234567 => HHTTHHHH\n",
+ " 164: HHTTHHHH rot: HHHHTTHH flip: 01 45 => TTHHHHHH\n",
+ " 165: TTHHHHHH rot: HHHHHTTH flip: 01234567 => TTTTTHHT\n",
+ " 166: TTTTTHHT rot: HTTTTTTH flip: 0 2 4 6 => TTHTHTHH\n",
+ " 167: TTHTHTHH rot: THHTTHTH flip: 01234567 => HTTHHTHT\n",
+ " 168: HTTHHTHT rot: TTHHTHTH flip: 012 456 => HHTHHTHH\n",
+ " 169: HHTHHTHH rot: THHTHHHH flip: 01234567 => HTTHTTTT\n",
+ " 170: HTTHTTTT rot: TTTHTTHT flip: 0 2 4 6 => HTHHHTTT\n",
+ " 171: HTHHHTTT rot: TTTHTHHH flip: 01234567 => HHHTHTTT\n",
+ " 172: HHHTHTTT rot: TTHHHTHT flip: 01 45 => HHHHTHHT\n",
+ " 173: HHHHTHHT rot: THHTHHHH flip: 01234567 => HTTHTTTT\n",
+ " 174: HTTHTTTT rot: THTTHTTT flip: 0 2 4 6 => HHHTTTHT\n",
+ " 175: HHHTTTHT rot: HHHTTTHT flip: 01234567 => TTTHHHTH\n",
+ " 176: TTTHHHTH rot: HTHTTTHH flip: 0123 => THTHTTHH\n",
+ " 177: THTHTTHH rot: HTTHHTHT flip: 01234567 => THHTTHTH\n",
+ " 178: THHTTHTH rot: THHTTHTH flip: 0 2 4 6 => HHTTHHHH\n",
+ " 179: HHTTHHHH rot: HHTTHHHH flip: 01234567 => TTHHTTTT\n",
+ " 180: TTHHTTTT rot: HHTTTTTT flip: 01 45 => TTTTHHTT\n",
+ " 181: TTTTHHTT rot: TTHHTTTT flip: 01234567 => HHTTHHHH\n",
+ " 182: HHTTHHHH rot: THHHHHHT flip: 0 2 4 6 => HHTHTHTT\n",
+ " 183: HHTHTHTT rot: HTTHHTHT flip: 01234567 => THHTTHTH\n",
+ " 184: THHTTHTH rot: HHTTHTHT flip: 012 456 => TTHTTHTT\n",
+ " 185: TTHTTHTT rot: TTTTHTTH flip: 01234567 => HHHHTHHT\n",
+ " 186: HHHHTHHT rot: HTHHTHHH flip: 0 2 4 6 => TTTHHHTH\n",
+ " 187: TTTHHHTH rot: TTTHHHTH flip: 01234567 => HHHTTTHT\n",
+ " 188: HHHTTTHT rot: THHHTTTH flip: 01 45 => HTHHHHTH\n",
+ " 189: HTHHHHTH rot: HTHHHHTH flip: 01234567 => THTTTTHT\n",
+ " 190: THTTTTHT rot: HTTHTTTT flip: 0 2 4 6 => TTHHHTHT\n",
+ " 191: TTHHHTHT rot: TTTHHHTH flip: 01234567 => HHHTTTHT\n",
+ " 192: HHHTTTHT rot: THHHTTTH flip: 012345 => HTTTHHTH\n",
+ " 193: HTTTHHTH rot: THHTTTHH flip: 01234567 => HTTHHHTT\n",
+ " 194: HTTHHHTT rot: HHTTHTTH flip: 0 2 4 6 => THHTTTHH\n",
+ " 195: THHTTTHH rot: THHTTTHH flip: 01234567 => HTTHHHTT\n",
+ " 196: HTTHHHTT rot: THTTHHHT flip: 01 45 => HTTTTTHT\n",
+ " 197: HTTTTTHT rot: TTTHTHTT flip: 01234567 => HHHTHTHH\n",
+ " 198: HHHTHTHH rot: THHHHHTH flip: 0 2 4 6 => HHTHTHHH\n",
+ " 199: HHTHTHHH rot: HHTHTHHH flip: 01234567 => TTHTHTTT\n",
+ " 200: TTHTHTTT rot: TTTTTHTH flip: 012 456 => HHHTHTHH\n",
+ " 201: HHHTHTHH rot: HHTHTHHH flip: 01234567 => TTHTHTTT\n",
+ " 202: TTHTHTTT rot: HTTTTTHT flip: 0 2 4 6 => TTHTHTTT\n",
+ " 203: TTHTHTTT rot: TTTTHTHT flip: 01234567 => HHHHTHTH\n",
+ " 204: HHHHTHTH rot: HHHTHTHH flip: 01 45 => TTHTTHHH\n",
+ " 205: TTHTTHHH rot: TTHTTHHH flip: 01234567 => HHTHHTTT\n",
+ " 206: HHTHHTTT rot: TTHHTHHT flip: 0 2 4 6 => HTTHHHTT\n",
+ " 207: HTTHHHTT rot: HHTTHTTH flip: 01234567 => TTHHTHHT\n",
+ " 208: TTHHTHHT rot: THHTHHTT flip: 0123 => HTTHHHTT\n",
+ " 209: HTTHHHTT rot: HTTHTTHH flip: 01234567 => THHTHHTT\n",
+ " 210: THHTHHTT rot: TTTHHTHH flip: 0 2 4 6 => HTHHTTTH\n",
+ " 211: HTHHTTTH rot: HTTTHHTH flip: 01234567 => THHHTTHT\n",
+ " 212: THHHTTHT rot: HTTHTTHH flip: 01 45 => THTHHHHH\n",
+ " 213: THTHHHHH rot: HHTHTHHH flip: 01234567 => TTHTHTTT\n",
+ " 214: TTHTHTTT rot: THTHTTTT flip: 0 2 4 6 => HHHHHTHT\n",
+ " 215: HHHHHTHT rot: HHHTHTHH flip: 01234567 => TTTHTHTT\n",
+ " 216: TTTHTHTT rot: TTTHTHTT flip: 012 456 => HHHHHTHT\n",
+ " 217: HHHHHTHT rot: HHHHTHTH flip: 01234567 => TTTTHTHT\n",
+ " 218: TTTTHTHT rot: TTTTHTHT flip: 0 2 4 6 => HTHTTTTT\n",
+ " 219: HTHTTTTT rot: TTTHTHTT flip: 01234567 => HHHTHTHH\n",
+ " 220: HHHTHTHH rot: HHTHTHHH flip: 01 45 => TTTHHTHH\n",
+ " 221: TTTHHTHH rot: TTTHHTHH flip: 01234567 => HHHTTHTT\n",
+ " 222: HHHTTHTT rot: HTTHTTHH flip: 0 2 4 6 => TTHHHTTH\n",
+ " 223: TTHHHTTH rot: HTTHTTHH flip: 01234567 => THHTHHTT\n",
+ " 224: THHTHHTT rot: TTHHTHHT flip: 01234 6 => HHTTHHTT\n",
+ " 225: HHTTHHTT rot: THHTTHHT flip: 01234567 => HTTHHTTH\n",
+ " 226: HTTHHTTH rot: HHTTHHTT flip: 0 2 4 6 => THHTTHHT\n",
+ " 227: THHTTHHT rot: HTTHHTTH flip: 01234567 => THHTTHHT\n",
+ " 228: THHTTHHT rot: HTTHHTTH flip: 01 45 => THTHTHTH\n",
+ " 229: THTHTHTH rot: THTHTHTH flip: 01234567 => HTHTHTHT\n",
+ " 230: HTHTHTHT rot: THTHTHTH flip: 0 2 4 6 => HHHHHHHH\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'HHHHHHHH'"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "play('HTTHTTHT', strategy, True)"
]
}
],