Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/turtledemo/nim.py @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 """ turtle-example-suite: | |
2 | |
3 tdemo_nim.py | |
4 | |
5 Play nim against the computer. The player | |
6 who takes the last stick is the winner. | |
7 | |
8 Implements the model-view-controller | |
9 design pattern. | |
10 """ | |
11 | |
12 | |
13 import turtle | |
14 import random | |
15 import time | |
16 | |
17 SCREENWIDTH = 640 | |
18 SCREENHEIGHT = 480 | |
19 | |
20 MINSTICKS = 7 | |
21 MAXSTICKS = 31 | |
22 | |
23 HUNIT = SCREENHEIGHT // 12 | |
24 WUNIT = SCREENWIDTH // ((MAXSTICKS // 5) * 11 + (MAXSTICKS % 5) * 2) | |
25 | |
26 SCOLOR = (63, 63, 31) | |
27 HCOLOR = (255, 204, 204) | |
28 COLOR = (204, 204, 255) | |
29 | |
30 def randomrow(): | |
31 return random.randint(MINSTICKS, MAXSTICKS) | |
32 | |
33 def computerzug(state): | |
34 xored = state[0] ^ state[1] ^ state[2] | |
35 if xored == 0: | |
36 return randommove(state) | |
37 for z in range(3): | |
38 s = state[z] ^ xored | |
39 if s <= state[z]: | |
40 move = (z, s) | |
41 return move | |
42 | |
43 def randommove(state): | |
44 m = max(state) | |
45 while True: | |
46 z = random.randint(0,2) | |
47 if state[z] > (m > 1): | |
48 break | |
49 rand = random.randint(m > 1, state[z]-1) | |
50 return z, rand | |
51 | |
52 | |
53 class NimModel(object): | |
54 def __init__(self, game): | |
55 self.game = game | |
56 | |
57 def setup(self): | |
58 if self.game.state not in [Nim.CREATED, Nim.OVER]: | |
59 return | |
60 self.sticks = [randomrow(), randomrow(), randomrow()] | |
61 self.player = 0 | |
62 self.winner = None | |
63 self.game.view.setup() | |
64 self.game.state = Nim.RUNNING | |
65 | |
66 def move(self, row, col): | |
67 maxspalte = self.sticks[row] | |
68 self.sticks[row] = col | |
69 self.game.view.notify_move(row, col, maxspalte, self.player) | |
70 if self.game_over(): | |
71 self.game.state = Nim.OVER | |
72 self.winner = self.player | |
73 self.game.view.notify_over() | |
74 elif self.player == 0: | |
75 self.player = 1 | |
76 row, col = computerzug(self.sticks) | |
77 self.move(row, col) | |
78 self.player = 0 | |
79 | |
80 def game_over(self): | |
81 return self.sticks == [0, 0, 0] | |
82 | |
83 def notify_move(self, row, col): | |
84 if self.sticks[row] <= col: | |
85 return | |
86 self.move(row, col) | |
87 | |
88 | |
89 class Stick(turtle.Turtle): | |
90 def __init__(self, row, col, game): | |
91 turtle.Turtle.__init__(self, visible=False) | |
92 self.row = row | |
93 self.col = col | |
94 self.game = game | |
95 x, y = self.coords(row, col) | |
96 self.shape("square") | |
97 self.shapesize(HUNIT/10.0, WUNIT/20.0) | |
98 self.speed(0) | |
99 self.pu() | |
100 self.goto(x,y) | |
101 self.color("white") | |
102 self.showturtle() | |
103 | |
104 def coords(self, row, col): | |
105 packet, remainder = divmod(col, 5) | |
106 x = (3 + 11 * packet + 2 * remainder) * WUNIT | |
107 y = (2 + 3 * row) * HUNIT | |
108 return x - SCREENWIDTH // 2 + WUNIT // 2, SCREENHEIGHT // 2 - y - HUNIT // 2 | |
109 | |
110 def makemove(self, x, y): | |
111 if self.game.state != Nim.RUNNING: | |
112 return | |
113 self.game.controller.notify_move(self.row, self.col) | |
114 | |
115 | |
116 class NimView(object): | |
117 def __init__(self, game): | |
118 self.game = game | |
119 self.screen = game.screen | |
120 self.model = game.model | |
121 self.screen.colormode(255) | |
122 self.screen.tracer(False) | |
123 self.screen.bgcolor((240, 240, 255)) | |
124 self.writer = turtle.Turtle(visible=False) | |
125 self.writer.pu() | |
126 self.writer.speed(0) | |
127 self.sticks = {} | |
128 for row in range(3): | |
129 for col in range(MAXSTICKS): | |
130 self.sticks[(row, col)] = Stick(row, col, game) | |
131 self.display("... a moment please ...") | |
132 self.screen.tracer(True) | |
133 | |
134 def display(self, msg1, msg2=None): | |
135 self.screen.tracer(False) | |
136 self.writer.clear() | |
137 if msg2 is not None: | |
138 self.writer.goto(0, - SCREENHEIGHT // 2 + 48) | |
139 self.writer.pencolor("red") | |
140 self.writer.write(msg2, align="center", font=("Courier",18,"bold")) | |
141 self.writer.goto(0, - SCREENHEIGHT // 2 + 20) | |
142 self.writer.pencolor("black") | |
143 self.writer.write(msg1, align="center", font=("Courier",14,"bold")) | |
144 self.screen.tracer(True) | |
145 | |
146 def setup(self): | |
147 self.screen.tracer(False) | |
148 for row in range(3): | |
149 for col in range(self.model.sticks[row]): | |
150 self.sticks[(row, col)].color(SCOLOR) | |
151 for row in range(3): | |
152 for col in range(self.model.sticks[row], MAXSTICKS): | |
153 self.sticks[(row, col)].color("white") | |
154 self.display("Your turn! Click leftmost stick to remove.") | |
155 self.screen.tracer(True) | |
156 | |
157 def notify_move(self, row, col, maxspalte, player): | |
158 if player == 0: | |
159 farbe = HCOLOR | |
160 for s in range(col, maxspalte): | |
161 self.sticks[(row, s)].color(farbe) | |
162 else: | |
163 self.display(" ... thinking ... ") | |
164 time.sleep(0.5) | |
165 self.display(" ... thinking ... aaah ...") | |
166 farbe = COLOR | |
167 for s in range(maxspalte-1, col-1, -1): | |
168 time.sleep(0.2) | |
169 self.sticks[(row, s)].color(farbe) | |
170 self.display("Your turn! Click leftmost stick to remove.") | |
171 | |
172 def notify_over(self): | |
173 if self.game.model.winner == 0: | |
174 msg2 = "Congrats. You're the winner!!!" | |
175 else: | |
176 msg2 = "Sorry, the computer is the winner." | |
177 self.display("To play again press space bar. To leave press ESC.", msg2) | |
178 | |
179 def clear(self): | |
180 if self.game.state == Nim.OVER: | |
181 self.screen.clear() | |
182 | |
183 | |
184 class NimController(object): | |
185 | |
186 def __init__(self, game): | |
187 self.game = game | |
188 self.sticks = game.view.sticks | |
189 self.BUSY = False | |
190 for stick in self.sticks.values(): | |
191 stick.onclick(stick.makemove) | |
192 self.game.screen.onkey(self.game.model.setup, "space") | |
193 self.game.screen.onkey(self.game.view.clear, "Escape") | |
194 self.game.view.display("Press space bar to start game") | |
195 self.game.screen.listen() | |
196 | |
197 def notify_move(self, row, col): | |
198 if self.BUSY: | |
199 return | |
200 self.BUSY = True | |
201 self.game.model.notify_move(row, col) | |
202 self.BUSY = False | |
203 | |
204 | |
205 class Nim(object): | |
206 CREATED = 0 | |
207 RUNNING = 1 | |
208 OVER = 2 | |
209 def __init__(self, screen): | |
210 self.state = Nim.CREATED | |
211 self.screen = screen | |
212 self.model = NimModel(self) | |
213 self.view = NimView(self) | |
214 self.controller = NimController(self) | |
215 | |
216 | |
217 def main(): | |
218 mainscreen = turtle.Screen() | |
219 mainscreen.mode("standard") | |
220 mainscreen.setup(SCREENWIDTH, SCREENHEIGHT) | |
221 nim = Nim(mainscreen) | |
222 return "EVENTLOOP" | |
223 | |
224 if __name__ == "__main__": | |
225 main() | |
226 turtle.mainloop() |