(root)/
Python-3.12.0/
Lib/
turtledemo/
nim.py
       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 ESC[4;38;5;81mNimModel(ESC[4;38;5;149mobject):
      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 ESC[4;38;5;81mStick(ESC[4;38;5;149mturtleESC[4;38;5;149m.ESC[4;38;5;149mTurtle):
      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 ESC[4;38;5;81mNimView(ESC[4;38;5;149mobject):
     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 ESC[4;38;5;81mNimController(ESC[4;38;5;149mobject):
     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 ESC[4;38;5;81mNim(ESC[4;38;5;149mobject):
     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()