Programming Pandit

c/c++/c#/Javav/Python


Latest Update

Thursday, September 10, 2020

Nim Design Python programming Demo by G Krishna Chauhan

Source Code



 """      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()





No comments:

Post a Comment