Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0568c48

Browse filesBrowse files
committed
added set
1 parent b2db318 commit 0568c48
Copy full SHA for 0568c48

File tree

Expand file treeCollapse file tree

9 files changed

+295
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

9 files changed

+295
-0
lines changed
Open diff view settings
Collapse file

‎OUTLINE.md‎

Copy file name to clipboardExpand all lines: OUTLINE.md
+1Lines changed: 1 addition & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@
3838
37. **morse**: Encrypt and decrypt text to and from two versions of Morse code.
3939
38. **rot13**: Encode and decode text by rotating the characters through a list.
4040
39. **word_search**: Find all the words hidden in the rows, columns, and diagonals in a block of text.
41+
40. **set**: Program the Set card game.
Collapse file

‎bin/chapters.txt‎

Copy file name to clipboardExpand all lines: bin/chapters.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ morse
4343
rot13
4444
#transpose
4545
word_search
46+
set
Collapse file

‎book.md‎

Copy file name to clipboardExpand all lines: book.md
+122Lines changed: 122 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ Ken Youens-Clark is a Sr. Scientific Programmer in the lab of Dr. Bonnie Hurwitz
155155
37. **morse**: Encrypt and decrypt text to and from two versions of Morse code.
156156
38. **rot13**: Encode and decode text by rotating the characters through a list.
157157
39. **word_search**: Find all the words hidden in the rows, columns, and diagonals in a block of text.
158+
40. **set**: Program the Set card game.
158159

159160
\newpage
160161

@@ -10872,6 +10873,127 @@ At line 157, I start the work of printing the revealed puzzle, iterating over th
1087210873

1087310874
\newpage
1087410875

10876+
# Chapter 40: Ready, Set, Go!
10877+
10878+
Write a Python program called `set.py` that plays the Set card game.
10879+
10880+
\newpage
10881+
10882+
## Solution
10883+
10884+
````
10885+
1 #!/usr/bin/env python3
10886+
2 """Set card game"""
10887+
3
10888+
4 import argparse
10889+
5 import os
10890+
6 import random
10891+
7 import sys
10892+
8 from itertools import product, combinations
10893+
9 from card import Card
10894+
10 from typing import List
10895+
11
10896+
12
10897+
13 # --------------------------------------------------
10898+
14 def get_args():
10899+
15 """Get command-line arguments"""
10900+
16
10901+
17 parser = argparse.ArgumentParser(
10902+
18 description='Argparse Python script',
10903+
19 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
10904+
20
10905+
21 parser.add_argument('-s',
10906+
22 '--seed',
10907+
23 help='Random seed',
10908+
24 metavar='int',
10909+
25 type=int,
10910+
26 default=None)
10911+
27
10912+
28 return parser.parse_args()
10913+
29
10914+
30
10915+
31 # --------------------------------------------------
10916+
32 def make_deck() -> List[Card]:
10917+
33 """Make Set deck"""
10918+
34
10919+
35 colors = ['Red', 'Purple', 'Green']
10920+
36 shapes = ['Oval', 'Squiggle', 'Diamond']
10921+
37 number = ['1', '2', '3']
10922+
38 shading = ['Solid', 'Striped', 'Outlined']
10923+
39
10924+
40 return list(
10925+
41 map(lambda t: Card(color=t[0], shape=t[1], number=t[2], shading=t[3]),
10926+
42 product(colors, shapes, number, shading)))
10927+
43
10928+
44
10929+
45 # --------------------------------------------------
10930+
46 def test_make_deck():
10931+
47 """Test make_deck"""
10932+
48
10933+
49 deck = make_deck()
10934+
50 assert len(deck) == 81
10935+
51
10936+
52
10937+
53 # --------------------------------------------------
10938+
54 def add(bits: List[list]) -> int:
10939+
55 """Add the bits"""
10940+
56
10941+
57 assert isinstance(bits, list)
10942+
58 assert isinstance(bits[0], list)
10943+
59
10944+
60 num_recs = len(bits)
10945+
61 num_bits = len(bits[0])
10946+
62
10947+
63 ret = []
10948+
64 for i in range(num_bits):
10949+
65 ret.append(1 if any(map(lambda n: bits[n][i], range(num_recs))) else 0)
10950+
66
10951+
67 return sum(ret)
10952+
68
10953+
69
10954+
70 # --------------------------------------------------
10955+
71 def find_set(cards: List[Card]) -> List[tuple]:
10956+
72 """Find a 'set' in a hand of cards"""
10957+
73
10958+
74 colors = list(map(lambda c: c.encode_color(), cards))
10959+
75 shapes = list(map(lambda c: c.encode_shape(), cards))
10960+
76 numbers = list(map(lambda c: c.encode_number(), cards))
10961+
77 shadings = list(map(lambda c: c.encode_shading(), cards))
10962+
78
10963+
79 sets = []
10964+
80 for combo in combinations(range(len(cards)), 3):
10965+
81 color = add(list(map(lambda i: colors[i], combo)))
10966+
82 shape = add(list(map(lambda i: shapes[i], combo)))
10967+
83 number = add(list(map(lambda i: numbers[i], combo)))
10968+
84 shading = add(list(map(lambda i: shadings[i], combo)))
10969+
85
10970+
86 if all([x in [1, 3] for x in [color, shape, number, shading]]):
10971+
87 sets.append(combo)
10972+
88
10973+
89 return sets
10974+
90
10975+
91 # --------------------------------------------------
10976+
92 def main():
10977+
93 """Make a jazz noise here"""
10978+
94
10979+
95 args = get_args()
10980+
96 deck: List[Card] = make_deck()
10981+
97
10982+
98 random.seed(args.seed)
10983+
99 cards: List[Card] = random.sample(deck, k=12)
10984+
100
10985+
101 for combo in find_set(cards):
10986+
102 print(combo)
10987+
103 print('\n'.join(map(lambda i: str(cards[i]), combo)))
10988+
104
10989+
105
10990+
106 # --------------------------------------------------
10991+
107 if __name__ == '__main__':
10992+
108 main()
10993+
````
10994+
10995+
\newpage
10996+
1087510997
# Appendix 1: argparse
1087610998

1087710999
The `argparse` module will interpret all the command-line arguments to your program. I suggest you use `argparse` for every command-line program you write so that you always have a standard way to get arguments and present help.
Collapse file

‎playful_python.pdf‎

Copy file name to clipboard
3.78 KB
Binary file not shown.
Collapse file

‎set/Makefile‎

Copy file name to clipboard
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.PHONY: pdf test
2+
3+
pdf:
4+
pandoc README.md -o README.pdf
5+
6+
test:
7+
pytest -v test.py
Collapse file

‎set/README.md‎

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ready, Set, Go!
2+
3+
Write a Python program called `set.py` that plays the Set card game.
Collapse file

‎set/card.py‎

Copy file name to clipboard
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
5+
class Card:
6+
color: str
7+
shape: str
8+
number: str
9+
shading: str
10+
11+
def __str__(self):
12+
return 'Card({})'.format(' '.join(
13+
[self.number, self.color, self.shading, self.shape]))
14+
15+
def encode_color(self):
16+
colors = ['Red', 'Purple', 'Green']
17+
return [1 if self.color == c else 0 for c in colors]
18+
19+
def encode_shape(self):
20+
shapes = ['Oval', 'Squiggle', 'Diamond']
21+
return [1 if self.shape == s else 0 for s in shapes]
22+
23+
def encode_number(self):
24+
numbers = ['1', '2', '3']
25+
return [1 if self.number == n else 0 for n in numbers]
26+
27+
def encode_shading(self):
28+
shadings = ['Solid', 'Striped', 'Outlined']
29+
return [1 if self.shading == s else 0 for s in shadings]
Collapse file

‎set/solution.py‎

Copy file name to clipboard
+108Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python3
2+
"""Set card game"""
3+
4+
import argparse
5+
import os
6+
import random
7+
import sys
8+
from itertools import product, combinations
9+
from card import Card
10+
from typing import List
11+
12+
13+
# --------------------------------------------------
14+
def get_args():
15+
"""Get command-line arguments"""
16+
17+
parser = argparse.ArgumentParser(
18+
description='Argparse Python script',
19+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
20+
21+
parser.add_argument('-s',
22+
'--seed',
23+
help='Random seed',
24+
metavar='int',
25+
type=int,
26+
default=None)
27+
28+
return parser.parse_args()
29+
30+
31+
# --------------------------------------------------
32+
def make_deck() -> List[Card]:
33+
"""Make Set deck"""
34+
35+
colors = ['Red', 'Purple', 'Green']
36+
shapes = ['Oval', 'Squiggle', 'Diamond']
37+
number = ['1', '2', '3']
38+
shading = ['Solid', 'Striped', 'Outlined']
39+
40+
return list(
41+
map(lambda t: Card(color=t[0], shape=t[1], number=t[2], shading=t[3]),
42+
product(colors, shapes, number, shading)))
43+
44+
45+
# --------------------------------------------------
46+
def test_make_deck():
47+
"""Test make_deck"""
48+
49+
deck = make_deck()
50+
assert len(deck) == 81
51+
52+
53+
# --------------------------------------------------
54+
def add(bits: List[list]) -> int:
55+
"""Add the bits"""
56+
57+
assert isinstance(bits, list)
58+
assert isinstance(bits[0], list)
59+
60+
num_recs = len(bits)
61+
num_bits = len(bits[0])
62+
63+
ret = []
64+
for i in range(num_bits):
65+
ret.append(1 if any(map(lambda n: bits[n][i], range(num_recs))) else 0)
66+
67+
return sum(ret)
68+
69+
70+
# --------------------------------------------------
71+
def find_set(cards: List[Card]) -> List[tuple]:
72+
"""Find a 'set' in a hand of cards"""
73+
74+
colors = list(map(lambda c: c.encode_color(), cards))
75+
shapes = list(map(lambda c: c.encode_shape(), cards))
76+
numbers = list(map(lambda c: c.encode_number(), cards))
77+
shadings = list(map(lambda c: c.encode_shading(), cards))
78+
79+
sets = []
80+
for combo in combinations(range(len(cards)), 3):
81+
color = add(list(map(lambda i: colors[i], combo)))
82+
shape = add(list(map(lambda i: shapes[i], combo)))
83+
number = add(list(map(lambda i: numbers[i], combo)))
84+
shading = add(list(map(lambda i: shadings[i], combo)))
85+
86+
if all([x in [1, 3] for x in [color, shape, number, shading]]):
87+
sets.append(combo)
88+
89+
return sets
90+
91+
# --------------------------------------------------
92+
def main():
93+
"""Make a jazz noise here"""
94+
95+
args = get_args()
96+
deck: List[Card] = make_deck()
97+
98+
random.seed(args.seed)
99+
cards: List[Card] = random.sample(deck, k=12)
100+
101+
for combo in find_set(cards):
102+
print(combo)
103+
print('\n'.join(map(lambda i: str(cards[i]), combo)))
104+
105+
106+
# --------------------------------------------------
107+
if __name__ == '__main__':
108+
main()
Collapse file

‎set/test.py‎

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

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.