diff --git a/Ghost.ipynb b/Ghost.ipynb index e39b09d..a302c5e 100644 --- a/Ghost.ipynb +++ b/Ghost.ipynb @@ -47,7 +47,8 @@ " self.words = {word for word in words if len(word) >= minlength}\n", " self.fragments = {word[:i] for word in self.words for i in range(len(word) + 1)}\n", " \n", - " def legal_plays(self, fragment): return {fragment + L for L in alphabet} & self.fragments \n", + " def legal_plays(self, fragment): \n", + " return {fragment + L for L in alphabet} & self.fragments \n", " \n", "alphabet = 'abcdefghijklmnopqrstuvwxyz'\n", " \n", @@ -58,7 +59,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Here is a small example:" + "Here is a small example with a vocabulary of just three words:" ] }, { @@ -71,8 +72,7 @@ { "data": { "text/plain": [ - "({'game', 'ghost', 'ghoul'},\n", - " {'', 'g', 'ga', 'gam', 'game', 'gh', 'gho', 'ghos', 'ghost', 'ghou', 'ghoul'})" + "{'game', 'ghost', 'ghoul'}" ] }, "execution_count": 2, @@ -83,7 +83,29 @@ "source": [ "v = Vocabulary(words('game ghost ghoul'))\n", "\n", - "v.words, v.fragments" + "v.words" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'', 'g', 'ga', 'gam', 'game', 'gh', 'gho', 'ghos', 'ghost', 'ghou', 'ghoul'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v.fragments" ] }, { @@ -95,7 +117,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -106,7 +128,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "collapsed": false }, @@ -124,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "collapsed": false }, @@ -135,35 +157,13 @@ "(172724, 387878, 'ethylenediaminetetraacetates')" ] }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(enable1.words), len(enable1.fragments), max(enable1.words, key=len)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'ghos', 'ghou'}" - ] - }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "enable1.legal_plays('gho')" + "len(enable1.words), len(enable1.fragments), max(enable1.words, key=len)" ] }, { @@ -176,7 +176,7 @@ { "data": { "text/plain": [ - "{'ewe'}" + "{'ghos', 'ghou'}" ] }, "execution_count": 7, @@ -185,7 +185,7 @@ } ], "source": [ - "enable1.legal_plays('ew')" + "enable1.legal_plays('gho')" ] }, { @@ -198,7 +198,7 @@ { "data": { "text/plain": [ - "{'tha', 'the', 'thi', 'tho', 'thr', 'thu', 'thw', 'thy'}" + "{'ewe'}" ] }, "execution_count": 8, @@ -206,6 +206,28 @@ "output_type": "execute_result" } ], + "source": [ + "enable1.legal_plays('ew')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'tha', 'the', 'thi', 'tho', 'thr', 'thu', 'thw', 'thy'}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "enable1.legal_plays('th')" ] @@ -223,7 +245,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -238,35 +260,16 @@ "source": [ "# Who Wins?\n", "\n", - "Who wins a game if both players are rational? Given the current fragment, the player whose turn it is will win if either:\n", + "Who wins a game if both players play rationally? To answer that, consider the general situation at some point\n", + "suring the game where\n", + "a player is presented with a fragment. That player can win if either:\n", "- The fragment is a word (meaning the other player formed the word, and lost).\n", - "- The fragment is not a legal fragment (meaning the other player formed a non-prefix, and lost).\n", + "- The fragment is not a legal fragment (meaning the other player made a mistake, and lost).\n", "- At least one of the legal plays puts the opponent in a position from which they *cannot* win.\n", "\n", - "The function `win(vocab, fragment)` implements this idea, returning `True` if the current player can force a win." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def win(vocab, fragment=''):\n", - " \"Does the player whose turn it is have a forced win?\"\n", - " return (fragment in vocab.words or \n", - " fragment not in vocab.fragments or\n", - " any(not win(vocab, play) \n", - " for play in vocab.legal_plays(fragment)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's test `win` to gain some confidence that we got it right:" + "The function `win(vocab, fragment)` implements this idea. It returns a winning fragment if there is one, otherwise `None`. In particular, it returns `fragment` if the current player has already won because `fragment` forms\n", + "a word or illegal fragment, and it returns one of the legal plays if the play leads to a position from\n", + "which the opponent *cannot* `win`." ] }, { @@ -275,20 +278,24 @@ "metadata": { "collapsed": false }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "win(Vocabulary(words('cat camel'))) # All words have odd number of letters; first player loses" + "def win(vocab, fragment=''):\n", + " \"\"\"Does the current player have a forced win? \n", + " Return fragment if the player has already won, or return a play that forces a win.\"\"\"\n", + " if fragment in vocab.words or fragment not in vocab.fragments:\n", + " return fragment\n", + " for play in vocab.legal_plays(fragment):\n", + " if not win(vocab, play):\n", + " return play \n", + " return False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's test `win` to gain some confidence that we got it right:" ] }, { @@ -301,7 +308,7 @@ { "data": { "text/plain": [ - "True" + "False" ] }, "execution_count": 12, @@ -310,7 +317,8 @@ } ], "source": [ - "win(Vocabulary(words('cat camel goat'))) # First player plays 'g', leading to a win with 'goat'" + "# No winning play because all words have odd number of letters.\n", + "win(Vocabulary(words('cat camel gecko'))) " ] }, { @@ -323,7 +331,7 @@ { "data": { "text/plain": [ - "False" + "'g'" ] }, "execution_count": 13, @@ -332,7 +340,8 @@ } ], "source": [ - "win(Vocabulary(words('cat camel goat gar'))) # Second player can avoid 'goat' with 'ga'" + "# 'g' is a winning play (but 'c' wuld be a loser)\n", + "win(Vocabulary(words('cat camel goat gerbil'))) " ] }, { @@ -345,7 +354,7 @@ { "data": { "text/plain": [ - "True" + "False" ] }, "execution_count": 14, @@ -354,7 +363,31 @@ } ], "source": [ - "win(Vocabulary(words('cat camel goat gar gannet'))) # First player plays 'gan' after 'ga' to win" + "# No winning play; dommed to 'camel' or 'gar'\n", + "win(Vocabulary(words('cat camel goat gecko gerbil gar'))) " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'g'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 'g' wins because 'ga' can be answered with 'gan'\n", + "win(Vocabulary(words('cat camel goat gecko gerbil gar gannet'))) " ] }, { @@ -368,7 +401,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "collapsed": false }, @@ -379,7 +412,7 @@ "False" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -400,18 +433,26 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 6.35 ms, sys: 179 µs, total: 6.53 ms\n", + "Wall time: 7.14 ms\n" + ] + }, { "data": { "text/plain": [ - "True" + "'h'" ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -419,14 +460,14 @@ "source": [ "enable1_4 = Vocabulary(enable1.words, 4)\n", "\n", - "win(enable1_4)" + "%time win(enable1_4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Yes.** The first player can win in this case. (It is easier for the first player to win, because now it is the second player who has the first chance to lose (on the fourth play).) So here's a good meta-strategy: Say \"Hey, let's play a game of Ghost. We can use the `enable1` word list. Would you like the limit to be 3 or 4 letters?\" Then if your opponent says three (or four) you can say \"OK, since you decided that, I'll decide to go second (or first).\"" + "**Yes.** The first player can win with this vocabulary, by playing `'h'` first (and there might be other first plays that also force a win). It makes sense that it is easier for the first player to win, because we've eliminated a bunch of three-letter words from the vocabulary, all of which are losers for the first player. So here's a good meta-strategy: Say \"*Hey, let's play a game of Ghost. We can use the `enable1` word list. Would you like the limit to be 3 or 4 letters?*\" Then if your opponent says three (or four) you can say \"*OK, since you decided that, I'll decide to go second (or first).*\"" ] }, { @@ -440,7 +481,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "collapsed": false }, @@ -450,8 +491,7 @@ "\n", "def rational(vocab, fragment): \n", " \"Select a play that makes opponent not win (if possible), otherwise a random play.\"\n", - " plays = list(vocab.legal_plays(fragment))\n", - " return first(p for p in plays if not win(vocab, p)) or random.choice(plays)\n", + " return win(vocab, fragment) or random.choice(list(vocab.legal_plays(fragment)))\n", "\n", "def ask(name):\n", " \"Return a strategy that asks for the next letter.\"\n", @@ -471,7 +511,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": { "collapsed": false }, @@ -494,28 +534,6 @@ " fragment = play # Keep playing" ] }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 'ycleped')" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "play(enable1, rational, rational) " - ] - }, { "cell_type": "code", "execution_count": 20, @@ -526,16 +544,7 @@ { "data": { "text/plain": [ - "[(1, 'bwana'),\n", - " (1, 'bwana'),\n", - " (1, 'bwana'),\n", - " (1, 'bwana'),\n", - " (1, 'bwana'),\n", - " (1, 'dwarf'),\n", - " (1, 'hmm'),\n", - " (1, 'llano'),\n", - " (1, 'oquassa'),\n", - " (1, 'whiff')]" + "(1, 'llama')" ] }, "execution_count": 20, @@ -544,9 +553,7 @@ } ], "source": [ - "# Does player 1 win every time?\n", - "\n", - "sorted(play(enable1, rational, rational, verbose=False) for _ in range(10))" + "play(enable1, rational, rational) " ] }, { @@ -559,7 +566,26 @@ { "data": { "text/plain": [ - "(0, 'null')" + "[(1, 'dreck'),\n", + " (1, 'mho'),\n", + " (1, 'bwana'),\n", + " (1, 'aal'),\n", + " (1, 'gjetost'),\n", + " (1, 'oquassa'),\n", + " (1, 'oquassa'),\n", + " (1, 'yperite'),\n", + " (1, 'yperite'),\n", + " (1, 'plica'),\n", + " (1, 'wrest'),\n", + " (1, 'qursh'),\n", + " (1, 'aal'),\n", + " (1, 'aas'),\n", + " (1, 'tweak'),\n", + " (1, 'uintahite'),\n", + " (1, 'uintahite'),\n", + " (1, 'hmm'),\n", + " (1, 'uintahite'),\n", + " (1, 'jnana')]" ] }, "execution_count": 21, @@ -568,7 +594,9 @@ } ], "source": [ - "play(enable1_4, rational, rational)" + "# Does player 1 win every time?\n", + "\n", + "[play(enable1, rational, rational, verbose=False) for _ in range(20)]" ] }, { @@ -577,24 +605,45 @@ "metadata": { "collapsed": false }, + "outputs": [ + { + "data": { + "text/plain": [ + "(0, 'hugs')" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "play(enable1_4, rational, rational)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Player 0, given \"\", plays? d\n", - "Player 0, given \"dw\", plays? dwa\n", - "Player 0, given \"dwar\", plays? dwarv\n", - "Player 0, given \"dwarve\", plays? dwarves\n" + "Player 0, given \"dr\", plays? dri\n", + "Player 0, given \"drif\", plays? drift\n" ] }, { "data": { "text/plain": [ - "(1, 'dwarves')" + "(1, 'drift')" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -619,7 +668,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": { "collapsed": false }, @@ -671,7 +720,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": { "collapsed": false }, @@ -699,7 +748,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": { "collapsed": false }, @@ -709,7 +758,7 @@ "output_type": "stream", "text": [ "Outcomes (7) for player 0:\n", - "Winners (7): naan nene ngultrum nirvanic nolo null nyctalopia\n" + "Winners (7): nays nene ngultrum nirvanic nolo null nyctalopia\n" ] } ], @@ -732,7 +781,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "collapsed": false }, @@ -743,11 +792,11 @@ "text": [ "Outcomes (55) for player 1:\n", "Winners (55): aah aal aargh aas bwana cwm drake dreck drift droit\n", - "drunk dry ewe fjeld fjord gjetost hmm ihram jnana kwashiorkor llano\n", + "druse dry ewe fjeld fjord gjetost hmm ihram jnana kwashiorkor llama\n", "mho nth oquassa praam prequel prill pro prurigo pry qua quell quiff\n", - "quomodo qursh rhamnus rheum rhizoid rho rhumb rhyolitic sjambok\n", - "tchotchke uhlan vying wrack wreck wrist wrong wrung wry xanthic\n", - "xanthin ycleped zucchetto\n" + "quondam qursh rhamnus rheum rhizoid rho rhumb rhyolitic sjambok\n", + "tchotchke uhlan vroom wrang wrest wrick wrong wrung wry xanthic\n", + "xanthin yperite zucchetto\n" ] } ], @@ -766,7 +815,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "collapsed": false }, @@ -778,15 +827,15 @@ "Outcomes (85) for player 1:\n", "Losers (4): hybrid hyphen hyte ngultrum\n", "Winners (81): aquiculture aquifer aquilegia aquiver bwana cnidarian\n", - "drake dreck drift droit drunk drywall eschatologies eschatology\n", + "drake dreck drift droit druse drywall eschatologies eschatology\n", "escheat eserine eskar esophagus esplanade esquire esquiring essay\n", "estuarine estuary esurience fjeld fjord gjetost hyaenic hydatid hyena\n", "hyenine hyenoid hygeist hying hylozoism hylozoist hymen hyoid hypha\n", - "hyraces hyrax hyson ihram jnana kwashiorkor llano mbira ngwee oquassa\n", - "praam prequel prill proof prurigo pryer quaff quell quiff quomodo\n", + "hyraces hyrax hyson ihram jnana kwashiorkor llama mbira ngwee oquassa\n", + "plaza plethoric plica plonk pluck plyer quaff quell quiff quondam\n", "qursh rhamnus rheum rhizoid rhomb rhumb rhyolitic sjambok tchotchke\n", - "uhlan vying wrack wreck wrist wrong wrung wryly xanthic xanthin\n", - "ycleped zucchetto\n" + "uhlan vroom wrang wrest wrick wrong wrung wryly xanthic xanthin\n", + "yperite zucchetto\n" ] } ], @@ -812,7 +861,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": { "collapsed": false }, @@ -840,19 +889,19 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "enable1s = SuperVocabulary(enable1.words)\n", + "enable1s = SuperVocabulary(enable1.words, 3)\n", "enable1_4s = SuperVocabulary(enable1.words, 4)" ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "metadata": { "collapsed": false }, @@ -880,7 +929,7 @@ " 'tcrop'}" ] }, - "execution_count": 30, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -890,30 +939,6 @@ "enable1s.legal_plays('crop')" ] }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Can the first player win in SuperGhost with 3-letter words?\n", - "\n", - "win(enable1s)" - ] - }, { "cell_type": "code", "execution_count": 32, @@ -924,7 +949,7 @@ { "data": { "text/plain": [ - "True" + "'y'" ] }, "execution_count": 32, @@ -932,6 +957,30 @@ "output_type": "execute_result" } ], + "source": [ + "# Can the first player win in SuperGhost with 3-letter words?\n", + "\n", + "win(enable1s)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'y'" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# How about with a 4-letter limit?\n", "\n", @@ -947,7 +996,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "metadata": { "collapsed": false }, @@ -968,7 +1017,7 @@ "(1, 'cumquat')" ] }, - "execution_count": 33, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -991,7 +1040,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "metadata": { "collapsed": true }, @@ -1003,13 +1052,14 @@ " def legal_plays(self, fragment):\n", " \"All plays that form a valid infix; optionally reverse fragment first.\"\n", " def all4(frag, L): \n", - " return (frag + L, frag[::-1] + L, L + frag, L + frag[::-1])\n", + " return (frag + L, frag[::-1] + L, \n", + " L + frag, L + frag[::-1])\n", " return {p for L in alphabet for p in all4(fragment, L)} & self.fragments" ] }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "metadata": { "collapsed": true }, @@ -1021,7 +1071,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "metadata": { "collapsed": false }, @@ -1055,7 +1105,7 @@ " 'tcrop'}" ] }, - "execution_count": 36, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -1074,7 +1124,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "metadata": { "collapsed": false }, @@ -1084,33 +1134,14 @@ "\n", "@lru_cache(None)\n", "def win(vocab, fragment=''):\n", - " \"Does the player whose turn it is have a forced win?\"\n", - " return (fragment in vocab.words or \n", - " fragment not in vocab.fragments or\n", - " any(not win(vocab, play) \n", - " for play in vocab.legal_plays(fragment)))" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "win(enable1sd)" + " \"\"\"Does the current player have a forced win? \n", + " Return fragment if the player has already won, or return a play that forces a win.\"\"\"\n", + " if fragment in vocab.words or fragment not in vocab.fragments:\n", + " return fragment\n", + " for play in vocab.legal_plays(fragment):\n", + " if not win(vocab, play):\n", + " return play \n", + " return False" ] }, { @@ -1123,7 +1154,7 @@ { "data": { "text/plain": [ - "True" + "'y'" ] }, "execution_count": 39, @@ -1131,6 +1162,28 @@ "output_type": "execute_result" } ], + "source": [ + "win(enable1sd)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'y'" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "win(enable1_4sd)" ] @@ -1144,7 +1197,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "metadata": { "collapsed": false }, @@ -1153,23 +1206,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "Player 0, given \"\", plays \"d\".\n", - "Player 1, given \"d\", plays \"db\".\n", - "Player 0, given \"db\", plays \"udb\".\n", - "Player 1, given \"udb\", plays \"bdui\".\n", - "Player 0, given \"bdui\", plays \"bduin\".\n", - "Player 1, given \"bduin\", plays \"ubduin\".\n", - "Player 0, given \"ubduin\", plays \"subduin\".\n", - "Player 1, given \"subduin\", plays \"subduing\".\n" + "Player 0, given \"\", plays \"y\".\n", + "Player 1, given \"y\", plays \"zy\".\n", + "Player 0, given \"zy\", plays \"izy\".\n", + "Player 1, given \"izy\", plays \"mizy\".\n", + "Player 0, given \"mizy\", plays \"mizyg\".\n", + "Player 1, given \"mizyg\", plays \"emizyg\".\n", + "Player 0, given \"emizyg\", plays \"emizygo\".\n", + "Player 1, given \"emizygo\", plays \"emizygou\".\n", + "Player 0, given \"emizygou\", plays \"hemizygou\".\n", + "Player 1, given \"hemizygou\", plays \"hemizygous\".\n" ] }, { "data": { "text/plain": [ - "(0, 'subduing')" + "(0, 'hemizygous')" ] }, - "execution_count": 40, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1187,7 +1242,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "metadata": { "collapsed": false }, @@ -1198,7 +1253,7 @@ "[387878, 387844, 1076434, 1076431, 1076434, 1076431]" ] }, - "execution_count": 41, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1216,7 +1271,7 @@ "\n", "Here's a summary of what we have learned. (*Note:* the bold **qursh** means it is a losing word):\n", "\n", - "| Variant \t| Shortest \t| Winner \t| First Player Outcomes | 2nd Outcomes | Fragments\n", + "| Variant \t| Shortest \t| Winner \t| First Player Forced Outcomes | 2nd Outcomes | Fragments\n", "|----\t|---:\t |---\t |--- |--- |---:\n", "| Ghost | 3 \t | Second \t| qaid qiviut qoph **qursh** qurush qwerty | 55 words | 387,878\n", "| Ghost | 4 \t | First \t| naan nene ngultrum nirvanic nolo null nyctalopia | 85 words | 387,844\n", @@ -1237,15 +1292,6 @@ "- **Xghost:** In *Xghost*, a letter can be added anywhere, so from the fragment `'era'` you could play `'erba'`.\n", "- **Spook:** In *Spook*, letters can be rearranged before adding one, so from the fragment `'era'` you could play `'bear'`." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": {