JustToThePoint English Website Version
JustToThePoint en español
JustToThePoint in Thai

Tic Tac Toe. Minimax. GUI using tkinter.

Tic Tac Toe

Tic-tac-toe is a paper-and-pencil game for two players who take turns marking the spaces in a three-by-three grid with X or O. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row is the winner.

First, we are going to implement a class representing the player.

import random
from copy import deepcopy
from rich import print # Rich is a Python library for rich text and beautiful formatting in the terminal. 

class Player:
    def __init__(self, type, symbol):
        self.type = type # There are two types of players: Player and Ai.
        self.symbol = symbol # This is the symbol representing the player on the board.
    def getSymbol(self):
        return self.symbol

This class was quite simple, wasn’t it? Let’s implement a second class to play the tic-tac-toe game.

class Game:
    def __init__(self, symbol):
        self.board = [' ' for x in range(9)] #  We create a blank board for placing the players' symbols, typically “X’s” and “O’s”.
        self.player = Player("Player", symbol)
        if symbol=='X':
            self.ai = Player("Ai", "O")
        else:
            self.ai = Player("Ai", "X")

    def drawPiece(self, piece): # This auxiliary method is used by drawBoard to draw the players' symbols in red (player) or blue (ai). It utilizes the Rich library for adding colors to our players' symbols in the terminal. 
        if piece==self.player.getSymbol():
            return "[red]" + piece + "[/red]"
        elif piece==self.ai.getSymbol():
            return "[blue]" + piece + "[/blue]"
        else:
            return " "

    def drawBoard(self):
    # It draws our board in a nice way.
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[0]) + ' | ' + self.drawPiece(self.board[1]) + ' | ' + self.drawPiece(self.board[2]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[3]) + ' | ' + self.drawPiece(self.board[4]) + ' | ' + self.drawPiece(self.board[5]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[6]) + ' | ' + self.drawPiece(self.board[7]) + ' | ' + self.drawPiece(self.board[8]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
    
    def isBoardFull(self):
    # It returns True if every space on the board has already been taken. Otherwise, it returns False. 
        if self.board.count(" ") > 0:
            return False
        else:
            return True

    def isWinnerHorizontally(self, player):
    # It returns True if "player" has placed three of his marks in a horizontal row.
        return ((self.board[6] == player.getSymbol() and self.board[7] == player.getSymbol() and self.board[8] == player.getSymbol()) or # the bottom row
    (self.board[3] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[5] == player.getSymbol()) or # the middle row
    (self.board[0] == player.getSymbol() and self.board[1] == player.getSymbol() and self.board[2] == player.getSymbol())) # the top row

    def isWinnerVertically(self, player):
    # It returns True if "player" has placed three of his marks in a vertical column.
        return ((self.board[6] == player.getSymbol() and self.board[3] == player.getSymbol() and self.board[0] == player.getSymbol()) or # The left column.
    (self.board[7] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[1] == player.getSymbol()) or # The middle column.
    (self.board[8] == player.getSymbol() and self.board[5] == player.getSymbol() and self.board[2] == player.getSymbol())) # The right column.
    
    def isWinnerDiagonally(self, player):
    # It returns True if "player" has placed three of his marks in one of the two diagonals.
        return ((self.board[6] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[2] == player.getSymbol()) 
    (self.board[8] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[0] == player.getSymbol())) 

    def isWinner(self, player):
    # It returns True if "player" has won. In other words, it returns True if "player" has placed three of his marks in a row, column, or diagonally. 
        return self.isWinnerHorizontally(player) or self.isWinnerVertically(player) or self.isWinnerDiagonally(player)
    
    def positionIsFree(self, position):
    # It returns True is "position" is free. If "position" is already taken, it will return False.
        return self.board[position-1] == ' '        
    
    def move(self, player, position):
    # "player" moves (or adds) his mark to "position". It inserts the player's symbol on the board in the "position - 1" index. 
        self.board[position-1] = player.getSymbol()

    def playerMove(self):
    # It asks the user to introduce a position, then checks if the position is valid, and finally, it moves the player to the desired position.
        validMove = False 
        while not validMove:  # It keeps looping and asking the user until we get a valid move.
            move = input('Please select a position (1-9): ')
            try:
                move  = int(move)
                if move > 0 and move < 10:  # It makes sure that the user types a valid position, i.e., a number between 1-9.
                    if self.positionIsFree(move):  # It checks if the position is already taken.
                        validMove = True
                        self.move(self.player, move) # If the position is valid and free, it moves the player to the desired position.
                    else:
                        print('This position is already taken!')
                else:
                    print('Please type a number within the range 1-9!')
            except:
                print('Please type a number (1-9)!')

    def chooseRandomFromList(self, movesList):
    # It returns a valid move from the list "movesList" passed as a parameter. Otherwise, it returns None.
        possibleMoves = [] # It will contain all the free positions of the list "movesList" passed as a parameter.
        for i in movesList:
            if self.positionIsFree(i):
                possibleMoves.append(i)
    
        if len(possibleMoves) != 0: # If there is at least one free position on the list, it will randomly select one of them.
            return random.choice(possibleMoves)
        else: # Otherwise, it will return None.
            return None

This is the computer’s algorithm for choosing a move. Some of our code is partially based on ideas of the articles about Tic Tac Toe of copyassignment.com and inventwithpython.

    def aiMove(self):
    # Firstly, we check if we can win in the next move.
        for i in range(1, 10): # It loops through all board's positions.
            copy = deepcopy(self) # deepcopy makes a new object that is a deep copy of self. Observe that copy is a fully independent clone of the original object.
            if copy.positionIsFree(i): # If the "i" position is available ...
                copy.move(copy.ai, i) # we move the "Ai" player in this position.
                if copy.isWinner(copy.ai): # If we are lucky and it is a winning position, we return this position.
                    return i
            
    # Secondly, we check if the player could win on his next move. If this is the case, we will block him by choosing the position "i" on the board where he would win.
        for i in range(1, 10):
            copy = deepcopy(self)
            if copy.positionIsFree(i):
                copy.move(copy.player, i)
                if copy.isWinner(copy.player):
                    return i

    # Thirdly, if one of the four corners is not already taken, we choose it.
        move = self.chooseRandomFromList([1, 3, 7, 9])
        if move != None:
            return move

    # We are running out of options, let's try to move to the board's center.
        if self.positionIsFree(5):
            return 5

    # 2, 4, 6, 8 are the last places to choose from.
        move = self.chooseRandomFromList([2, 4, 6, 8])
        if move != None:
            return move
        else:
            return None

def main():
    print('Welcome to Tic Tac Toe! If you want to win, you need to complete a straight line (Diagonal, Horizontal, Vertical). The board has nine positions 1-9 starting at the top left.')
    answer = input('What is your favourite symbol: O, X, *, $, ... ')
    myGame = Game(answer.upper())
    myGame.drawBoard()

    while not(myGame.isBoardFull()): # The game's loop is finished when the board is full.
        if not(myGame.isWinner(myGame.ai)): # If the computer has not won yet.
            myGame.playerMove() # It is the player's turn.
            myGame.drawBoard() # After the player has moved, we draw the board.
        else:
            print('Computer wins.')
            break
        
        if not(myGame.isWinner(myGame.player)): # If the player has not won yet.
            move = myGame.aiMove() # We decide where the AI player should move.
            if move == None: # If no place or position has been found, it means that the board is already full. You could give the option to decide who goes first.
                print('Game is a Tie! No more spaces left to move.')
            else:
                myGame.move(myGame.ai, move) # Otherwise, the AI player moves to his best position.
                print(f"Ai has placed an {myGame.ai.getSymbol()} in position {move}.")
                myGame.drawBoard() # And show the board.
        else:
            print('Player wins, good job!')
            break

if __name__ == "__main__":
    main()
    playAgain = True
    while playAgain:
        answer = input('Do you want to play again? (Y/N) ' )
        if answer.lower() == 'y' or answer.lower() == 'yes':
            print('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐-')
            main()
        else:
            playAgain = False

tictactoe

TicTacToe in Python with “minimax” AI

First, we are going to implement a class representing the player.

import random
from copy import deepcopy
from rich import print # Rich is a Python library for rich text and beautiful formatting in the terminal. 

class Player:
    def __init__(self, type, symbol):
        self.type = type # There are two types of players: Player and Ai.
        self.symbol = symbol # This is the symbol representing the player on the board.
    def getSymbol(self):
        return self.symbol

This class was quite simple, wasn't it? Let's implement a second class to play the tic-tac-toe game.

class Game:
    def __init__(self, symbol, difficulty):
        self.board = [' ' for x in range(9)] #  We create a blank board for placing the players' symbols, typically “X’s” and “O’s”.
        self.player = Player("Player", symbol)
        if symbol=='X':
            self.ai = Player("Ai", "O")
        else:
            self.ai = Player("Ai", "X")
        if difficulty==1 or difficulty==2: # Difficulty = 1 is the previous algorithm, 2 is the "minimax" AI.
            self.difficulty =  difficulty
        else:
            self.difficulty = 2

    def drawPiece(self, piece): # This auxiliary method is used by drawBoard to draw the players' symbols in red (player) or blue (ai). It utilizes the Rich library for adding colors to our players' symbols in the terminal. 
        if piece==self.player.getSymbol():
            return "[red]" + piece + "[/red]"
        elif piece==self.ai.getSymbol():
            return "[blue]" + piece + "[/blue]"
        else:
            return " "

    def drawBoard(self):
    # It draws our board in a nice way.
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[0]) + ' | ' + self.drawPiece(self.board[1]) + ' | ' + self.drawPiece(self.board[2]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[3]) + ' | ' + self.drawPiece(self.board[4]) + ' | ' + self.drawPiece(self.board[5]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
        print('|' + self.drawPiece(self.board[6]) + ' | ' + self.drawPiece(self.board[7]) + ' | ' + self.drawPiece(self.board[8]) + '| ')
        print('+‐‐‐‐‐‐‐‐-+')
    
    def isBoardFull(self):
    # It returns True if every space on the board has already been taken. Otherwise, it returns False. 
        if self.board.count(" ") > 0:
            return False
        else:
            return True

    def isWinnerHorizontally(self, player):
    # It returns True if "player" has placed three of his marks in a horizontal row.
        return ((self.board[6] == player.getSymbol() and self.board[7] == player.getSymbol() and self.board[8] == player.getSymbol()) or # the bottom row
    (self.board[3] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[5] == player.getSymbol()) or # the middle row
    (self.board[0] == player.getSymbol() and self.board[1] == player.getSymbol() and self.board[2] == player.getSymbol())) # the top row

    def isWinnerVertically(self, player):
    # It returns True if "player" has placed three of his marks in a vertical column.
        return ((self.board[6] == player.getSymbol() and self.board[3] == player.getSymbol() and self.board[0] == player.getSymbol()) or # The left column.
    (self.board[7] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[1] == player.getSymbol()) or # The middle column.
    (self.board[8] == player.getSymbol() and self.board[5] == player.getSymbol() and self.board[2] == player.getSymbol())) # The right column.
    
    def isWinnerDiagonally(self, player):
    # It returns True if "player" has placed three of his marks in one of the two diagonals.
        return ((self.board[6] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[2] == player.getSymbol()) 
    (self.board[8] == player.getSymbol() and self.board[4] == player.getSymbol() and self.board[0] == player.getSymbol())) 

    def isWinner(self, player):
    # It returns True if "player" has won. In other words, it returns True if "player" has placed three of his marks in a row, column, or diagonally. 
        return self.isWinnerHorizontally(player) or self.isWinnerVertically(player) or self.isWinnerDiagonally(player)
    
    def positionIsFree(self, position):
    # It returns True is "position" is free. If "position" is already taken, it will return False.
        return self.board[position-1] == ' '        
    
    def move(self, player, position):
    # "player" moves (or adds) his mark to "position". It inserts the player's symbol on the board in the "position - 1" index. 
        self.board[position-1] = player.getSymbol()

    def playerMove(self):
    # It asks the user to introduce a position, then checks if the position is valid, and finally, it moves the player to the desired position.
        validMove = False 
        while not validMove:  # It keeps looping and asking the user until we get a valid move.
            move = input('Please select a position (1-9): ')
            try:
                move  = int(move)
                if move > 0 and move < 10:  # It makes sure that the user types a valid position, i.e., a number between 1-9.
                    if self.positionIsFree(move):  # It checks if the position is already taken.
                        validMove = True
                        self.move(self.player, move) # If the position is valid and free, it moves the player to the desired position.
                    else:
                        print('This position is already taken!')
                else:
                    print('Please type a number within the range 1-9!')
            except:
                print('Please type a number (1-9)!')

    def chooseRandomFromList(self, movesList):
    # It returns a valid move from the list "movesList" passed as a parameter. Otherwise, it returns None.
        possibleMoves = [] # It will contain all the free positions of the list "movesList" passed as a parameter.
        for i in movesList:
            if self.positionIsFree(i):
                possibleMoves.append(i)
    
        if len(possibleMoves) != 0: # If there is at least one free position on the list, it will randomly select one of them.
            return random.choice(possibleMoves)
        else: # Otherwise, it will return None.
            return None

    def aiMove(self):
        if self.difficulty==1:
            return self.aiMoveEasy()
        else:
            return self.aiMoveDifficult()

This is the computer’s algorithm for choosing a move. Some of our code is partially based on ideas of the articles about Tic Tac Toe of copyassignment.com and inventwithpython.

    def aiMoveEasy(self):
    # Firstly, we check if we can win in the next move.
        for i in range(1, 10): # It loops through all board's positions.
            copy = deepcopy(self) # deepcopy makes _a new object that is a deep copy of self_. Observe that copy is a fully independent clone of the original object.
            if copy.positionIsFree(i): # If the "i" position is available ...
                copy.move(copy.ai, i) # we move the "Ai" player in this position.
                if copy.isWinner(copy.ai): # If we are lucky and it is a winning position, we return this position.
                    return i
            
    # Secondly, we check if the player could win on his next move. If this is the case, we will block him by choosing the position "i" on the board where he would win.
        for i in range(1, 10):
            copy = deepcopy(self)
            if copy.positionIsFree(i):
                copy.move(copy.player, i)
                if copy.isWinner(copy.player):
                    return i

    # Thirdly, if one of the four corners is not already taken, we choose it.
        move = self.chooseRandomFromList([1, 3, 7, 9])
        if move != None:
            return move

    # We are running out of options, let's try to move to the board's center.
        if self.positionIsFree(5):
            return 5

    # 2, 4, 6, 8 are the last places to choose from.
        move = self.chooseRandomFromList([2, 4, 6, 8])
        if move != None:
            return move
        else:
            return None

    def minimax(self, computer):
    # It returns bestScore, bestPosition
        if self.isWinner(self.ai):
        # If AI has already won (leaf node), it returns the best score and the "None" position. 
            return (1000, None)
        elif self.isWinner(self.player):
        # If the player has won (leaf node), it returns the worst score and the "None" position.
            return (-1000, None)
        if self.isBoardFull():
        # If there is a tie (leaf node), it returns 0 as a score and the "None" position.
            return (0, None)
        if (computer): # Minimax tries to maximize its advantage over the opponent, it evaluates all branches of the game tree and then chooses the one with maximum advantage or score. The value to the maximizing player (computer) is the maximum of the values resulting from each of player's possible replies.
            bestScore = -1000
            bestPosition = -1
            for i in range(1, 10):
                copy = deepcopy(self)
                if copy.positionIsFree(i):
                    copy.move(copy.ai, i)
                    newScore = copy.minimax(not computer)[0]
                    if bestScore < newScore:
                        bestScore = newScore
                        bestPosition = i
            return bestScore, bestPosition
        else: # If it is the player, minimax tries to minimize the worst-case scenario. The value to the minimizing player (player) is the minimum of the values resulting from each of the computer's possible replies.
            bestScore = 1000
            bestPosition = -1
            for i in range(1, 10):
                copy = deepcopy(self)
                if copy.positionIsFree(i):
                    copy.move(copy.player, i)
                    newScore = copy.minimax(not computer)[0]
                    if bestScore > newScore:
                        bestScore = newScore
                        bestPosition = i
                    
            return bestScore, bestPosition

    def aiMoveDifficult(self):
        return self.minimax(True)[1]

def main():
    #Main game loop
    print('Welcome to Tic Tac Toe! If you want to win, you need to complete a straight line (Diagonal, Horizontal, Vertical). The board has nine positions 1-9 starting at the top left.')
    answer = input('What is your favourite symbol: O, X, *, $, ... ')
    level = input('Level: easy (1) or difficult (2) ')    
    myGame = Game(answer.upper(), int(level))
    myGame.drawBoard()

    while not(myGame.isBoardFull()): # The game's loop is finished when the board is full.
        if not(myGame.isWinner(myGame.ai)): # If the computer has not won yet.
            myGame.playerMove() # It is the player's turn.
            myGame.drawBoard() # After the player has moved, we draw the board.
        else:
            print('Computer wins.')
            break
        
        if not(myGame.isWinner(myGame.player)): # If the player has not won yet.
            move = myGame.aiMove() # We decide where the AI player should move.
            if move == None: # If no place or position has been found, it means that the board is already full. You could give the option to decide who goes first.
                print('Game is a Tie! No more spaces left to move.')
            else:
                myGame.move(myGame.ai, move) # Otherwise, the AI player moves to his best position.
                print(f"Ai has placed an {myGame.ai.getSymbol()} in position {move}.")
                myGame.drawBoard() # And show the board.
        else:
            print('Player wins, good job!')
            break
if __name__ == "__main__":
    main()
    playAgain = True
    while playAgain:
        answer = input('Do you want to play again? (Y/N) ' )
        if answer.lower() == 'y' or answer.lower ()== 'yes':
            print('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐-')
            main()
        else:
            playAgain = False

# GUI using tkinter
class GUI:
    # If the user selects the quit option, this message is displayed
    def quit(self):   
        msg=messagebox.askquestion("Confirm", "Are you sure that you want to quit?)
        if msg=='yes':
            self.app.destroy()

    # It destroys the winner window and the main GUI window.
    def destruct(self):
        global winnerWindow
        self.app.destroy()
        winnerWindow.destroy()

    # It resets the game by destroying the main GUI window and creating a new instance of the GUI class.
    def reset(self):
        self.app.destroy()
        myApp = GUI()

    # It displays the game's end result.
    def displayWinner(self, winner):
        global winnerWindow    
        winnerWindow = Tk()
        winnerWindow.title("Tic Tac Toe")
        winnerWindow.configure(bg="Black")
        l1=Label(winnerWindow,text="THE WINNER IS: ",font=("COMIC SANS MS",15), bg="Black", fg="White")
        l1.pack()
        l2=Label(winnerWindow,text=winner,font=("COMIC SANS MS",15), bg="Black", fg="White")
        l2.pack()
        bproceed=Button(winnerWindow,text="Accept", font=("COMIC SANS MS",10,"bold"), command = self.destruct)
        bproceed.pack()

    # A button b1,..., b9 has been clicked.
    def changeVal(self, button, position):
        # First, we check that the position (or button) is available
        if button["text"] == "":
            button["text"] = "X" # We update the button's text...
            self.myGame.move(self.myGame.player, position) # and move the player in this position.
            if not(self.myGame.isWinner(self.myGame.player)): # If the player has not won yet.
                move = self.myGame.aiMove() # We decide where the AI player should move.
                if move is None: # If no place or position has been found, it means that the board is already full. You could give the option to decide who goes first.
                    self.displayWinner("NONE! IT IS A TIE!")    
                else:
                    self.myGame.move(self.myGame.ai, move) # Otherwise, the AI player moves to his best position.
                    self.buttons[move-1]["text"] = "O" # And we update the board.
                    if self.myGame.isWinner(self.myGame.ai):
                        self.displayWinner("AI is the winner")
            else: # It is not going to happen, but you can change the AI's algorithm to allow the player to win.
                self.displayWinner("Player wins")
        else:
            if self.myGame.isBoardFull():
                self.displayWinner("NONE! IT IS A TIE!")
            else:
                messagebox.showerror("Error", "This box already has a value!")
        self.myGame.drawBoard()
    
def __init__(self):
        self.app =Tk() # It initializes the game's GUI.
        self.app.title("TIC TAC TOE") 
        self.app.configure(bg="white") # The background of the main window is white.
        self.myGame = Game("X", 2) # It creates an object of our tic tac toe game.
        
        # There is a label and two buttons (reset and quit) in the first row. The label indicates the player and AI's marks.
        self.l1=Label(self.app, text="PLAYER: (X), COMPUTER: (O)", height=3, font=("COMIC SANS MS",10,"bold"), bg="white")
        self.l1.grid(row=0,column=0)       
        self.resetButton=Button(self.app, text="Reset", command=self.reset, font=("COMIC SANS MS",20,"bold"))
        self.resetButton.grid(row=0,column=1)
        self.exitButton=Button(self.app, text="Quit", command=self.quit, font=("COMIC SANS MS",20,"bold"))
        self.exitButton.grid(row=0,column=2)

We will have an array of 9 square buttons which are packed together to form our game’s board. In other words, we have 9 buttons b0, b2, b3, b4, b5, b6, b7, b8, b8, and our main window’s layout is in a grid format. When a button is clicked, the function changeVal is called. The parameters of the function are the button itself and its position.

        self.buttons = []
        
        self.b0 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b0,1))
        self.buttons.append(self.b0)
        self.b1 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b1,2))
        self.buttons.append(self.b1)
        self.b2 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b2,3))
        self.buttons.append(self.b2)
        self.b3 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b3,4))
        self.buttons.append(self.b3)
        self.b4 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b4,5))
        self.buttons.append(self.b4)
        self.b5 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b5,6))
        self.buttons.append(self.b5)
        self.b6 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b6,7))
        self.buttons.append(self.b6)
        self.b7 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b7,8))
        self.buttons.append(self.b7)
        self.b8 = Button(self.app,text="",height=4,width=8,bg="black",activebackground="white",fg="white",font="Times 31 bold",command=lambda: self.changeVal(self.b8,9))
        self.buttons.append(self.b8)

        self.b0.grid(row=2,column=0)
        self.b1.grid(row=2,column=1)
        self.b2.grid(row=2,column=2)

        self.b3.grid(row=3,column=0)
        self.b4.grid(row=3,column=1)
        self.b5.grid(row=3,column=2)

        self.b6.grid(row=4,column=0)
        self.b7.grid(row=4,column=1)
        self.b8.grid(row=4,column=2) 
        self.app.mainloop()   

if __name__ == "__main__":
    myApp = GUI()

Tic Tac Toe

Bitcoin donation

JustToThePoint Copyright © 2011 - 2022 PhD. Máximo Núñez Alarcón, Anawim. ALL RIGHTS RESERVED. Bilingual e-books, articles, and videos to help your child and your entire family succeed, develop a healthy lifestyle, and have a lot of fun.

This website uses cookies to improve your navigation experience.
By continuing, you are consenting to our use of cookies, in accordance with our Cookies Policy and Website Terms and Conditions of use.