Tic-Tac-Toe GUI in Python Using Tkinter

Tic-Tac-Toe GUI in Python Using Tkinter

Hey folks, This tutorial will help you play and create Tic-Tac-Toe, a very renowned game we have all got our hands on since our childhood. To do this task, we will use some in-built libraries of Python namely which are Tkinter and Random.

Using:

from tkinter import *
from tkinter import messagebox
import random as r

 

Tic-Tac-Toe GUI in Python using Tkinter

We’ll kick off with learning the functions used in this project:

1)The Button function:

def button(frame):          #Function to define a button
    b=Button(frame,padx=1,bg="papaya whip",width=3,text="   ",font=('arial',60,'bold'),relief="sunken",bd=10)
    return b

The above function makes it possible to define a custom button with custom properties.

2) The Change function:

def change_a():             #Function to change the operand for the next player
    global a
    for i in ['O','X']:
        if not(i==a):
            a=i
            break

The change function switches the ‘O’ to ‘X’ and vice-versa for the other player to play his chance.

3)The Reset function:

def reset():                #Resets the game
    global a
    for i in range(3):
        for j in range(3):
                b[i][j]["text"]=" "
                b[i][j]["state"]=NORMAL

The reset function resets the state of all buttons to Normal and clears the text on them.

4)The Check function:

def check():                #Checks for victory or Draw
    for i in range(3):
            if(b[i][0]["text"]==b[i][1]["text"]==b[i][2]["text"]==a or b[0][i]["text"]==b[1][i]["text"]==b[2][i]["text"]==a):
                    messagebox.showinfo("Congrats!!","'"+a+"' has won")
                    reset()
    if(b[0][0]["text"]==b[1][1]["text"]==b[2][2]["text"]==a or b[0][2]["text"]==b[1][1]["text"]==b[2][0]["text"]==a):
        messagebox.showinfo("Congrats!!","'"+a+"' has won")
        reset()   
    elif(b[0][0]["state"]==b[0][1]["state"]==b[0][2]["state"]==b[1][0]["state"]==b[1][1]["state"]==b[1][2]["state"]==b[2][0]["state"]==b[2][1]["state"]==b[2][2]["state"]==DISABLED):
        messagebox.showinfo("Tied!!","The match ended in a draw")
        reset()

The check function checks the board row-wise,column-wise and diagonal-wise for equality and displays the result of the game.

5)The Click function:

def click(row,col):
        b[row][col].config(text=a,state=DISABLED,disabledforeground=colour[a])
        check()
        change_a()
        label.config(text=a+"'s Chance")def click(row,col):
        b[row][col].config(text=a,state=DISABLED,disabledforeground=colour[a])
        check()
        change_a()
        label.config(text=a+"'s Chance")

The above function handles button clicks on the board. This calls the check() function(mentioned as function 4 above) and the change_a() function(mentioned as function 2 above) and sets the state and text of the button clicked.

In our main program we follow the steps given below:

  1. First of all, define the tk window with the Tk() as the root variable.
  2. Then we create the title of the window.
  3. Next, we define a variable to store the playable character(say, ‘O’ and ‘X’).
  4. Then we define a list to store all the buttons and place them in the window.
  5. Finally, we display a label saying the character which has to be played next.
  6. We end by a root.mainloop() function to keep events on the main window active and all other widgets interactive.

Also, in our code, we are using a messagebox class from the Tkinter library to display prompts during the game for the results.

The Complete program looks like so:

from tkinter import *
from tkinter import messagebox
import random as r
def button(frame):          #Function to define a button
    b=Button(frame,padx=1,bg="papaya whip",width=3,text="   ",font=('arial',60,'bold'),relief="sunken",bd=10)
    return b
def change_a():             #Function to change the operand for the next player
    global a
    for i in ['O','X']:
        if not(i==a):
            a=i
            break
def reset():                #Resets the game
    global a
    for i in range(3):
        for j in range(3):
                b[i][j]["text"]=" "
                b[i][j]["state"]=NORMAL
    a=r.choice(['O','X'])
def check():                #Checks for victory or Draw
    for i in range(3):
            if(b[i][0]["text"]==b[i][1]["text"]==b[i][2]["text"]==a or b[0][i]["text"]==b[1][i]["text"]==b[2][i]["text"]==a):
                    messagebox.showinfo("Congrats!!","'"+a+"' has won")
                    reset()
    if(b[0][0]["text"]==b[1][1]["text"]==b[2][2]["text"]==a or b[0][2]["text"]==b[1][1]["text"]==b[2][0]["text"]==a):
        messagebox.showinfo("Congrats!!","'"+a+"' has won")
        reset()   
    elif(b[0][0]["state"]==b[0][1]["state"]==b[0][2]["state"]==b[1][0]["state"]==b[1][1]["state"]==b[1][2]["state"]==b[2][0]["state"]==b[2][1]["state"]==b[2][2]["state"]==DISABLED):
        messagebox.showinfo("Tied!!","The match ended in a draw")
        reset()
def click(row,col):
        b[row][col].config(text=a,state=DISABLED,disabledforeground=colour[a])
        check()
        change_a()
        label.config(text=a+"'s Chance")
###############   Main Program #################
root=Tk()                   #Window defined
root.title("Tic-Tac-Toe")   #Title given
a=r.choice(['O','X'])       #Two operators defined
colour={'O':"deep sky blue",'X':"lawn green"}
b=[[],[],[]]
for i in range(3):
        for j in range(3):
                b[i].append(button(root))
                b[i][j].config(command= lambda row=i,col=j:click(row,col))
                b[i][j].grid(row=i,column=j)
label=Label(text=a+"'s Chance",font=('arial',20,'bold'))
label.grid(row=3,column=0,columnspan=3)
root.mainloop()

To learn more about Random:

random() module in Python

More games like this:

Rock Paper Scissors in Python using GUI Tkinter

Hangman Game with GUI in Python using Tkinter

Color Game with GUI in Python using Tkinter

 

10 responses to “Tic-Tac-Toe GUI in Python Using Tkinter”

  1. Laly Papa says:

    Exception in Tkinter callback
    Traceback (most recent call last):
    File “C:\Users\nagyuborka\Python37\lib\tkinter\__init__.py”, line 1705, in __call__
    return self.func(*args)
    File “C:/Users/nagyuborka/Python_programok/szotar_jatekok_toto_naptar_otlet/Tkinter_tic_tac_toe/Tkinter_t_t_t_00.py”, line 65, in
    b[i][j].config(command=lambda row=i, col=j: click(row, col))
    File “C:/Users/nagyuborka/Python_programok/szotar_jatekok_toto_naptar_otlet/Tkinter_tic_tac_toe/Tkinter_t_t_t_00.py”, line 52, in click
    label.config(text=a+”‘s Chance”)
    TypeError: unsupported operand type(s) for +: ‘int’ and ‘str’

    • Satyam Singh Niranjan says:

      Works perfectly fine for me. I checked it right now. Try to make a new file and copy the code again into it and then run the same program. Maybe its a problem with the file name or something, because the code is tested several times and proved to work efficiently. If you have further queries don’t hesitate to reach me at my email id:
      satyam048niranjan@gmail.com

  2. Nico Mapeso says:

    Hi, sir Good Sir I’m new to Tkinter I just would like to ask what is the process that undergoes in the check function? I’m kind of confused, the other functions are easy to understand but I’m just having a hard time understanding your conditions on the check function. Thank you and good day!

    • Satyam Singh Niranjan says:

      The variables ‘a’ is the current player’s sign(X or O). What the check() function does is to checks the board ‘b’ for 3 matching signs in a row/column/diagonal and also, if the board has been completely used i.e. all buttons are Disabled.
      1) Now the Loop has a condition which checks each Row and Column for 3 matching signs. Thus, the code checks the 1,2 and 3 Column for each Row and 1,2 and 3 Row for each Column.
      2) After the loop, there is another condition which checks the Diagonals for 3 matching signs, and thus the code checks the indices of the diagonals.
      3) The last part of the function is another condition which checks if the state of all buttons is Disabled. This is done to ensure if the game is tied.

      If any of the above conditions are satisfied a prompt is displayed to declare the result of the game.

  3. Amogh S says:

    Hello sir you never said why we need this code
    for i in range(3):
    for j in range(3):
    b[i].append(button(root))
    b[i][j].config(command= lambda row=i,col=j:click(row,col))
    b[i][j].grid(row=i,column=j)
    please guide me I want to know whats this code used for.

    • Satyam Singh Niranjan says:

      This code sets up the buttons in the application. The variable b contains 3 empty rows. So, We will use this as a 3×3 matrix. Now in the nested for-loop:
      1) The first line i.e. b[i].append(button(root)) makes sure that a button is added every time the inner loop runs. Where b[i] is the 1st,2nd or 3rd row. So this line adds 3 buttons in each row
      2) The second line connects the on-clicked command to the button, which in this case is a lambda(anonymous) function.
      3) The third line lays the current button, using the grid method, in the root window.

  4. Snehal Singh says:

    can you provide the variable description table?

    • Satyam Singh Niranjan says:

      a–>selects either ‘O’ or ‘X’ randomly. Later it’s used to get the current player’s symbol. This is a global variable and is used by the functions(just a call by reference alternative).
      colour–> this is a dictionary which is used to get the colour for a symbol.
      b–> this is a list with 3 empty lists which serve as rows for the intended 3×3 matrix. This is a global variable and is used by the functions(just a call by reference alternative).
      r–> is used as an alias for the imported random class

      all others are function variable.

      • Abu Raihan says:

        from tkinter import *
        from tkinter import messagebox
        import random as r
        def button(frame): #Function to define a button
        b=Button(frame,padx=1,bg=”papaya whip”,width=3,text=” “,font=(‘arial’,60,’bold’),relief=”sunken”,bd=10)
        return b
        def change_a(): #Function to change the operand for the next player
        global a
        for i in [‘O’,’X’]:
        if not(i==a):
        a=i
        break
        def reset(): #Resets the game
        global a
        for i in range(3):
        for j in range(3):
        b[i][j][“text”]=” ”
        b[i][j][“state”]=NORMAL
        a=r.choice([‘O’,’X’])
        def check(): #Checks for victory or Draw
        for i in range(3):
        if(b[i][0][“text”]==b[i][1][“text”]==b[i][2][“text”]==a or b[0][i][“text”]==b[1][i][“text”]==b[2][i][“text”]==a):
        messagebox.showinfo(“Congrats!!”,”‘”+a+”‘ has won”)
        reset()
        if(b[0][0][“text”]==b[1][1][“text”]==b[2][2][“text”]==a or b[0][2][“text”]==b[1][1][“text”]==b[2][0][“text”]==a):
        messagebox.showinfo(“Congrats!!”,”‘”+a+”‘ has won”)
        reset()
        elif(b[0][0][“state”]==b[0][1][“state”]==b[0][2][“state”]==b[1][0][“state”]==b[1][1][“state”]==b[1][2][“state”]==b[2][0][“state”]==b[2][1][“state”]==b[2][2][“state”]==DISABLED):
        messagebox.showinfo(“Tied!!”,”The match ended in a draw”)
        reset()
        def click(row,col):
        b[row][col].config(text=a,state=DISABLED,disabledforeground=colour[a])
        check()
        change_a()
        label.config(text=a+”‘s Chance”)
        ############### Main Program #################
        root=Tk() #Window defined
        root.title(“Tic-Tac-Toe”) #Title given
        a=r.choice([‘O’,’X’]) #Two operators defined
        colour={‘O’:”deep sky blue”,’X’:”lawn green”}
        b=[[],[],[]]
        for i in range(3):
        for j in range(3):
        b[i].append(button(root))
        b[i][j].config(command= lambda row=i,col=j:click(row,col))
        b[i][j].grid(row=i,column=j)
        label=Label(text=a+”‘s Chance”,font=(‘arial’,20,’bold’))
        label.grid(row=3,column=0,columnspan=3)
        root.mainloop()

  5. Gaurav Jain says:

    Do you have a youtube video where you explain in detail ?

Leave a Reply

Your email address will not be published. Required fields are marked *