4 "signature": "sha256:07f366ec645d178071697c25c43d438fd80cf3a676ad9bd8d7613f5bfa36adf5"
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",
78 " location = self.target.find(letter)\n",
79 " while location > -1:\n",
80 " locations += [location]\n",
81 " starting = location + 1\n",
82 " location = self.target.find(letter, starting)\n",
83 " return locations\n",
85 " def update_discovered_word(self, guessed_letter):\n",
86 " locations = self.find_all(guessed_letter)\n",
87 " for location in locations:\n",
88 " self.discovered[location] = guessed_letter\n",
89 " return self.discovered\n",
91 " def do_turn(self):\n",
93 " guess = self.player.guess(self.discovered, self.wrong_letters, self.lives)\n",
95 " guess = self.ask_for_guess()\n",
96 " if guess in self.target:\n",
97 " self.update_discovered_word(guess)\n",
100 " if guess not in self.wrong_letters:\n",
101 " self.wrong_letters += [guess]\n",
102 " if self.lives == 0:\n",
103 " self.game_finished = True\n",
104 " self.game_lost = True\n",
105 " if '_' not in self.discovered:\n",
106 " self.game_finished = True\n",
107 " self.game_won = True\n",
109 " def ask_for_guess(self):\n",
110 " print('Word:', ' '.join(self.discovered), \n",
111 " ' : Lives =', self.lives, \n",
112 " ', wrong guesses:', ' '.join(sorted(self.wrong_letters)))\n",
113 " guess = input('Enter letter: ').strip().lower()[0]\n",
116 " def play_game(self):\n",
117 " while not self.game_finished:\n",
119 " if not self.player:\n",
120 " self.report_on_game()\n",
121 " return self.game_won\n",
123 " def report_on_game(self):\n",
124 " if self.game_won:\n",
125 " print('You won! The word was', self.target)\n",
127 " print('You lost. The word was', self.target)\n",
128 " return self.game_won"
130 "language": "python",
139 "class PlayerFixedOrder:\n",
140 " def __init__(self, ordered_letters):\n",
141 " self.ordered_letters = ordered_letters\n",
143 " def guess(self, discovered, missed, lives):\n",
144 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
145 " self.ordered_subtract(guessed_letters)\n",
146 " return self.ordered_letters[0]\n",
148 " def ordered_subtract(self, to_remove):\n",
149 " for r in to_remove:\n",
150 " if r in self.ordered_letters:\n",
151 " ri = self.ordered_letters.index(r)\n",
152 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]"
154 "language": "python",
163 "class PlayerAlphabetical(PlayerFixedOrder):\n",
164 " def __init__(self):\n",
165 " super().__init__(string.ascii_lowercase)\n",
167 "class PlayerFreqOrdered(PlayerFixedOrder):\n",
168 " def __init__(self):\n",
169 " super().__init__(LETTERS_IN_ORDER)\n"
171 "language": "python",
181 "for _ in range(1000):\n",
182 " g = Game(random.choice(WORDS), player=PlayerAlphabetical())\n",
188 "language": "python",
192 "output_type": "stream",
206 "for _ in range(1000):\n",
207 " g = Game(random.choice(WORDS), player=PlayerFreqOrdered())\n",
213 "language": "python",
217 "output_type": "stream",
231 "for _ in range(1000):\n",
232 " g = Game(random.choice(WORDS), player=PlayerFixedOrder(list(reversed(string.ascii_lowercase))))\n",
238 "language": "python",
242 "output_type": "stream",
255 "DICT_COUNTS = collections.Counter(l.lower() for l in open('/usr/share/dict/british-english').read() if l in string.ascii_letters)\n",
256 "DICT_LETTERS_IN_ORDER = [p[0] for p in DICT_COUNTS.most_common()]"
258 "language": "python",
269 "language": "python",
274 "output_type": "pyout",
277 "Counter({'s': 91332, 'e': 88692, 'i': 66900, 'a': 64468, 'r': 57460, 'n': 57128, 't': 52949, 'o': 49121, 'l': 40995, 'c': 31854, 'd': 28505, 'u': 26372, 'g': 22693, 'm': 22549, 'p': 22249, 'h': 19337, 'b': 15540, 'y': 12652, 'f': 10679, 'k': 8386, 'v': 8000, 'w': 7505, 'x': 2125, 'z': 2058, 'j': 1950, 'q': 1536})"
287 "print(DICT_LETTERS_IN_ORDER)\n",
288 "print(LETTERS_IN_ORDER)"
290 "language": "python",
294 "output_type": "stream",
297 "['s', 'e', 'i', 'a', 'r', 'n', 't', 'o', 'l', 'c', 'd', 'u', 'g', 'm', 'p', 'h', 'b', 'y', 'f', 'k', 'v', 'w', 'x', 'z', 'j', 'q']\n",
298 "['e', 't', 'a', 'o', 'i', 'h', 'n', 's', 'r', 'd', 'l', 'u', 'm', 'w', 'c', 'y', 'f', 'g', 'p', 'b', 'v', 'k', 'x', 'j', 'q', 'z']\n"
309 "for _ in range(1000):\n",
310 " g = Game(random.choice(WORDS), player=PlayerFixedOrder(DICT_LETTERS_IN_ORDER))\n",
316 "language": "python",
320 "output_type": "stream",
333 "class PlayerAdaptiveLength:\n",
334 " def __init__(self, words):\n",
335 " self.all_words = words\n",
336 " self.candidate_words = None\n",
338 " def guess(self, discovered, missed, lives):\n",
339 " if not self.candidate_words:\n",
340 " self.set_ordered_letters(len(discovered))\n",
341 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
342 " self.ordered_subtract(guessed_letters)\n",
343 " return self.ordered_letters[0]\n",
345 " def ordered_subtract(self, to_remove):\n",
346 " for r in to_remove:\n",
347 " if r in self.ordered_letters:\n",
348 " ri = self.ordered_letters.index(r)\n",
349 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]\n",
351 " def set_ordered_letters(self, word_len):\n",
352 " self.candidate_words = [w for w in self.all_words if len(w) == word_len]\n",
353 " counts = collections.Counter(l.lower() for l in ''.join(self.candidate_words) if l in string.ascii_letters)\n",
354 " self.ordered_letters = [p[0] for p in counts.most_common()]"
356 "language": "python",
366 "for _ in range(1000):\n",
367 " g = Game(random.choice(WORDS), player=PlayerAdaptiveLength(WORDS))\n",
373 "language": "python",
377 "output_type": "stream",
390 "class PlayerAdaptiveIncludedLetters:\n",
391 " def __init__(self, words):\n",
392 " self.candidate_words = words\n",
394 " def guess(self, discovered, missed, lives):\n",
395 " self.filter_candidate_words(discovered)\n",
396 " self.set_ordered_letters()\n",
397 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
398 " self.ordered_subtract(guessed_letters)\n",
399 " return self.ordered_letters[0]\n",
401 " def ordered_subtract(self, to_remove):\n",
402 " for r in to_remove:\n",
403 " if r in self.ordered_letters:\n",
404 " ri = self.ordered_letters.index(r)\n",
405 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]\n",
407 " def filter_candidate_words(self, discovered):\n",
408 " exp = re.compile('^' + ''.join(discovered).replace('_', '.') + '$')\n",
409 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)]\n",
411 " def set_ordered_letters(self):\n",
412 " counts = collections.Counter(l.lower() for l in ''.join(self.candidate_words) if l in string.ascii_letters)\n",
413 " self.ordered_letters = [p[0] for p in counts.most_common()]"
415 "language": "python",
425 "for _ in range(1000):\n",
426 " g = Game(random.choice(WORDS), player=PlayerAdaptiveIncludedLetters(WORDS))\n",
432 "language": "python",
436 "output_type": "stream",
449 "re.match('^[^xaz]*$', 'happy')"
451 "language": "python",
460 "class PlayerAdaptiveExcludedLetters:\n",
461 " def __init__(self, words):\n",
462 " self.candidate_words = words\n",
464 " def guess(self, discovered, missed, lives):\n",
465 " self.filter_candidate_words(missed)\n",
466 " self.set_ordered_letters()\n",
467 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
468 " self.ordered_subtract(guessed_letters)\n",
469 " return self.ordered_letters[0]\n",
471 " def ordered_subtract(self, to_remove):\n",
472 " for r in to_remove:\n",
473 " if r in self.ordered_letters:\n",
474 " ri = self.ordered_letters.index(r)\n",
475 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]\n",
477 " def filter_candidate_words(self, missed):\n",
479 " exp = re.compile('^[^' + ''.join(missed) + ']*$')\n",
480 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)]\n",
482 " def set_ordered_letters(self):\n",
483 " counts = collections.Counter(l.lower() for l in ''.join(self.candidate_words) if l in string.ascii_letters)\n",
484 " self.ordered_letters = [p[0] for p in counts.most_common()]"
486 "language": "python",
496 "for _ in range(1000):\n",
497 " g = Game(random.choice(WORDS), player=PlayerAdaptiveExcludedLetters(WORDS))\n",
503 "language": "python",
507 "output_type": "stream",
520 "class PlayerAdaptivePattern:\n",
521 " def __init__(self, words):\n",
522 " self.candidate_words = words\n",
524 " def guess(self, discovered, missed, lives):\n",
525 " self.filter_candidate_words(discovered, missed)\n",
526 " self.set_ordered_letters()\n",
527 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
528 " self.ordered_subtract(guessed_letters)\n",
529 " return self.ordered_letters[0]\n",
531 " def ordered_subtract(self, to_remove):\n",
532 " for r in to_remove:\n",
533 " if r in self.ordered_letters:\n",
534 " ri = self.ordered_letters.index(r)\n",
535 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]\n",
537 " def filter_candidate_words(self, discovered, missed):\n",
538 " attempted_letters = list(set(l.lower() for l in discovered + missed if l in string.ascii_letters))\n",
539 " if attempted_letters:\n",
540 " exclusion_pattern = '[^' + ''.join(attempted_letters) + ']'\n",
542 " exclusion_pattern = '.'\n",
543 " exp = re.compile('^' + ''.join(discovered).replace('_', exclusion_pattern) + '$')\n",
544 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)]\n",
546 " def set_ordered_letters(self):\n",
547 " counts = collections.Counter(l.lower() for l in ''.join(self.candidate_words) if l in string.ascii_letters)\n",
548 " self.ordered_letters = [p[0] for p in counts.most_common()]\n"
550 "language": "python",
560 "for _ in range(1000):\n",
561 " g = Game(random.choice(WORDS), player=PlayerAdaptivePattern(WORDS))\n",
567 "language": "python",
571 "output_type": "stream",
587 "for _ in range(1000):\n",
588 " g = Game(random.choice(WORDS), player=PlayerAdaptivePattern(WORDS))\n",
594 "language": "python",
598 "output_type": "stream",
606 "output_type": "stream",
614 "output_type": "stream",
622 "output_type": "stream",
626 "1 loops, best of 3: 57.2 s per loop\n"
636 "class PlayerAdaptive:\n",
637 " def __init__(self, words):\n",
638 " self.candidate_words = words\n",
640 " def guess(self, discovered, missed, lives):\n",
641 " self.filter_candidate_words(discovered, missed)\n",
642 " self.set_ordered_letters()\n",
643 " guessed_letters = [l.lower() for l in discovered + missed if l in string.ascii_letters]\n",
644 " self.ordered_subtract(guessed_letters)\n",
645 " return self.ordered_letters[0]\n",
647 " def ordered_subtract(self, to_remove):\n",
648 " for r in to_remove:\n",
649 " if r in self.ordered_letters:\n",
650 " ri = self.ordered_letters.index(r)\n",
651 " self.ordered_letters = self.ordered_letters[:ri] + self.ordered_letters[ri+1:]\n",
653 " def filter_candidate_words(self, discovered, missed):\n",
656 " def set_ordered_letters(self):\n",
657 " counts = collections.Counter(l.lower() \n",
658 " for l in ''.join(self.candidate_words) + string.ascii_lowercase \n",
659 " if l in string.ascii_letters)\n",
660 " self.ordered_letters = [p[0] for p in counts.most_common()]"
662 "language": "python",
671 "class PlayerAdaptiveLength(PlayerAdaptive):\n",
672 " def __init__(self, words):\n",
673 " super().__init__(words)\n",
674 " self.word_len = None\n",
675 " self.ordered_letters = None\n",
677 " def filter_candidate_words(self, discovered, missed):\n",
678 " if not self.word_len:\n",
679 " self.word_len = len(discovered)\n",
680 " self.candidate_words = [w for w in self.candidate_words if len(w) == self.word_len]\n",
682 " def set_ordered_letters(self):\n",
683 " if not self.ordered_letters:\n",
684 " super().set_ordered_letters()"
686 "language": "python",
695 "class PlayerAdaptiveIncludedLetters(PlayerAdaptive):\n",
696 " def filter_candidate_words(self, discovered, missed):\n",
697 " exp = re.compile('^' + ''.join(discovered).replace('_', '.') + '$')\n",
698 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)]"
700 "language": "python",
709 "class PlayerAdaptiveExcludedLetters(PlayerAdaptive):\n",
710 " def filter_candidate_words(self, discovered, missed):\n",
712 " exp = re.compile('^[^' + ''.join(missed) + ']*$')\n",
713 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)] "
715 "language": "python",
724 "class PlayerAdaptivePattern(PlayerAdaptive):\n",
725 " def filter_candidate_words(self, discovered, missed):\n",
726 " attempted_letters = [l for l in discovered if l != '_'] + missed\n",
727 " if attempted_letters:\n",
728 " exclusion_pattern = '[^' + ''.join(attempted_letters) + ']'\n",
730 " exclusion_pattern = '.'\n",
731 " exp = re.compile('^' + ''.join(discovered).replace('_', exclusion_pattern) + '$')\n",
732 " self.candidate_words = [w for w in self.candidate_words if exp.match(w)]"
734 "language": "python",
746 "for _ in range(1000):\n",
747 " g = Game(random.choice(WORDS), player=PlayerAdaptiveLength(WORDS))\n",
753 "language": "python",
757 "output_type": "stream",
765 "output_type": "stream",
773 "output_type": "stream",
781 "output_type": "stream",
785 "1 loops, best of 3: 30.9 s per loop\n"
798 "for _ in range(1000):\n",
799 " g = Game(random.choice(WORDS), player=PlayerAdaptiveIncludedLetters(WORDS))\n",
805 "language": "python",
809 "output_type": "stream",
817 "output_type": "stream",
825 "output_type": "stream",
833 "output_type": "stream",
837 "1 loops, best of 3: 1min 8s per loop\n"
850 "for _ in range(1000):\n",
851 " g = Game(random.choice(WORDS), player=PlayerAdaptiveExcludedLetters(WORDS))\n",
857 "language": "python",
861 "output_type": "stream",
869 "output_type": "stream",
877 "output_type": "stream",
885 "output_type": "stream",
889 "1 loops, best of 3: 13min 6s per loop\n"
902 "for _ in range(1000):\n",
903 " g = Game(random.choice(WORDS), player=PlayerAdaptivePattern(WORDS))\n",
909 "language": "python",
913 "output_type": "stream",
921 "output_type": "stream",
929 "output_type": "stream",
937 "output_type": "stream",
941 "1 loops, best of 3: 56.6 s per loop\n"
951 "for _ in range(1000):\n",
952 " g = Game(random.choice(WORDS), player=PlayerAdaptivePattern(WORDS))\n",
954 " if not g.game_won:\n",
955 " print(g.target, g.discovered, g.wrong_letters)"
957 "language": "python",
961 "output_type": "stream",
964 "jutting ['_', 'u', 't', 't', 'i', 'n', 'g'] ['e', 'a', 'o', 'l', 's', 'f', 'p', 'b', 'c', 'r']\n",
969 "output_type": "stream",
972 " ['_', 'a', '_', 'e'] ['r', 'l', 'm', 'p', 's', 'g', 'b', 'd', 'v', 'k']\n",
977 "output_type": "stream",
980 " ['_', 'a', '_', 'e'] ['r', 'l', 'm', 'p', 's', 'g', 'b', 'd', 'v', 'k']\n",
985 "output_type": "stream",
988 " ['_', 'u', 'n', 'k'] ['e', 's', 'o', 'a', 'i', 'l', 'f', 'r', 'j', 'p']\n",
993 "output_type": "stream",
996 " ['_', 'o', 'o', 'n', 's'] ['e', 't', 'k', 'm', 'p', 'd', 'f', 'c', 'b', 'g']\n",
1001 "output_type": "stream",
1004 " ['_', 'a', 'b'] ['t', 'p', 'g', 'w', 'm', 'd', 'y', 'r', 'c', 'n']\n",
1009 "output_type": "stream",
1012 " ['_', 'o', 'k', 'e', 'd'] ['s', 'a', 'w', 'p', 't', 'r', 'h', 'b', 'y', 'c']\n"
1019 "cell_type": "code",
1022 "iterations = 10000\n",
1024 "for _ in range(iterations):\n",
1025 " g = Game(random.choice(WORDS), player=PlayerAdaptivePattern(WORDS))\n",
1027 " if g.game_won:\n",
1029 "print(wins / iterations)"
1031 "language": "python",
1035 "output_type": "stream",
1045 "cell_type": "code",
1048 "language": "python",