Spaces:
Build error
Build error
""" turtle-example-suite: | |
tdemo_nim.py | |
Play nim against the computer. The player | |
who takes the last stick is the winner. | |
Implements the model-view-controller | |
design pattern. | |
""" | |
import turtle | |
import random | |
import time | |
SCREENWIDTH = 640 | |
SCREENHEIGHT = 480 | |
MINSTICKS = 7 | |
MAXSTICKS = 31 | |
HUNIT = SCREENHEIGHT // 12 | |
WUNIT = SCREENWIDTH // ((MAXSTICKS // 5) * 11 + (MAXSTICKS % 5) * 2) | |
SCOLOR = (63, 63, 31) | |
HCOLOR = (255, 204, 204) | |
COLOR = (204, 204, 255) | |
def randomrow(): | |
return random.randint(MINSTICKS, MAXSTICKS) | |
def computerzug(state): | |
xored = state[0] ^ state[1] ^ state[2] | |
if xored == 0: | |
return randommove(state) | |
for z in range(3): | |
s = state[z] ^ xored | |
if s <= state[z]: | |
move = (z, s) | |
return move | |
def randommove(state): | |
m = max(state) | |
while True: | |
z = random.randint(0,2) | |
if state[z] > (m > 1): | |
break | |
rand = random.randint(m > 1, state[z]-1) | |
return z, rand | |
class NimModel(object): | |
def __init__(self, game): | |
self.game = game | |
def setup(self): | |
if self.game.state not in [Nim.CREATED, Nim.OVER]: | |
return | |
self.sticks = [randomrow(), randomrow(), randomrow()] | |
self.player = 0 | |
self.winner = None | |
self.game.view.setup() | |
self.game.state = Nim.RUNNING | |
def move(self, row, col): | |
maxspalte = self.sticks[row] | |
self.sticks[row] = col | |
self.game.view.notify_move(row, col, maxspalte, self.player) | |
if self.game_over(): | |
self.game.state = Nim.OVER | |
self.winner = self.player | |
self.game.view.notify_over() | |
elif self.player == 0: | |
self.player = 1 | |
row, col = computerzug(self.sticks) | |
self.move(row, col) | |
self.player = 0 | |
def game_over(self): | |
return self.sticks == [0, 0, 0] | |
def notify_move(self, row, col): | |
if self.sticks[row] <= col: | |
return | |
self.move(row, col) | |
class Stick(turtle.Turtle): | |
def __init__(self, row, col, game): | |
turtle.Turtle.__init__(self, visible=False) | |
self.row = row | |
self.col = col | |
self.game = game | |
x, y = self.coords(row, col) | |
self.shape("square") | |
self.shapesize(HUNIT/10.0, WUNIT/20.0) | |
self.speed(0) | |
self.pu() | |
self.goto(x,y) | |
self.color("white") | |
self.showturtle() | |
def coords(self, row, col): | |
packet, remainder = divmod(col, 5) | |
x = (3 + 11 * packet + 2 * remainder) * WUNIT | |
y = (2 + 3 * row) * HUNIT | |
return x - SCREENWIDTH // 2 + WUNIT // 2, SCREENHEIGHT // 2 - y - HUNIT // 2 | |
def makemove(self, x, y): | |
if self.game.state != Nim.RUNNING: | |
return | |
self.game.controller.notify_move(self.row, self.col) | |
class NimView(object): | |
def __init__(self, game): | |
self.game = game | |
self.screen = game.screen | |
self.model = game.model | |
self.screen.colormode(255) | |
self.screen.tracer(False) | |
self.screen.bgcolor((240, 240, 255)) | |
self.writer = turtle.Turtle(visible=False) | |
self.writer.pu() | |
self.writer.speed(0) | |
self.sticks = {} | |
for row in range(3): | |
for col in range(MAXSTICKS): | |
self.sticks[(row, col)] = Stick(row, col, game) | |
self.display("... a moment please ...") | |
self.screen.tracer(True) | |
def display(self, msg1, msg2=None): | |
self.screen.tracer(False) | |
self.writer.clear() | |
if msg2 is not None: | |
self.writer.goto(0, - SCREENHEIGHT // 2 + 48) | |
self.writer.pencolor("red") | |
self.writer.write(msg2, align="center", font=("Courier",18,"bold")) | |
self.writer.goto(0, - SCREENHEIGHT // 2 + 20) | |
self.writer.pencolor("black") | |
self.writer.write(msg1, align="center", font=("Courier",14,"bold")) | |
self.screen.tracer(True) | |
def setup(self): | |
self.screen.tracer(False) | |
for row in range(3): | |
for col in range(self.model.sticks[row]): | |
self.sticks[(row, col)].color(SCOLOR) | |
for row in range(3): | |
for col in range(self.model.sticks[row], MAXSTICKS): | |
self.sticks[(row, col)].color("white") | |
self.display("Your turn! Click leftmost stick to remove.") | |
self.screen.tracer(True) | |
def notify_move(self, row, col, maxspalte, player): | |
if player == 0: | |
farbe = HCOLOR | |
for s in range(col, maxspalte): | |
self.sticks[(row, s)].color(farbe) | |
else: | |
self.display(" ... thinking ... ") | |
time.sleep(0.5) | |
self.display(" ... thinking ... aaah ...") | |
farbe = COLOR | |
for s in range(maxspalte-1, col-1, -1): | |
time.sleep(0.2) | |
self.sticks[(row, s)].color(farbe) | |
self.display("Your turn! Click leftmost stick to remove.") | |
def notify_over(self): | |
if self.game.model.winner == 0: | |
msg2 = "Congrats. You're the winner!!!" | |
else: | |
msg2 = "Sorry, the computer is the winner." | |
self.display("To play again press space bar. To leave press ESC.", msg2) | |
def clear(self): | |
if self.game.state == Nim.OVER: | |
self.screen.clear() | |
class NimController(object): | |
def __init__(self, game): | |
self.game = game | |
self.sticks = game.view.sticks | |
self.BUSY = False | |
for stick in self.sticks.values(): | |
stick.onclick(stick.makemove) | |
self.game.screen.onkey(self.game.model.setup, "space") | |
self.game.screen.onkey(self.game.view.clear, "Escape") | |
self.game.view.display("Press space bar to start game") | |
self.game.screen.listen() | |
def notify_move(self, row, col): | |
if self.BUSY: | |
return | |
self.BUSY = True | |
self.game.model.notify_move(row, col) | |
self.BUSY = False | |
class Nim(object): | |
CREATED = 0 | |
RUNNING = 1 | |
OVER = 2 | |
def __init__(self, screen): | |
self.state = Nim.CREATED | |
self.screen = screen | |
self.model = NimModel(self) | |
self.view = NimView(self) | |
self.controller = NimController(self) | |
def main(): | |
mainscreen = turtle.Screen() | |
mainscreen.mode("standard") | |
mainscreen.setup(SCREENWIDTH, SCREENHEIGHT) | |
nim = Nim(mainscreen) | |
return "EVENTLOOP" | |
if __name__ == "__main__": | |
main() | |
turtle.mainloop() | |