@@ -155,6 +155,7 @@ Ken Youens-Clark is a Sr. Scientific Programmer in the lab of Dr. Bonnie Hurwitz
15515537. **morse** : Encrypt and decrypt text to and from two versions of Morse code.
15615638. **rot13** : Encode and decode text by rotating the characters through a list.
15715739. **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
1087710999The `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.
0 commit comments