Skip to content

Commit 59b2682

Browse files
committed
added boggle
1 parent 37b49c1 commit 59b2682

File tree

9 files changed

+337
-35
lines changed

9 files changed

+337
-35
lines changed

OUTLINE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@
4242
41. **set**: Find "set" of cards from a deck of 81 where each of 4 attributes can have each of 3 values and a "set" of 3 cards is either the same or entirely different for each of the 4 attributes.
4343
42. **scrabble**: Find all possible words you could make from a random set of seven characters.
4444
43. **rummikub**: Program the tile-based Rummikub game where you find sets of the same number of different colors or consecutive runs of numbers in the same color.
45+
44. **boggle**: Write a Boggle game.

bin/chapters.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ word_search
4747
set
4848
scrabble
4949
rummikub
50+
boggle

boggle/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.PHONY: test
2+
3+
test:
4+
pytest -xv test.py

boggle/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Boggle
2+
3+
Write a Boggle game.

boggle/precis.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Write a Boggle game.

boggle/boggle.py renamed to boggle/solution.py

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
from itertools import combinations
99
from collections import defaultdict, Counter
10+
from pprint import pprint
1011

1112

1213
# --------------------------------------------------
@@ -17,17 +18,6 @@ def get_args():
1718
description='Boggle',
1819
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
1920

20-
# parser.add_argument('positional',
21-
# metavar='str',
22-
# help='A positional argument')
23-
24-
# parser.add_argument('-a',
25-
# '--arg',
26-
# help='A named string argument',
27-
# metavar='str',
28-
# type=str,
29-
# default='')
30-
3121
parser.add_argument('-s',
3222
'--seed',
3323
help='Random seed',
@@ -42,11 +32,6 @@ def get_args():
4232
type=argparse.FileType('r'),
4333
default='/usr/share/dict/words')
4434

45-
# parser.add_argument('-o',
46-
# '--on',
47-
# help='A boolean flag',
48-
# action='store_true')
49-
5035
return parser.parse_args()
5136

5237

@@ -56,32 +41,46 @@ def main():
5641

5742
args = get_args()
5843
words = get_words(args.wordlist)
59-
6044
random.seed(args.seed)
6145

6246
dice = [
63-
'U Qu H M N I', 'O B J A O B', 'F F S K A P', 'N S I E U E',
64-
'E G H W E N', 'S O A C H P', 'T T R E Y L', 'R N Z N H L',
65-
'R E V L Y D', 'T U I C M O', 'T D T Y S I', 'O O W T T A',
66-
'N A E A E G', 'R V T H E W', 'L X E D R I', 'O T S E S I'
47+
'O B J A O B',
48+
'F F S K A P',
49+
'N S I E U E',
50+
'E G H W E N',
51+
'S O A C H P',
52+
'T T R E Y L',
53+
'R N Z N H L',
54+
'R E V L Y D',
55+
'T U I C M O',
56+
'T D T Y S I',
57+
'O O W T T A',
58+
'N A E A E G',
59+
'R V T H E W',
60+
'L X E D R I',
61+
'O T S E S I',
62+
'U QU H M N I',
6763
]
6864

6965
show = list(map(lambda s: random.choice(s.split()), dice))
70-
7166
for i, die in enumerate(show, start=1):
72-
print('{:2} '.format(die), end='')
73-
if i % 4 == 0:
74-
print()
67+
print('{:2} '.format(die), end='\n' if i % 4 == 0 else '')
7568

76-
i = 0
77-
found = set()
69+
combos_by_len = defaultdict(set)
7870
for n in range(1, 17):
79-
print(n)
80-
for combo in combinations(show, n):
81-
wanted = Counter(combo)
82-
for word, counter in words[len(combo)]:
83-
if counter == wanted and word not in found:
84-
found.add(word)
71+
for combo in map(lambda c: ''.join(sorted(''.join(c))),
72+
combinations(show, n)):
73+
74+
combos_by_len[len(combo)].add(combo)
75+
76+
found = []
77+
for n, combos in combos_by_len.items():
78+
lookup = defaultdict(set)
79+
for word in words[n]:
80+
lookup[''.join(sorted(word))].add(word)
81+
82+
for combo in combos:
83+
found.extend(lookup[combo])
8584

8685
if found:
8786
for i, word in enumerate(sorted(found), start=1):
@@ -96,7 +95,7 @@ def get_words(fh):
9695

9796
words = defaultdict(list)
9897
for word in fh.read().upper().split():
99-
words[len(word)].append((word, Counter(word)))
98+
words[len(word)].append(word)
10099

101100
return words
102101

@@ -107,7 +106,7 @@ def test_get_words():
107106

108107
words = get_words(io.StringIO('apple banana cherry fig'))
109108
assert len(words[3]) == 1
110-
assert words[3][0] == ('fig', Counter('fig'))
109+
assert 'fig' in words[3]
111110
assert len(words[5]) == 1
112111
assert len(words[6]) == 2
113112

boggle/test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python3
2+
"""tests for boggle.py"""
3+
4+
import os
5+
import re
6+
import random
7+
from subprocess import getstatusoutput
8+
9+
prg = './boggle.py'
10+
11+
# --------------------------------------------------
12+
def test_exists():
13+
"""exists"""
14+
15+
assert os.path.isfile(prg)
16+
17+
18+
# --------------------------------------------------
19+
def test_usage():
20+
"""usage"""
21+
22+
for flag in ['-h', '--help']:
23+
rv, out = getstatusoutput('{} {}'.format(prg, flag))
24+
assert rv == 0
25+
assert re.match("usage", out, re.IGNORECASE)

0 commit comments

Comments
 (0)