4 "signature": "sha256:5a2b414ce60f525ddfcbb85f2b57ef6ecf5d08662151337bdc833cd40f541f71"
29 "WORDS = [w.strip() for w in open('/usr/share/dict/british-english').readlines() \n",
30 " if re.match(r'^[a-z]*$', w.strip())]"
41 "LETTER_COUNTS = collections.Counter(l.lower() for l in open('../sherlock-holmes.txt').read() if l in string.ascii_letters)\n",
42 "LETTERS_IN_ORDER = [p[0] for p in LETTER_COUNTS.most_common()]"
65 " def __init__(self, target, player=None, lives=STARTING_LIVES):\n",
66 " self.lives = lives\n",
67 " self.player = player\n",
68 " self.target = target\n",
69 " self.discovered = list('_' * len(target))\n",
70 " self.wrong_letters = []\n",
71 " self.game_finished = False\n",
72 " self.game_won = False\n",
73 " self.game_lost = False\n",
75 " def find_all(self, letter):\n",
76 " return [p for p, l in enumerate(self.target) if l == letter]\n",
78 " def update_discovered_word(self, guessed_letter):\n",
79 " locations = self.find_all(guessed_letter)\n",
80 " for location in locations:\n",
81 " self.discovered[location] = guessed_letter\n",
82 " return self.discovered\n",
84 " def do_turn(self):\n",
86 " guess = self.player.guess(self.discovered, self.wrong_letters, self.lives)\n",
88 " guess = self.ask_for_guess()\n",
89 " if guess in self.target:\n",
90 " self.update_discovered_word(guess)\n",
93 " if guess not in self.wrong_letters:\n",
94 " self.wrong_letters += [guess]\n",
95 " if self.lives == 0:\n",
96 " self.game_finished = True\n",
97 " self.game_lost = True\n",
98 " if '_' not in self.discovered:\n",
99 " self.game_finished = True\n",
100 " self.game_won = True\n",
102 " def ask_for_guess(self):\n",
103 " print('Word:', ' '.join(self.discovered), \n",
104 " ' : Lives =', self.lives, \n",
105 " ', wrong guesses:', ' '.join(sorted(self.wrong_letters)))\n",
106 " guess = input('Enter letter: ').strip().lower()[0]\n",
109 " def play_game(self):\n",
110 " while not self.game_finished:\n",
112 " if not self.player:\n",
113 " self.report_on_game()\n",
114 " return self.game_won\n",
116 " def report_on_game(self):\n",
117 " if self.game_won:\n",
118 " print('You won! The word was', self.target)\n",
120 " print('You lost. The word was', self.target)\n",
121 " return self.game_won"
123 "language": "python",
132 "DICT_COUNTS = collections.Counter(l.lower() for l in open('/usr/share/dict/british-english').read() if l in string.ascii_letters)\n",
133 "DICT_LETTERS_IN_ORDER = [p[0] for p in DICT_COUNTS.most_common()]"
135 "language": "python",
144 "class PlayerAdaptiveNoRegex:\n",
145 " def __init__(self, words):\n",
146 " self.candidate_words = words\n",
148 " def guess(self, discovered, missed, lives):\n",
149 " self.filter_candidate_words(discovered, missed)\n",
150 " self.set_ordered_letters()\n",
151 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
152 " return [l for l in self.ordered_letters if l not in guessed_letters][0]\n",
154 " def filter_candidate_words(self, discovered, missed):\n",
157 " def set_ordered_letters(self):\n",
158 " counts = collections.Counter(l.lower() \n",
159 " for l in ''.join(self.candidate_words) + string.ascii_lowercase \n",
160 " if l in string.ascii_letters)\n",
161 " self.ordered_letters = [p[0] for p in counts.most_common()]\n",
163 " def match(self, pattern, target, excluded=None):\n",
164 " if not excluded:\n",
166 " if len(pattern) != len(target):\n",
168 " for m, c in zip(pattern, target):\n",
169 " if m == '_' and c not in excluded:\n",
172 " elif m != '_' and m == c:\n",
179 "language": "python",
188 "class PlayerAdaptiveLengthNoRegex(PlayerAdaptiveNoRegex):\n",
189 " def __init__(self, words):\n",
190 " super().__init__(words)\n",
191 " self.word_len = None\n",
192 " self.ordered_letters = None\n",
194 " def filter_candidate_words(self, discovered, missed):\n",
195 " if not self.word_len:\n",
196 " self.word_len = len(discovered)\n",
197 " self.candidate_words = [w for w in self.candidate_words if len(w) == self.word_len]\n",
199 " def set_ordered_letters(self):\n",
200 " if not self.ordered_letters:\n",
201 " super().set_ordered_letters()"
203 "language": "python",
212 "class PlayerAdaptiveIncludedLettersNoRegex(PlayerAdaptiveNoRegex):\n",
213 " def filter_candidate_words(self, discovered, missed):\n",
214 " self.candidate_words = [w for w in self.candidate_words if self.match(discovered, w)]"
216 "language": "python",
225 "class PlayerAdaptiveExcludedLettersNoRegex(PlayerAdaptiveNoRegex):\n",
226 " def filter_candidate_words(self, discovered, missed):\n",
228 " empty_target = '_' * len(discovered)\n",
229 " self.candidate_words = [w for w in self.candidate_words if self.match(empty_target, w, missed)] "
231 "language": "python",
240 "class PlayerAdaptivePatternNoRegex(PlayerAdaptiveNoRegex):\n",
241 " def filter_candidate_words(self, discovered, missed):\n",
242 " attempted_letters = [l for l in discovered if l != '_'] + missed\n",
243 " self.candidate_words = [w for w in self.candidate_words if self.match(discovered, w, attempted_letters)]"
245 "language": "python",
257 "for _ in range(1000):\n",
258 " g = Game(random.choice(WORDS), player=PlayerAdaptivePatternNoRegex(WORDS))\n",
264 "language": "python",
268 "output_type": "stream",
276 "output_type": "stream",
284 "output_type": "stream",
292 "output_type": "stream",
296 "1 loops, best of 3: 48.2 s per loop\n"
306 "len([w for w in WORDS if 'r' in w])"
308 "language": "python",
313 "output_type": "pyout",
326 "len([w for w in WORDS if 'r' not in w])"
328 "language": "python",
333 "output_type": "pyout",
346 "letter_diffs = []\n",
347 "for l in string.ascii_lowercase:\n",
349 " for w in WORDS:\n",
354 " letter_diffs += [(l, abs(n))]\n",
355 "sorted(letter_diffs, key=lambda p: p[1])"
357 "language": "python",
362 "output_type": "pyout",
400 "def letter_diff(l):\n",
401 " return abs(sum(1 if l in w else -1 for w in WORDS))\n",
403 "letter_diffs = [(l, letter_diff(l)) \n",
404 " for l in string.ascii_lowercase]\n",
405 "sorted(letter_diffs, key=lambda p: p[1])"
407 "language": "python",
412 "output_type": "pyout",
450 "class PlayerAdaptiveSplit(PlayerAdaptivePatternNoRegex):\n",
451 " def set_ordered_letters(self):\n",
452 " def letter_diff(l):\n",
453 " return abs(sum(1 if l in w else -1 for w in self.candidate_words))\n",
454 " possible_letters = set(''.join(self.candidate_words))\n",
455 " # if len(self.candidate_words) > 1:\n",
456 " letter_diffs = [(l, letter_diff(l)) for l in possible_letters]\n",
457 " self.ordered_letters = [p[0] for p in sorted(letter_diffs, key=lambda p: p[1])]\n",
459 " # self.ordered_letters = list(self.candidate_words[0])"
461 "language": "python",
470 "g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
473 "language": "python",
478 "output_type": "pyout",
493 "language": "python",
498 "output_type": "pyout",
513 "language": "python",
518 "output_type": "pyout",
521 "['b', 'a', 's', 't', 'e']"
533 "language": "python",
538 "output_type": "pyout",
554 "for _ in range(1000):\n",
555 " g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
561 "language": "python",
565 "output_type": "stream",
573 "output_type": "stream",
581 "output_type": "stream",
589 "output_type": "stream",
593 "1 loops, best of 3: 55.6 s per loop\n"
603 "p=PlayerAdaptiveSplit(WORDS)"
605 "language": "python",
614 "dsc = ['_'] * len('recognition')\n",
617 "language": "python",
622 "output_type": "pyout",
625 "['_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_']"
635 "p.guess(dsc, [], 10)"
637 "language": "python",
642 "output_type": "pyout",
655 "len(p.candidate_words)"
657 "language": "python",
662 "output_type": "pyout",
675 "p.guess(['_', '_', '_', 'o', '_', '_', '_', '_', '_', 'o', '_'], [], 10)"
677 "language": "python",
682 "output_type": "pyout",
697 "language": "python",
702 "output_type": "pyout",
730 "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], [], 10)"
732 "language": "python",
737 "output_type": "pyout",
752 "language": "python",
757 "output_type": "pyout",
760 "['excoriation', 'recognition', 'recondition']"
770 "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], ['a'], 9)"
772 "language": "python",
777 "output_type": "pyout",
792 "language": "python",
797 "output_type": "pyout",
800 "['recognition', 'recondition']"
810 "p.guess(['_', '_', 'c', 'o', '_', '_', '_', '_', '_', 'o', '_'], ['a', 'd'], 8)"
812 "language": "python",
817 "output_type": "pyout",
832 "language": "python",
837 "output_type": "pyout",
850 "g = Game('recognition', player=PlayerAdaptiveSplit(WORDS))\n",
853 "language": "python",
858 "output_type": "pyout",
873 "language": "python",
878 "output_type": "pyout",
881 "['r', 'e', 'c', 'o', 'g', 'n', 'i', 't', 'i', 'o', 'n']"
893 "language": "python",
898 "output_type": "pyout",
914 "for _ in range(10000):\n",
915 " g = Game(random.choice(WORDS), player=PlayerAdaptiveSplit(WORDS))\n",
921 "language": "python",
925 "output_type": "stream",
933 "output_type": "stream",
941 "output_type": "stream",
949 "output_type": "stream",
953 "1 loops, best of 3: 9min 15s per loop\n"
966 "for _ in range(10000):\n",
967 " g = Game(random.choice(WORDS), player=PlayerAdaptivePatternNoRegex(WORDS))\n",
973 "language": "python",
977 "output_type": "stream",
985 "output_type": "stream",
993 "output_type": "stream",
1001 "output_type": "stream",
1005 "1 loops, best of 3: 8min 12s per loop\n"
1012 "cell_type": "code",
1015 "for w in random.sample(WORDS, 5000):\n",
1016 " gp = Game(w, player=PlayerAdaptivePatternNoRegex(WORDS))\n",
1017 " gp.play_game()\n",
1018 " gs = Game(w, player=PlayerAdaptiveSplit(WORDS))\n",
1019 " gs.play_game()\n",
1020 " if not gp.game_won and not gs.game_won:\n",
1021 " print('Both:::::', gp.target, 'Pattern:', '[' + ' '.join(gp.discovered) + ']', ''.join(gp.wrong_letters), \n",
1022 " ':: Split:', '[' + ' '.join(gs.discovered) + ']', ''.join(gs.wrong_letters))\n",
1023 " if not gp.game_won and gs.game_won:\n",
1024 " print('Pattern::', gp.target, '[' + ' '.join(gp.discovered) + ']', ''.join(gp.wrong_letters))\n",
1025 " if gp.game_won and not gs.game_won:\n",
1026 " print('Split::::', gs.target, '[' + ' '.join(gs.discovered) + ']', ''.join(gs.wrong_letters))"
1028 "language": "python",
1032 "output_type": "stream",
1035 "Split:::: cut [_ _ t] aoeiybgnpj\n",
1040 "output_type": "stream",
1043 " reviewers [_ _ _ _ _ _ _ _ _] taoldgnupc\n",
1048 "output_type": "stream",
1051 " piped [_ i _ e d] saolrnkvbm\n",
1056 "output_type": "stream",
1059 " joying Pattern: [_ o _ i n g] esapwdtrkm :: Split: [_ o _ _ n _] srdatpwhvk\n",
1064 "output_type": "stream",
1067 " duck Pattern: [_ u _ _] esoailfrnm :: Split: [_ u _ _] esaorlnfmt\n",
1072 "output_type": "stream",
1075 " bum [b _ _] aoeiyrtgns\n",
1080 "output_type": "stream",
1083 " jibing [_ i _ i n g] esrldmpkvt\n",
1088 "output_type": "stream",
1091 " begged [_ _ _ _ _ d] srlnoauipt\n",
1096 "output_type": "stream",
1099 " bucked [b u _ _ e d] aoilstfgpr\n",
1104 "output_type": "stream",
1107 " bunk [_ u n k] esoailfrgp\n",
1112 "output_type": "stream",
1115 " dumping [_ u _ p _ _ g] srlaoecjhb\n",
1120 "output_type": "stream",
1123 " meekest [_ _ _ _ _ s _] iaournlpdw\n",
1128 "output_type": "stream",
1131 " wove [_ o v e] arnldptkmc\n",
1136 "output_type": "stream",
1139 " finking [_ _ _ _ _ _ g] srlaoeutpd\n",
1144 "output_type": "stream",
1147 " fan Pattern: [_ a _] tpgwdmrbys :: Split: [_ a n] tpgwmbyrdv\n",
1152 "output_type": "stream",
1155 " hug [_ u g] aoeibpdmtj\n",
1160 "output_type": "stream",
1163 " feminism [_ _ _ _ _ _ _ _] ratlogdcuh\n",
1168 "output_type": "stream",
1171 " effect [_ _ _ _ c t] srdnaioulp\n",
1176 "output_type": "stream",
1179 " puff [_ u f f] esaorlnmgc\n",
1184 "output_type": "stream",
1187 " skivvies [_ _ _ _ _ _ _ _] ratlogdcuh\n",
1192 "output_type": "stream",
1195 " miffing [_ _ _ _ _ _ g] srlaoeutpd\n",
1200 "output_type": "stream",
1203 " dung Pattern: [_ u n _] esoailfrkt :: Split: [_ u n g] esaorlkthb\n",
1208 "output_type": "stream",
1211 " gibed [_ i _ e d] saomlprkvn\n",
1216 "output_type": "stream",
1219 " rubs [_ u b s] eaoicpdtnh\n",
1224 "output_type": "stream",
1227 " bat [_ a t] ecpsofmvhr\n",
1232 "output_type": "stream",
1235 " boobs [_ o o _ s] eatdklmpfn\n",
1240 "output_type": "stream",
1243 " yon Pattern: [_ o n] atbdwpiecs :: Split: [_ o n] atbdwpiesc\n",
1248 "output_type": "stream",
1251 " firs Pattern: [f i _ s] eaoptgbdmn :: Split: [_ i _ s] eaotpgbdmn\n",
1256 "output_type": "stream",
1259 " quipping [_ _ _ _ _ _ _ g] ratloscedh\n",
1264 "output_type": "stream",
1267 " ragging [r a _ _ _ n _] seotzclpdm\n",
1272 "output_type": "stream",
1275 " fuddled [_ u _ _ l _ _] sraoibzmgc\n",
1280 "output_type": "stream",
1283 " yack Pattern: [_ a c k] esolrntmpj :: Split: [_ a c k] esrlntmjhb\n",
1288 "output_type": "stream",
1291 " vanning [_ a _ _ _ _ g] srltpbwmck\n",
1296 "output_type": "stream",
1299 " fizziest [_ _ _ _ _ _ _ t] rauonlphdk\n",
1304 "output_type": "stream",
1307 " rug [_ u g] aoeibpdmtj\n",
1312 "output_type": "stream",
1315 " fixed Pattern: [_ i _ e d] saomlprkvn :: Split: [_ i _ e d] saolrnkvbm\n",
1320 "output_type": "stream",
1323 " mop [_ o p] atbdwchlsf\n",
1328 "output_type": "stream",
1331 " separatists [_ _ p _ _ _ _ _ _ _ _] oldcgnymbx\n",
1336 "output_type": "stream",
1339 " miff [_ _ _ _] esaoutnlrc\n",
1344 "output_type": "stream",
1347 " putty [p u _ _ y] seaoimlnrf\n",
1352 "output_type": "stream",
1355 " mice [_ i _ e] aorlnvtdkw\n",
1360 "output_type": "stream",
1363 " fixing Pattern: [_ i _ i n g] esrldmpkvt :: Split: [_ _ _ _ n _] srdaoeulbp\n",
1368 "output_type": "stream",
1371 " gaged [_ a _ e d] srwctpmzbh\n",
1376 "output_type": "stream",
1379 " fag [_ a g] tpjnhrlbsw\n",
1384 "output_type": "stream",
1387 " woeful [_ o _ _ _ _] srdnaictyb\n",
1392 "output_type": "stream",
1395 " pauper [_ a _ _ _ r] sntlmidkvj\n",
1400 "output_type": "stream",
1403 " faxing Pattern: [f a _ i n g] esrwtlcdkz :: Split: [_ a _ _ n _] srdtwmpczh\n",
1408 "output_type": "stream",
1411 " yoking Pattern: [_ o k i n g] esapwdtrcj :: Split: [_ o k _ n _] srdatpwhvj\n",
1416 "output_type": "stream",
1419 " cox Pattern: [_ o _] atbdwpnsge :: Split: [_ o _] atbdwpngse\n",
1424 "output_type": "stream",
1427 " doff [_ o _ _] esalrnctyb\n",
1432 "output_type": "stream",
1435 " puck Pattern: [_ u _ _] esoailfrnm :: Split: [_ u _ _] esaorlnfmt\n",
1440 "output_type": "stream",
1443 " tuck [_ u _ _] esoailfrnm\n",
1448 "output_type": "stream",
1451 " kerchiefs [_ _ _ c _ _ _ _ _] taoldgnupv\n",
1456 "output_type": "stream",
1459 " members [_ _ _ _ _ r s] aoiutdpcgv\n",
1464 "output_type": "stream",
1467 " foxing Pattern: [_ o _ i n g] esapwdtrkm :: Split: [_ o _ _ n _] srdatpwhvk\n",
1472 "output_type": "stream",
1475 " anaesthetises [_ _ _ _ _ _ _ _ _ _ _ _ _] clgmpdvuro\n",
1480 "output_type": "stream",
1483 " versifies [_ _ _ _ _ _ _ _ _] taoldgnupc\n",
1488 "output_type": "stream",
1491 " babes Pattern: [_ a _ e s] rltngcdkzv :: Split: [_ a _ e s] rltngcdkzv\n",
1496 "output_type": "stream",
1499 " huffing [_ u f f _ _ g] srlaoecpbm\n",
1504 "output_type": "stream",
1507 " weeper [_ _ _ p _ r] saioutdhbk\n",
1512 "output_type": "stream",
1515 " buffering [_ u _ _ _ _ _ _ g] taoldsphmv\n",
1520 "output_type": "stream",
1523 " dills [_ _ l l s] eaountghrb\n",
1528 "output_type": "stream",
1531 " wigging [_ _ g g _ _ g] srlaouejpd\n",
1536 "output_type": "stream",
1539 " indenting [_ _ d _ _ t _ _ _] aoscrlbvhf\n",
1544 "output_type": "stream",
1547 " morn [_ o r n] esaltchbpw\n",
1552 "output_type": "stream",
1555 " buff Pattern: [_ u f f] esoailgcpd :: Split: [_ u f f] esaorlnmgc\n",
1560 "output_type": "stream",
1563 " zero [_ e r _] satlbnhpyg\n",
1568 "output_type": "stream",
1571 " jazz Pattern: [_ a _ _] esolrntmky :: Split: [_ a _ _] esrlntmkdw\n",
1576 "output_type": "stream",
1579 " k [_] geopdtuyiz\n",
1584 "output_type": "stream",
1587 " find [_ _ n d] esaoutkhrb\n",
1592 "output_type": "stream",
1595 " happy [_ a _ _ y] sentdrglcz\n",
1600 "output_type": "stream",
1603 " fibbing [_ _ _ _ _ _ g] srlaoeutpd\n",
1608 "output_type": "stream",
1611 " wifeliest [_ _ _ _ _ _ _ _ t] nroacmhpgu\n",
1616 "output_type": "stream",
1619 " r Pattern: [_] giecposdwk :: Split: [_] geopdtuyiz\n",
1624 "output_type": "stream",
1627 " businesses [_ _ _ _ n _ _ _ _ _] olatdgcphr\n",
1632 "output_type": "stream",
1635 " fife Pattern: [_ i _ e] aorlndvtpm :: Split: [_ i _ e] aorlnvtdkw\n",
1640 "output_type": "stream",
1643 " fix Pattern: [_ i _] aoeptdngsb :: Split: [_ i _] aoetndpgbs\n",
1648 "output_type": "stream",
1651 " mil Pattern: [_ i _] aoeptdngsb :: Split: [_ i _] aoetndpgbs\n",
1656 "output_type": "stream",
1659 " wetted [_ _ t t _ d] srlnoauipj\n"
1666 "cell_type": "code",
1669 "gs = Game('businesses', player=PlayerAdaptiveSplit(WORDS))"
1671 "language": "python",
1677 "cell_type": "code",
1680 "g = Game('feminism', player=PlayerAdaptiveSplit(WORDS))\n",
1681 "while not g.game_finished:\n",
1682 " guess = g.player.guess(g.discovered, g.wrong_letters, g.lives)\n",
1683 " print(g.target, '(' + str(g.lives) + ')', \n",
1684 " '[' + ' '.join(g.discovered) + ']', ''.join(g.wrong_letters), \n",
1685 " ';', len(g.player.candidate_words), 'candidate words')\n",
1686 " print('Guess = ', guess)\n",
1689 "language": "python",
1693 "output_type": "stream",
1696 "feminism (10) [_ _ _ _ _ _ _ _] ; 10328 candidate words\n",
1702 "output_type": "stream",
1705 " (9) [_ _ _ _ _ _ _ _] r ; 5102 candidate words\n",
1707 "feminism (8) [_ _ _ _ _ _ _ _] ra ; 2673 candidate words\n",
1713 "output_type": "stream",
1716 " (7) [_ _ _ _ _ _ _ _] rat ; 1466 candidate words\n",
1718 "feminism (6) [_ _ _ _ _ _ _ _] ratl ; 704 candidate words\n",
1720 "feminism (5) [_ _ _ _ _ _ _ _] ratlo ; 359 candidate words\n",
1722 "feminism (4) [_ _ _ _ _ _ _ _] ratlog ; 189 candidate words\n",
1724 "feminism (3) [_ _ _ _ _ _ _ _] ratlogd ; 94 candidate words\n",
1726 "feminism (2) [_ _ _ _ _ _ _ _] ratlogdc ; 50 candidate words\n",
1728 "feminism (1) [_ _ _ _ _ _ _ _] ratlogdcu ; 31 candidate words\n",
1733 "prompt_number": 170
1736 "cell_type": "code",
1739 "g = Game('feminism', player=PlayerAdaptivePatternNoRegex(WORDS))\n",
1740 "while not g.game_finished:\n",
1741 " guess = g.player.guess(g.discovered, g.wrong_letters, g.lives)\n",
1742 " print(g.target, '(' + str(g.lives) + ')', \n",
1743 " '[' + ' '.join(g.discovered) + ']', ''.join(g.wrong_letters), \n",
1744 " ';', len(g.player.candidate_words), 'candidate words')\n",
1745 " print('Guess = ', guess)\n",
1748 "language": "python",
1752 "output_type": "stream",
1755 "feminism (10) [_ _ _ _ _ _ _ _] ; 10328 candidate words\n",
1761 "output_type": "stream",
1764 " (10) [_ e _ _ _ _ _ _] ; 540 candidate words\n",
1766 "feminism (10) [_ e _ i _ i _ _] ; 42 candidate words\n",
1768 "feminism (10) [_ e _ i n i _ _] ; 3 candidate words\n",
1770 "feminism (10) [_ e _ i n i s _] ; 3 candidate words\n",
1772 "feminism (10) [f e _ i n i s _] ; 2 candidate words\n",
1777 "prompt_number": 172
1780 "cell_type": "code",
1783 "g.player.candidate_words"
1785 "language": "python",
1790 "output_type": "pyout",
1791 "prompt_number": 171,
1827 "prompt_number": 171
1830 "cell_type": "code",
1833 "language": "python",