Python Tic Tac Toe – Develop a Game in Python

It’s no doubt, you must have played Tic Tac Toe in your school days and every one of us loves to play the game. You will be surprised to know that the game of Tic Tac Toe is known to exist since ancient Egypt times.

With this Python project by TechVidvan, we are going to build an interactive game of Tic Tac Toe where we’ll learn new things along the way.

Keeping you updated with latest technology trends, Join TechVidvan on Telegram

What is Tic Tac Toe?

Tic Tac Toe is one of the most played games and is the best time killer game that you can play anywhere with just a pen and paper. If you don’t know how to play this game don’t worry let us first understand that.

The game is played by two individuals. First, we draw a board with a 3×3 square grid. The first player chooses ‘X’ and draws it on any of the square grid, then it’s the chance of the second player to draw ‘O’ on the available spaces. Like this, the players draw ‘X’ and ‘O’ alternatively on the empty spaces until a player succeeds in drawing 3 consecutive marks either in the horizontal, vertical or diagonal way. Then the player wins the game otherwise the game draws when all spots are filled.

tic tac toe - project in python

Python Tic Tac Toe – Project Details

The interesting Python project will be build using the pygame library. We will be explaining all the pygame object methods that are used in this project. Pygame is a great library that will allow us to create the window and draw images and shapes on the window. This way we will capture mouse coordinates and identify the block where we need to mark ‘X’ or ‘O’. Then we will check if the user wins the game or not.

Download Tic Tac Toe Project code

Please download the full source code of tic tac toe project: Tic Tac Toe Python Project

Prerequisites

To implement this game, we will use the basic concepts of Python and Pygame which is a Python library for building cross-platform games. It contains the modules needed for computer graphics and sound libraries. To install the library, you can use pip installer from the command line:

pip install pygame

Steps to Build a Python Tic Tac Toe Game

First, let’s check the steps to build Tic Tac Toe program in Python:

  • Create the display window for our game.
  • Draw the grid on the canvas where we will play Tic Tac Toe.
  • Draw the status bar below the canvas to show which player’s turn is it and who wins the game.
  • When someone wins the game or the game is a draw then we reset the game.

We need to run our game inside an infinite loop. It will continuously look for events and when a user presses the mouse button on the grid we will first get the X and Y coordinates of the mouse. Then we will check which square the user has clicked. Then we will draw the appropriate ‘X’ or ‘O’ image on the canvas. So that is basically what we will do in this Python project idea.

1. Initializing game components

So let’s start by importing the pygame library and the time library because we will use the time.sleep() method to pause game at certain positions. Then we initialize all the global variables that we will use in our Tic Tac Toe game.

import pygame as pg,sys
from pygame.locals import *
import time


#initialize global variables
XO = 'x'
winner = None
draw = False
width = 400
height = 400
white = (255, 255, 255)
line_color = (10,10,10)

#TicTacToe 3x3 board
TTT = [[None]*3,[None]*3,[None]*3]

Here, the TTT is the main 3×3 Tic Tac Toe board and at first, it will have 9 None values. The height and width of the canvas where we will play the game is 400×400.

2. Initializing Pygame window

We use the pygame to create a new window where we’ll play our Tic Tac Toe game. So we initialize the pygame with pg.init() method and the window display is set with a width of 400 and a height of 500. We have reserved 100-pixel space for displaying the status of the game.

The pg.display.set_mode() initializes the display and we reference it with the screen variable. This screen variable will be used whenever we want to draw something on the display.

The pg.display.set_caption method is used to set a name that will appear at the top of the display window.

#initializing pygame window
pg.init()
fps = 30
CLOCK = pg.time.Clock()
screen = pg.display.set_mode((width, height+100),0,32)
pg.display.set_caption("Tic Tac Toe")

3. Load and transform images

The Python project uses many images like the opening image that will display when the game starts or resets. The X and O images that we will draw when the user clicks on the grid. We load all the images and resize them so that they will fit easily in our window.

#loading the images
opening = pg.image.load('tic tac opening.png')
x_img = pg.image.load('x.png')
o_img = pg.image.load('o.png')

#resizing images
x_img = pg.transform.scale(x_img, (80,80))
o_img = pg.transform.scale(o_img, (80,80))
opening = pg.transform.scale(opening, (width, height+100))

4. Define the functions

Now we create a function that will start the game. We will also use this function when we want to restart the game. In pygame, the blit() function is used on the surface to draw an image on top of another image.

So we draw the opening image and after drawing, we always need to update the display with pg.display.update(). When the opening image is drawn, we wait for 1 second using time.sleep(1) and fill the screen with white colour.

Next, we draw 2 vertical and horizontal lines on the white background to make the 3×3 grid. In the end, we call the draw_status() function

def game_opening():
    screen.blit(opening,(0,0))
    pg.display.update()
    time.sleep(1)
    screen.fill(white)

    # Drawing vertical lines
    pg.draw.line(screen,line_color,(width/3,0),(width/3, height),7)
    pg.draw.line(screen,line_color,(width/3*2,0),(width/3*2, height),7)
    # Drawing horizontal lines
    pg.draw.line(screen,line_color,(0,height/3),(width, height/3),7)
    pg.draw.line(screen,line_color,(0,height/3*2),(width, height/3*2),7)
    draw_status()

The draw_status() function draws a black rectangle where we update the status of the game showing which player’s turn is it and whether the game ends or draws.

def draw_status():
    global draw

    if winner is None:
        message = XO.upper() + "'s Turn"
    else:
        message = winner.upper() + " won!"
    if draw:
        message = 'Game Draw!'

    font = pg.font.Font(None, 30)
    text = font.render(message, 1, (255, 255, 255))

    # copy the rendered message onto the board
    screen.fill ((0, 0, 0), (0, 400, 500, 100))
    text_rect = text.get_rect(center=(width/2, 500-50))
    screen.blit(text, text_rect)
    pg.display.update()

The check_win() function checks the Tic Tac Toe board to see all the marks of ‘X’ and ‘O’. It calculates whether a player has won the game or not. They can either win when the player has marked 3 consecutive marks in a row, column or diagonally. This function is called every time when we draw a mark ‘X’ or ‘O’ on the board.

def check_win():
    global TTT, winner,draw

    # check for winning rows
    for row in range (0,3):
        if ((TTT [row][0] == TTT[row][1] == TTT[row][2]) and(TTT [row][0] is not None)):
            # this row won
            winner = TTT[row][0]
            pg.draw.line(screen, (250,0,0), (0, (row + 1)*height/3 -height/6),\
                              (width, (row + 1)*height/3 - height/6 ), 4)
            break

    # check for winning columns
    for col in range (0, 3):
        if (TTT[0][col] == TTT[1][col] == TTT[2][col]) and (TTT[0][col] is not None):
            # this column won
            winner = TTT[0][col]
            #draw winning line
            pg.draw.line (screen, (250,0,0),((col + 1)* width/3 - width/6, 0),\
                          ((col + 1)* width/3 - width/6, height), 4)
            break

    # check for diagonal winners
    if (TTT[0][0] == TTT[1][1] == TTT[2][2]) and (TTT[0][0] is not None):
        # game won diagonally left to right
        winner = TTT[0][0]
        pg.draw.line (screen, (250,70,70), (50, 50), (350, 350), 4)

    if (TTT[0][2] == TTT[1][1] == TTT[2][0]) and (TTT[0][2] is not None):
        # game won diagonally right to left
        winner = TTT[0][2]
        pg.draw.line (screen, (250,70,70), (350, 50), (50, 350), 4)

    if(all([all(row) for row in TTT]) and winner is None ):
        draw = True
    draw_status()

The drawXO(row, col) function takes the row and column where the mouse is clicked and then it draws the ‘X’ or ‘O’ mark. We calculate the x and y coordinates of the starting point from where we’ll draw the png image of the mark.

def drawXO(row,col):
    global TTT,XO
    if row==1:
        posx = 30
    if row==2:
        posx = width/3 + 30
    if row==3:
        posx = width/3*2 + 30

    if col==1:
        posy = 30
    if col==2:
        posy = height/3 + 30
    if col==3:
        posy = height/3*2 + 30
    TTT[row-1][col-1] = XO
    if(XO == 'x'):
        screen.blit(x_img,(posy,posx))
        XO= 'o'
    else:
        screen.blit(o_img,(posy,posx))
        XO= 'x'
    pg.display.update()
    #print(posx,posy)
    #print(TTT)

The userClick() function is triggered every time the user presses the mouse button.

When the user clicks the mouse, we first take the x and y coordinates of where the mouse is clicked on the display window and then if that place is not occupied we draw the ‘XO’ on the canvas. We also check if the player wins or not after drawing ‘XO’ on the board.

def userClick():
    #get coordinates of mouse click
    x,y = pg.mouse.get_pos()

    #get column of mouse click (1-3)
    if(x<width/3):
        col = 1
    elif (x<width/3*2):
        col = 2
    elif(x<width):
        col = 3
    else:
        col = None

    #get row of mouse click (1-3)
    if(y<height/3):
        row = 1
    elif (y<height/3*2):
        row = 2
    elif(y<height):
        row = 3
    else:
        row = None
    #print(row,col)

    if(row and col and TTT[row-1][col-1] is None):
        global XO

        #draw the x or o on screen
        drawXO(row,col)
        check_win()

The last function is the reset_game(). This will restart the game and we also reset all the variables to the beginning of the game.

def reset_game():
    global TTT, winner,XO, draw
    time.sleep(3)
    XO = 'x'
    draw = False
    game_opening()
    winner=None
    TTT = [[None]*3,[None]*3,[None]*3]

5. Run the tic tac toe game forever

To start the game, we will call the game_opening() function. Then, we run an infinite loop and continuously check for any event made by the user. If the user presses mouse button, the MOUSEBUTTONDOWN event will be captured and then we will trigger the userClick() function. Then if the user wins or the game draws, we reset the game by calling reset_game() function. We update the display in each iteration and we have set the frames per second to 30.

game_opening()

# run the game loop forever
while(True):
    for event in pg.event.get():
        if event.type == QUIT:
            pg.quit()
            sys.exit()
        elif event.type is MOUSEBUTTONDOWN:
            # the user clicked; place an X or O
            userClick()
            if(winner or draw):
                reset_game()

    pg.display.update()
    CLOCK.tick(fps)

Hooray! The game is complete and ready to play. Save the source code with the tictactoe.py file name and run the file.

Output:

tic tac toe starting in python project with source code

tic tac toe game in python project idea

Summary

With this project in Python, we have successfully made the Tic Tac Toe game. We used the popular pygame library for rendering graphics on a display window. We learned how to capture events from the keyboard or mouse and trigger a function when the mouse button is pressed. This way we can calculate mouse position, draw X or O on the display and check if the player wins the game or not. I hope you enjoyed building the game.

Now, it’s time to work on another interesting project – Python Project on Typing Speed Test

Any difficulty while working on the Python project with source code? Do share in the comment section. Our TechVidvan experts are always there to assist you.

42 Responses

  1. Sushila says:

    nice project with good explanation.But,as a beginner i am getting the following error:
    error: Couldn’t open tic tac opening.png, in
    line 32, in opening = pg.image.load(‘tic tac opening.png’)
    I am beginner with python.Please, help me to solve this error.
    Thanking You.

    • TechVidvan Team says:

      Hi Sushila,

      The pg.image.load() function is used to loads an image. So to load the image it needs full path of the image. You are getting this error because the program couldn’t find the ‘tic tac opening.png’ image in your system. Make sure the image exists in same folder and path is correct.
      If the ‘tic tac opening.png’ image and the code file are in the same folder then we can directly use the name of the image with the proper extension. Otherwise, we will have to provide the full path of the image. For example “D:/projects/TicTacToe/tic tac opening.png”

    • Kothakota Viswanadh says:

      delete the spaces in the ” tic tac opening.png” and try

      • Allen says:

        I am getting this error, how would I resolve this? I need to create a folder and put the code in it? I am using Pycharm, thank you for your help!

        Traceback (most recent call last):
        File “C:\Users\selva\PycharmProjects\pythonProject1\Project 3.py”, line 22, in
        opening = pg.image.load(‘tic tac opening.png’)
        FileNotFoundError: No such file or directory.

  2. vikas says:

    I Use this Project
    This is awsome project for begginers

  3. qwerty says:

    unable to see output

  4. Vk says:

    Very good project.. loved it

    I found an logical error when I run it. When I click on row 1 col 2 it would draw xo in row 2 col 1..

    I made following few changed in drawxo function

    When we test for ‘row’; we need to set the posy variable(not posx)
    Similarly when we test for ‘col’ we set posx (not posy)

    After this it worked fine.

    Hope this was helpful if anyone is finding similar run time error.

    Do keep posting these simple projects to get hands on learning for beginners..
    Thank you

  5. Aniruddha says:

    I copy and paste all the code in Jupyter however its throwing below error

    File “”, line 106
    pg.display.update()
    ^
    IndentationError: unindent does not match any outer indentation level

    • Tech Vidvan says:

      The indentation of this statement should match with the else statement, for more details please check tictactoe.py after downloading.

  6. Ashvini says:

    i got this error
    error: Couldn’t open tic tac opening.png

  7. neesham says:

    bro error in drawxo ,indent error in near ttt

  8. Sai Kiran says:

    I really appreciate the project code and the way of explanation, keep this job going on .
    Thank you very much for teaching 🙂

  9. adnan says:

    Excuse me :
    An error message appears with the following code
    >>>screen.blit(opening,(0,0))

    thanks…

  10. Toyosi says:

    i got an error importing pygame

    Traceback (most recent call last):
    File “/home/toyosi/projects/tic_tac_toe/template/tictactoe.py”, line 1, in
    import pygame as pg,sys
    File “/home/toyosi/projects/tic_tac_toe/tenv/lib/python3.8/site-packages/pygame/__init__.py”, line 120, in
    from pygame.base import *
    ImportError: /home/toyosi/projects/tic_tac_toe/tenv/lib/python3.8/site-packages/pygame/base.so: undefined symbol: PyCObject_Type

  11. RamGopal says:

    Not displaying output.

  12. Priyanka Pattanshetti says:

    My program is running fine but i am unable to see the output window. It just appears and goes away, what must be the problem? Can you please help me with this issue

  13. Thi Le says:

    My program displayed the window with the grid but nothing happens when I clicked on it. I tried this with your code in the package too and the same thing happened. I assume there is a bug in userClick(). Do you mind helping me with this? Thank you

    • Tech Vidvan says:

      Please download the code and then try running tictactoe.py. If you are still facing any problem then try reinstalling pygame

  14. ARSHAD UMAR KHAN says:

    i am getting an error and game is not working well image of x and o are stacking once all the boxes get filled and winning function is not working..

    C:/Users/ASUS/PycharmProjects/untitled/i can code.py:56: DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
    text_rect = text.get_rect(center=(width / 2, 500 – 50))

    • Tech Vidvan says:

      Please replace this line “text_rect = text.get_rect(center=(width / 2, 500 – 50))” with “text_rect = text.get_rect(center=(width // 2, 500 – 50))”

  15. Aniket says:

    Its ab awesome tutorial , but my code is getting run without any error but that popup window flash on screen and disappear please help me to solve this issue

  16. aissa says:

    nice project i get some error on line 19, 20, 21, in
    def drawXO():

  17. James Nguyen says:

    It says Error Unexpected Indent

    It says line 2 ( pip install pygame)
    Is there a way you guys cn

  18. Kevin Nguyen says:

    It dont draw X or O for me, please help

  19. Zaid says:

    Hi there,
    A very well guided project indeed. However, I’m facing the issue where the game loads, and then the image of ‘X’ and ‘O’ does not appear on the click of the mouse.
    Also, it gives the following warning that I do not understand.

    libpng warning: iCCP: known incorrect sRGB profile
    libpng warning: iCCP: known incorrect sRGB profile

    • Andrew says:

      I’ve just got the same issue. I managed to fix it by changing the line “elif event.type is MOUSEBUTTONDOWN:” to “elif event.type == MOUSEBUTTONDOWN:”, so swapping the “is” for “==”. It then worked for me.

      I also got the same warnings. There’s some issue with the X.png and O.png files. I made my own and it got rid of the warnings, but you can run the game without changing them.

  20. Danny says:

    Can u make a video of this step by step so that we can do it . It’s little bit confusing.

Leave a Reply

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.