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