mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			226 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""      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()
 |