Open In App

Tic Tac Toe game with GUI using tkinter in Python

Improve
Improve
Like Article
Like
Save
Share
Report

Tic-tac-toe (American English), noughts and crosses (British English), or Xs and Os is a paper-and-pencil game for two players, X and O, who take turns marking the spaces in a 3×3 grid. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row is the winner.

tkinter Python library is used to create the GUI. Two options are available to play the game, along with the system or with another player.

A small winning strategy is used to play with the system. The system will try to find the best place to put its naught or cross by which the system will win or try to stop players to win. 

Approach:

  • Create a landing page containing selection buttons: Single-player or multiplayer.
  • Create a game board containing nine tiles to play the game along with other details (i.e. playing with a system or another player, whose turn etc.).
  • Allow the player to press the tile and check the status of the game (i.e. Tie game, any one of the players won the match or the game is still running).
  • Display the message, of who won the match.

Description of other functions:

  • gameboard_pc() and gameboard_pl() will create another geometry to play the game. It will add 9 buttons on the 3×3 board of the game (Three rows of buttons containing three buttons each).
  • get_text_pc() and get_text() functions will put the text on buttons as it is pressed.
  • pc() function will decide the next move of the system.
  • winner() function will check whether the player won the match or not.
  • isfree() function will check whether the player can put it’s a coin or not.
  • isfull() function will check whether the board is full or not.

Example 1: GUI of Tic Tac Toe

Python




#importing Packages from tkinter
from tkinter import * 
from tkinter import messagebox
 
Player1 = 'X'
stop_game = False
 
def clicked(r,c):
     
    #player
    global Player1
    # global stop_game
 
    if Player1 == "X" and states[r] == 0 and stop_game == False:
        b[r].configure(text = "X")
        states[r] = 'X'
        Player1='O'
 
     
    if Player1 == 'O' and states[r] == 0 and stop_game == False:
        b[r].configure(text = 'O')
        states[r] = "O"
        Player1 = "X"
 
    check_if_win()
    # check_if_tie()
    # if check_if_win() == False:
    #     tie = messagebox.showinfo("tie","its tie")
    #     return tie
def check_if_win():
    global stop_game
    # count = 0
 
    for i in range(3):
        if states[i][0] == states[i][1] == states[i][2] !=0:
            stop_game = True
 
            winner = messagebox.showinfo("Winner", states[i][0] + " Won")
            # disableAllButton()
            break
 
    # for j in range(3):
        elif states [0][i] == states[1][i] == states[2][i] != 0:
            stop_game = True
 
            winner = messagebox.showinfo("Winner", states[0][i]+ " Won!")
            break
 
        elif states[0][0] == states[1][1] == states[2][2] !=0:
            stop_game = True
 
            winner = messagebox.showinfo("Winner", states[0][0]+ " Won!")
            break
 
        elif states[0][2] == states[1][1] == states[2][0] !=0:
            stop_game = True
 
            winner = messagebox.showinfo("Winner" , states[0][2]+ " Won!")
            break
 
        elif states[0][0] and states[0][1] and states[0][2] and states[1][0] and states[1][1] and states[1][2] and states[2][0] and states[2][1] and states[2][2] != 0:
            stop_game = True
 
            winner = messagebox.showinfo("tie", "Tie")
 
# Design window
#Creating the Canvas
root = Tk()
# Title of the window            
root.title("GeeksForGeeks-:Tic Tac Toe"
root.resizable(0,0)
 
#Button
b = [
     [0,0,0],
     [0,0,0],
     [0,0,0]]
 
#text for buttons
states = [
     [0,0,0],
     [0,0,0],
     [0,0,0]]
 
for i in range(3):
    for j in range(3):
                                          
        b[i][j] = Button(
                        height = 4, width = 8,
                        font = ("Helvetica","20"),
                        command = lambda r = i, c = j : clicked(r,c))
        b[i][j].grid(row = i, column = j)
 
 
mainloop()           


Output:

 

Code Explanation:

  1. The code starts by importing the tkinter package.
  2. This is a library that allows us to create graphical user interfaces in Python.
  3. Next, we import the messagebox function from this same library.
  4. The messagebox function creates a window with an OK button and text input field for the player to enter their move.
  5. The next line of code sets up our variables: Player1 = ‘X’, stop_game = False.
  6. These are global variables which means they can be accessed anywhere in the program without having to use parentheses or any other special syntax (e. g., if Player1 == “X” and states[r] == 0 ).
  7. Global variables are often used when you want your program’s logic to be able to access all parts of it without needing extra lines of code for each part (e.g., checking if Player1 == “O” and states[r] == 0).
  8. Next, we have two functions: clicked(r,c) and check_if_win().
  9. The first one checks whether player X has won or not based on what state r is currently in; if so, then it changes state r back into X; otherwise, it changes state r into O depending on who won last time.
  10. The code is a function that checks if the player has won or lost.
  11. The code starts by importing tkinter, which is a library for creating graphical user interfaces in Python.
  12. The next line imports messagebox, which allows the program to display messages on screen.
  13. The first line of the function sets up Player1 as “X”.
  14. Then states[r] is set to 0 and stop_game is set to False because this function will be checking if the player has won or lost.
  15. If they have won then states[r] will be changed to “X” and Player1 will be changed to “O”.
  16. If they have lost then states[r] will be changed to “O” and Player1 will be changed.
  17. The code starts by declaring a global variable called stop_game.
  18. The code then declares three loops that iterate through the states of the game board.
  19. Inside each loop, if any state is true, then stop_game is set to True, and winner is displayed in messagebox with the corresponding state value.
  20. The check_if_win() function checks if there are any winning combinations on the board.
  21. If so, it displays “Winner” in messagebox with the corresponding state value and sets stop_game to True.
  22. The code checks if the player has won.
  23. If they have, it displays a messagebox with the states of the game and their corresponding values.
  24. If they haven’t, it displays a messagebox with “tie” and returns from the function.

Example 2) GUI of Tic Tac Toe

Python3




# Tic Tac Toe game with GUI
# using tkinter
 
# importing all necessary libraries
import random
import tkinter
from tkinter import *
from functools import partial
from tkinter import messagebox
from copy import deepcopy
 
# sign variable to decide the turn of which player
sign = 0
 
# Creates an empty board
global board
board = [[" " for x in range(3)] for y in range(3)]
 
# Check l(O/X) won the match or not
# according to the rules of the game
 
 
def winner(b, l):
    return ((b[0][0] == l and b[0][1] == l and b[0][2] == l) or
            (b[1][0] == l and b[1][1] == l and b[1][2] == l) or
            (b[2][0] == l and b[2][1] == l and b[2][2] == l) or
            (b[0][0] == l and b[1][0] == l and b[2][0] == l) or
            (b[0][1] == l and b[1][1] == l and b[2][1] == l) or
            (b[0][2] == l and b[1][2] == l and b[2][2] == l) or
            (b[0][0] == l and b[1][1] == l and b[2][2] == l) or
            (b[0][2] == l and b[1][1] == l and b[2][0] == l))
 
# Configure text on button while playing with another player
def get_text(i, j, gb, l1, l2):
    global sign
    if board[i][j] == ' ':
        if sign % 2 == 0:
            l1.config(state=DISABLED)
            l2.config(state=ACTIVE)
            board[i][j] = "X"
        else:
            l2.config(state=DISABLED)
            l1.config(state=ACTIVE)
            board[i][j] = "O"
        sign += 1
        button[i][j].config(text=board[i][j])
    if winner(board, "X"):
        gb.destroy()
        box = messagebox.showinfo("Winner", "Player 1 won the match")
    elif winner(board, "O"):
        gb.destroy()
        box = messagebox.showinfo("Winner", "Player 2 won the match")
    elif(isfull()):
        gb.destroy()
        box = messagebox.showinfo("Tie Game", "Tie Game")
 
# Check if the player can push the button or not
 
 
def isfree(i, j):
    return board[i][j] == " "
 
# Check the board is full or not
 
 
def isfull():
    flag = True
    for i in board:
        if(i.count(' ') > 0):
            flag = False
    return flag
 
# Create the GUI of game board for play along with another player
 
 
def gameboard_pl(game_board, l1, l2):
    global button
    button = []
    for i in range(3):
        m = 3+i
        button.append(i)
        button[i] = []
        for j in range(3):
            n = j
            button[i].append(j)
            get_t = partial(get_text, i, j, game_board, l1, l2)
            button[i][j] = Button(
                game_board, bd=5, command=get_t, height=4, width=8)
            button[i][j].grid(row=m, column=n)
    game_board.mainloop()
 
# Decide the next move of system
 
 
def pc():
    possiblemove = []
    for i in range(len(board)):
        for j in range(len(board[i])):
            if board[i][j] == ' ':
                possiblemove.append([i, j])
    move = []
    if possiblemove == []:
        return
    else:
        for let in ['O', 'X']:
            for i in possiblemove:
                boardcopy = deepcopy(board)
                boardcopy[i[0]][i[1]] = let
                if winner(boardcopy, let):
                    return i
        corner = []
        for i in possiblemove:
            if i in [[0, 0], [0, 2], [2, 0], [2, 2]]:
                corner.append(i)
        if len(corner) > 0:
            move = random.randint(0, len(corner)-1)
            return corner[move]
        edge = []
        for i in possiblemove:
            if i in [[0, 1], [1, 0], [1, 2], [2, 1]]:
                edge.append(i)
        if len(edge) > 0:
            move = random.randint(0, len(edge)-1)
            return edge[move]
 
# Configure text on button while playing with system
 
 
def get_text_pc(i, j, gb, l1, l2):
    global sign
    if board[i][j] == ' ':
        if sign % 2 == 0:
            l1.config(state=DISABLED)
            l2.config(state=ACTIVE)
            board[i][j] = "X"
        else:
            button[i][j].config(state=ACTIVE)
            l2.config(state=DISABLED)
            l1.config(state=ACTIVE)
            board[i][j] = "O"
        sign += 1
        button[i][j].config(text=board[i][j])
    x = True
    if winner(board, "X"):
        gb.destroy()
        x = False
        box = messagebox.showinfo("Winner", "Player won the match")
    elif winner(board, "O"):
        gb.destroy()
        x = False
        box = messagebox.showinfo("Winner", "Computer won the match")
    elif(isfull()):
        gb.destroy()
        x = False
        box = messagebox.showinfo("Tie Game", "Tie Game")
    if(x):
        if sign % 2 != 0:
            move = pc()
            button[move[0]][move[1]].config(state=DISABLED)
            get_text_pc(move[0], move[1], gb, l1, l2)
 
# Create the GUI of game board for play along with system
 
 
def gameboard_pc(game_board, l1, l2):
    global button
    button = []
    for i in range(3):
        m = 3+i
        button.append(i)
        button[i] = []
        for j in range(3):
            n = j
            button[i].append(j)
            get_t = partial(get_text_pc, i, j, game_board, l1, l2)
            button[i][j] = Button(
                game_board, bd=5, command=get_t, height=4, width=8)
            button[i][j].grid(row=m, column=n)
    game_board.mainloop()
 
# Initialize the game board to play with system
 
 
def withpc(game_board):
    game_board.destroy()
    game_board = Tk()
    game_board.title("Tic Tac Toe")
    l1 = Button(game_board, text="Player : X", width=10)
    l1.grid(row=1, column=1)
    l2 = Button(game_board, text="Computer : O",
                width=10, state=DISABLED)
 
    l2.grid(row=2, column=1)
    gameboard_pc(game_board, l1, l2)
 
# Initialize the game board to play with another player
 
 
def withplayer(game_board):
    game_board.destroy()
    game_board = Tk()
    game_board.title("Tic Tac Toe")
    l1 = Button(game_board, text="Player 1 : X", width=10)
 
    l1.grid(row=1, column=1)
    l2 = Button(game_board, text="Player 2 : O",
                width=10, state=DISABLED)
 
    l2.grid(row=2, column=1)
    gameboard_pl(game_board, l1, l2)
 
# main function
 
 
def play():
    menu = Tk()
    menu.geometry("250x250")
    menu.title("Tic Tac Toe")
    wpc = partial(withpc, menu)
    wpl = partial(withplayer, menu)
 
    head = Button(menu, text="---Welcome to tic-tac-toe---",
                  activeforeground='red',
                  activebackground="yellow", bg="red",
                  fg="yellow", width=500, font='summer', bd=5)
 
    B1 = Button(menu, text="Single Player", command=wpc,
                activeforeground='red',
                activebackground="yellow", bg="red",
                fg="yellow", width=500, font='summer', bd=5)
 
    B2 = Button(menu, text="Multi Player", command=wpl, activeforeground='red',
                activebackground="yellow", bg="red", fg="yellow",
                width=500, font='summer', bd=5)
 
    B3 = Button(menu, text="Exit", command=menu.quit, activeforeground='red',
                activebackground="yellow", bg="red", fg="yellow",
                width=500, font='summer', bd=5)
    head.pack(side='top')
    B1.pack(side='top')
    B2.pack(side='top')
    B3.pack(side='top')
    menu.mainloop()
 
 
# Call main function
if __name__ == '__main__':
    play()


Output:

Code Explanation:

  1. The code starts by importing all necessary libraries.
  2. Next, the code creates an empty board with three rows and three columns.
  3. The next line of code sets up a variable called sign to decide which player goes first.
  4. Then, the game starts by creating a list of strings that will be used as pieces on the board.
  5. The next few lines are where the actual game is played out: # Creates an empty board global board # Sets up variables for turn order sign = 0 # Plays out each move in turn-based fashion while True: # Checks if there is a winner if (board[sign][0] == “X” or board[sign][1] == “X”) : print(“You win!”)
  6. break elif (board[sign][0] == “O” or board[sign][1] == “O”) : print(“You lose!”)
  7. break else : # If neither player has won yet, then it’s time to play again!
  8. pass.
  9. The code creates an empty board with 3 rows and 3 columns.
  10. The code imports all necessary libraries.
  11. The code creates a function to generate random numbers between 0 and 9.
  12. The code is a function that takes two arguments, b, and l. The first argument is the board state at the beginning of the game (the initial position).
  13. The second argument is the winning condition for this particular game.
  14. The code starts by checking if both players have an equal number of pieces on their respective sides of the board.
  15. If they do, then it checks to see if either player has more than one piece in a row or column on their side of the board.
  16. If so, then it returns true because that player won; otherwise, it returns false because neither player won.
  17. The code is meant to check if the player who won the game was player 1, 2, or 3.
  18. The first part of the code checks if player 1 won the match and also whether or not player 2 won the match.
  19. If both of these conditions are true then it means that player 1 has won the match.
  20. The second part of the code checks if player 2 won the match and also whether or not player 3 won the match.
  21. If both of these conditions are true then it means that player 2 has won the match.
  22. The third part of this code checks if either one of players 1 or 3 have lost their matches and also whether or not either one of players 2 or 3 have lost their matches.
  23. If all three conditions
  24. The code starts by defining a function called get_text.
  25. This function takes two arguments, i and j, which are the coordinates of the button that is being clicked on.
  26. The third argument is gb, which stands for global board.
  27. The fourth argument is l1 and l2, which represent the buttons that are currently active in this game.
  28. Finally, sign is defined as an integer variable to keep track of how many times each player has won so far in this game.
  29. The next line defines a condition where if board[i][j] == ‘ ‘: If there’s no text on the button then it will be set to “X” or “O”.
  30. Then it checks whether sign % 2 == 0: If there’s one space left over after checking for spaces then it will be set to “X” while else it will be set to “O”.
  31. Next up comes another condition where if winner(board,”X”) returns true then gb gets destroyed because X wins!
  32. The code will cause the button to change text depending on which player is winning.
  33. In the case of a tie, the button text will be “XO”.
  34. The code starts with a function called isfree.
  35. This function checks if the player can push the button or not.
  36. If they cannot, then it will show an error message to them and destroy the board.
  37. The next part of code is checking if there are any spaces on the board or not by using a for loop that iterates through all of the cells in the board.
  38. The condition for this loop is flag = True, which means that there are no spaces on the board and so it will continue to check until it finds one.
  39. After that, another function called isfull() checks if there are any more cells left in the game or not by using a for loop as well but this time iterating through all of those cells instead of just one cell like before.
  40. The code is meant to be executed by a user.
  41. It will check if the player can push the button or not.
  42. If they cannot, then it will show an information box that says “Tie Game”.
  43. If they can push the button, then it will show an information box saying “Winner”.
  44. The code starts by creating a global variable button.
  45. Then the code creates an empty list called button for each of the three buttons on the game board.
  46. The next line adds 3 to i and j, which is then used in the following lines to create lists with 3 elements: one for each player’s turn.
  47. The next line gets text from two different places: l1 and l2, where “l” stands for left side of the screen and “r” stands for right side of the screen.
  48. This is done using partial(), which takes four arguments: x-coordinate, y-coordinate, game_board object that will be displayed on this coordinate (in this case it would be game_board), and index number of player who will use this text (in this case it would be 1).
  49. Then these lists are appended together into a single list called get_t.
  50. Finally, Button objects are created with Analyze() function that takes four arguments: x-coordinate, y-coordinate, game_board object that will be displayed on this coordinate (in this case it would be game_board), and index number of player who will use this text (in this case it would be 2).
  51. The code is a function that takes in the game board, l1 and l2 as parameters.
  52. The function then creates an empty list button for each of the 3 numbers from 0 to 2.
  53. The next step is to create a list of buttons that are initialized with i and j values for each of the 3 numbers from 0 to 2.
  54. Then, using a partial function called get_t, it sets up text on each button based on their index number and coordinates of where they should be placed on the game board.
  55. Finally, we assign each button its corresponding color by assigning Button objects with appropriate values for their index number and coordinates.
  56. The code starts by defining the variables needed for the game.
  57. The board variable is a list of lists that stores all the squares on the game board, and each square has two coordinates: row and column.
  58. The button variable is a list of lists that stores all buttons in order from left to right on the screen.
  59. The function pc() randomly chooses one of three moves for player 1 (the computer) to make next, then returns it as an integer value.
  60. If there are no possible moves, then pc() returns 0; if there are more than one possible move, then pc() will return one randomly chosen move from those possibilities.
  61. The get_text_pc function takes four parameters: i, j, gb (game board), l1 (leftmost button), and l2 (rightmost button).
  62. It uses these values to determine which text should be displayed on each button while playing with system using deepcopy().
  63. Then it displays this text using messagebox().
  64. The code is a program that will be used to play the game of tic-tac-toe.
  65. The player will input their moves on the board and then the computer will decide what move it wants to make.
  66. The code starts by creating a global variable called button.
  67. This is an empty list that will hold the buttons for the game board.
  68. The code then creates 3 lists of numbers, one for each row in the game board and one for each column.
  69. These are used to create individual buttons on the screen which represent players playing along with this system.
  70. The next line creates a function called get_text_pc which takes two arguments: i and j, representing player number 1 and 2 respectively, as well as their position on the game board (l1) and length of text they want displayed (l2).
  71. It returns a string containing what should be shown on those two buttons at that location in text form.
  72. Next comes another function called partial which takes three arguments: i, j, l1, l2 – these represent player number 1’s position on the game board (i), player number 2’s position on the game board (j), and where they want to display it from left to right or top to bottom – either 0 or 5 respectively; this is represented by l1 being 0 or 5 depending if you’re displaying it from left-to-right or top-to-bottom respectively; finally l2 represents how many columns wide
  73. The code creates a game board with three rows and three columns.
  74. The first row is created by the code, which assigns the value of 3 to m. The second row is created by the code, which assigns the value of 4 to n. The third row is created by the code, which assigns 5 to bd and command=get_text_pc to each button in that row.
  75. The next line of code in this snippet creates a button for each number from 1-3 (inclusive) and appends it as an element in the third column of buttons (the third column being assigned to n).
  76. This line also sets height=4 and width=8 for each button in that column.
  77. Then, this.
  78. The code starts by initializing the game board to play with a player.
  79. The code then creates two buttons, one for Player 1 and one for Player 2.
  80. These buttons are created as partial functions that call the function withpc or withplayer respectively.
  81. The main function is called when the user clicks on “play” in the menu.
  82. This function calls both of these partial functions and passes them an instance of Tk() which represents the game board object.
  83. The code will create two buttons on the game board.
  84. The first button is for player 1 and the second button is for player 2.
  85. The withplayer function will be called when player 2 clicks the “Player 2” button.
  86. It will destroy the current game board and create a new one with Player 2’s name on it.


Last Updated : 30 Nov, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads