Making of Tic-Tac-Toe game using Python TKinter

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

If you want to try something interesting apart from your daily work, then you are at the right place. In this blog, we are going to make a Tic-Tac-Toe game using Python TKinter. I will also be telling some basic features of TKinter. So let's get started...

Python comes built-in with TKinter for GUI. In tkinter, everything is a widget, i.e. there is buttton widget, text widget etc. At first, you should import tkinter. Then the first widget you create will be the root widget; this will create a window. To allow this window to be on the screen forever, you have to run an infinite loop. In tkinter, this happens with the mainloop() funtion at the end. Hence, the first few lines of code which has to be there are,

from tkinter import *
root = Tk()
root.title('Tic-Tac-Toe')
root.mainloop()

Now, since we have to display few messages, we should use messagebox widget. MessageBox Widget is used to display the message boxes in the python applications. This module is used to display a message using a number of functions. To use it, we have to import messagebox.

from tkinter import messagebox

Now, we have to create button. For this game, we have to create total 9 buttons.

b1 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b1))
b2 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b2))
b3 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b3))

b4 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b4))
b5 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b5))
b6 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b6))

b7 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b7))
b8 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b8))
b9 = Button(root, text=" ", font=("Helvetica", 20), height=3, width=6, bg="white", command=lambda: b_click(b9))

Now let's arrange these buttons in a grid,

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

b4.grid(row=1, column=0)
b5.grid(row=1, column=1)
b6.grid(row=1, column=2)

b7.grid(row=2, column=0)
b8.grid(row=2, column=1)
b9.grid(row=2, column=2)

Let's assign two variables at the top, 'clicked' and 'count'. Initialise 'clicked' to 'True' and 'count' to '0'. According to our logic, if 'clicked' is True, that means 'X' is clicking and if it is 'False' that means it's time for 'O' to click, while 'count' is to keep track of the total number of turns i.e. 9.

clicked = True
count = 0

Define a button clicked function to keep track of buttons clicked and the winner. So first if somebody clicks on a button, we need to check if that button was blank or already clicked. For this, we'll use if-elif-else statements. And every time somebody clicks, we have to check if that person won through checkifwon() function. We'll talk about checkifwon() function in some time.

if b["text"] == " " and clicked == True:
        b["text"] = "X"
        clicked = False
        count += 1
        checkifwon()

The above snippet means that if, text on button is nothing i.e. if button is empty and 'clicked' is true i.e. if 'X' is clicking, then write 'X' on the button clicked. And 'clicked' will turn false i.e. now, it's time for 'O' to click. Whenever somebody tries to make a move, 'count' will increment by 1.

Now, it's time for 'O''s turn.

elif b["text"] == " " and clicked == False:
        b["text"] = "O"
        clicked = True
        count += 1
        checkifwon()

The above snippet means that if, text on button is nothing i.e. if button is empty and 'clicked' is false i.e. if 'O' is clicking, then write 'O' on the button clicked. And 'clicked' will turn true i.e. now, it's time for 'X' to click. While 'count' will increment by 1.

And at last, if all the buttons are clicked, or if the person is trying to click on an already clicked button, then we have to tell them it's wrong. We will display a message through messagebox widget.

else:
        messagebox.showerror("Tic Tac Toe", "That box has already been selected.\nPick another box...")

Now, let's create a function checkifwon() to check if someone won or not. Make a global variable 'winner' and initialise it to false. If somebody wins, then 'winner' will change to true and the game stops. To win this game, you have to get the same thing horizontally , vertically or diagonally , as shown in the figure.

If the pattern matches, we'll change the colour of button to green and display a message through messagebox widget. There will be total 8 chances of 'X' to win and 8 chances of 'O' to win. Hence, total 16 if-elif statements. I'll show here 1 if statement, and try writing other elif statements for 'X' and 'O' by yourself. If you face some problem, you can check the code through my github.

if b1["text"] == "X" and b2["text"] == "X" and b3["text"] == "X":
        b1.config(highlightbackground="green")
        b2.config(highlightbackground="green")
        b3.config(highlightbackground="green")

        winner = True
        messagebox.showinfo("Tic Tac Toe", "Congratulations, X wins!!")
        disable_all_buttons()

Now let's check the disable_all_buttons() buttons. So, when the game ends, player cannot play any other move, hence we have to disable all the buttons. We can do this by the following easy code snippet.

def disable_all_buttons():
    b1.config(state=DISABLED)
    b2.config(state=DISABLED)
    b3.config(state=DISABLED)
    b4.config(state=DISABLED)
    b5.config(state=DISABLED)
    b6.config(state=DISABLED)
    b7.config(state=DISABLED)
    b8.config(state=DISABLED)
    b9.config(state=DISABLED)

So, after the end of game, players should reset the game. For this, we can add a small menu option on the top. We can enable this feature through some simple lines of code in tkinter.

my_menu = Menu(root)
root.config(menu=my_menu)

options_menu = Menu(my_menu)
my_menu.add_cascade(label="Options", menu=options_menu)
options_menu.add_command(label="Reset Game", command=reset)

At last, to check if it's a tie and no one wins, you can add an if statement under checkifwon() function.

if count == 9 and winner == False:
        messagebox.showinfo("Tic Tac Toe", "It's a tie!!\nNo one wins!\n Reset the game...")

You can check the whole code on my github link.

Thank you for showing interest:)