领带时Python TicTacToe GUI游戏崩溃

时间:2014-12-04 07:30:39

标签: python tkinter widget handle tkinter-canvas

我正在尝试使用python构建一个简单的Tic Tac Toe游戏,现在几乎就在那里,除非游戏在每次打结时崩溃

所以当它是平局时,点击的最后一个空方块不会像其他人那样改变颜色,并且窗口冻结,点击被禁用....我不知道原因是

我的整个代码在这里:

import tkinter
import random


class Game(object):
    """
    Enter the class docstring here
    """
    block_size = 100
    def __init__(self, parent):
        parent.title('Tic Tac Toe')
        self.parent = parent

        self.initialize_game()

    def initialize_game(self):
        # These are the initializations that need to happen
        # at the beginning and after restarts
        self.board = [None, None, None, None, None, None, None, None, None]  # game board as a instance variable
        self.map = {(0, 0): 0, (0, 1): 1, (0, 2): 2, (1, 0): 3, (1, 1): 4, (1, 2): 5, (2, 0): 6, (2, 1): 7,
                    (2, 2): 8}  # map to self.board
        self.top_frame = tkinter.Frame(self.parent)
        self.top_frame.pack(side=tkinter.TOP)

        # add restart button on top frame
        restart_button = tkinter.Button(self.top_frame, text='Restart', width=20,
                                        command=self.restart)
        restart_button.pack()  # register restart_button with geometry manager

        # create bottom frame for group the label below
        self.bottom_frame=tkinter.Frame(self.parent)
        self.bottom_frame.pack(side=tkinter.BOTTOM)

        # create label for displaying game result text
        self.my_lbl=tkinter.Label(self.bottom_frame,text=None)
        self.my_lbl.pack()

        # create a canvas to draw our board on the top frame
        self.canvas = tkinter.Canvas(self.top_frame,
                                     width=self.block_size * 3,
                                     height=self.block_size * 3)

        # draw 3x3 visible blocks on the canvas
        for ro in range(3):
            for col in range(3):

                self.canvas.create_rectangle(self.block_size * col,
                                             self.block_size * ro,
                                             self.block_size * (col + 1),
                                             self.block_size * (ro + 1),fill='white')

        # bind entire canvas with left click  handler (play function)
        self.canvas.bind("<Button-1>", self.play)
        self.canvas.pack()                  # register canvas with a geometry manager

    def board_full(self):
        if None not in self.board:
            return True            # true for full
        else:
            return False           # false for not full


    def possible_moves(self):
        """return: list of possible moves"""
        possible_moves = []                 # list for possible moves
        for i in range(0, 9):
            if self.board[i] is None:       # if cell un-taken
                possible_moves.append(i)    # append the cell number to list
            else:
                pass              # cell taken, don't append
        return possible_moves     # return list of possible moves

    def pc_move(self):
        m = True
        while m:
            pc_move = random.randint(0, 8)    # random generate a number from 0 to 8
            if pc_move in self.possible_moves():  # if the number is a possible move
                self.board[pc_move] = 'O'         # mark O
                self.canvas.itemconfigure(tagOrId=(pc_move+1),fill='blue')
                m = False                        # exit loop
            else:                                # not a possible movie
                continue                          # re-do
        return self

    def draw_out(self):
        """to be deleted"""
        print(self.board[0:3])
        print(self.board[3:6])
        print(self.board[6:9])

    def play(self, event):  # This method is invoked when the user clicks on a square.
        """
        when the player clicks on a un-taken square, this method first translate cursor into cell number,
        then update game board and check game result based on condition
        :parameter: click
        :return: updated game object
        """
        # after the click: part 1     human play first
        print('clicked', event.y, event.x)  # to be deleted  show window coordinate
        cx = self.canvas.canvasx(event.x)   # window coordinate to canvas coordinate
        cy = self.canvas.canvasy(event.y)   # window coordinate to canvas coordinate
        cid = self.canvas.find_closest(cx,cy)[0] # find the closet colored widget by click point
        my_move = self.map[(cy // self.block_size, cx // self.block_size)]  # map cursor
        if self.board[my_move] is None:            # check if cell is empty
            self.board[my_move] = 'X'              # if cell empty mark X for my play
            self.canvas.itemconfigure(cid,fill='green') # fill green color for player
            #self.canvas.itemconfigure(tagOrId=(my_move+1),fill='green')
        else:              # if the cell taken, do nothing until click on empty square
            return None
                                      #  check game result and board full:
        self.draw_out()                          # DEBUGGING line
        if self.check_game()is not None:
            print(self.check_game())             # DEBUGGING line
        else:
            pass
        # part 2: while not filled, PC make one move right after my move:
        self.possible_moves()                     # check possible moves for PC
        self.pc_move()                            # pc make move
        self.draw_out()                           # DELETE LATER
        # part3: check game result and board full
        if self.check_game()is not None:
            print(self.check_game())             # DEBUGGING line
        else:
            pass
        return self  # when board is filled, return

    def check_game(self):
        """
        Check if the game is win or lost or a tie
        Return:  win, lose, tie, none """
        result=None
        if (self.board[0] == self.board[1] == self.board[2] == 'X') or (
                            self.board[3] == self.board[4] == self.board[5] == 'X') or (
                            self.board[6] == self.board[7] == self.board[8] == 'X') or (
                            self.board[0] == self.board[3] == self.board[6] == 'X') or (
                            self.board[1] == self.board[4] == self.board[7] == 'X') or (
                            self.board[2] == self.board[5] == self.board[8] == 'X') or (
                            self.board[0] == self.board[4] == self.board[8] == 'X') or (
                            self.board[2] == self.board[4] == self.board[6] == 'X'):
            result = 'You win!'  # player win
            self.my_lbl.configure(text=result)
        elif (self.board[0] == self.board[1] == self.board[2] == 'O') or (
                            self.board[3] == self.board[4] == self.board[5] == 'O') or (
                            self.board[6] == self.board[7] == self.board[8] == 'O') or (
                            self.board[0] == self.board[3] == self.board[6] == 'O') or (
                            self.board[1] == self.board[4] == self.board[7] == 'O') or (
                            self.board[2] == self.board[5] == self.board[8] == 'O') or (
                            self.board[0] == self.board[4] == self.board[8] == 'O') or (
                            self.board[2] == self.board[4] == self.board[6] == 'O'):
            result = 'You lost!'  # player lose
            self.my_lbl.config(text=result)
        elif self.board_full()is True:
                result = 'A tie!'  # tie
                self.my_lbl.configure(text=result)
        else:
            pass
        return result


    def restart(self):
        """ Reinitialize the game and board after restart button is pressed """
        self.top_frame.destroy()
        self.bottom_frame.destroy()
        self.initialize_game()


def main():
    root = tkinter.Tk()  # Instantiate a root window
    my_game = Game(root)  # Instantiate a Game object
    root.mainloop()  # Enter the main event loop


if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:2)

尝试替换

def pc_move(self): m = True while m:

使用

while not self.board_full():

然后将m设置回假break,而不是。{/ p>

您的代码无效的原因是因为如果if pc_move in self.possible_moves():返回false,则运行:

else: continue

直到时间结束。