]> granicus.if.org Git - python/commitdiff
#8616: add new turtle demo "nim".
authorGeorg Brandl <georg@python.org>
Sat, 29 May 2010 08:46:18 +0000 (08:46 +0000)
committerGeorg Brandl <georg@python.org>
Sat, 29 May 2010 08:46:18 +0000 (08:46 +0000)
Demo/turtle/tdemo_nim.py [new file with mode: 0644]

diff --git a/Demo/turtle/tdemo_nim.py b/Demo/turtle/tdemo_nim.py
new file mode 100644 (file)
index 0000000..b0edf44
--- /dev/null
@@ -0,0 +1,227 @@
+"""      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