How To Make Tic Tac Toe In Python

In this tutorial, I want to discuss a step-by-step guide on How To Make Tic Tac Toe In Python, which you can learn with the help of source codes.

What is Tic Tac Toe In Python?

Tic Tac Toe Python is one of the most popular games, and you can play it anywhere with just a pen and paper to pass the time. Don’t worry if you don’t know how to play this game. Let’s figure it out first.

Only two people can play the game. First, we make a 33 grid on a piece of paper. The first player chooses “X” and draws it anywhere on the square grid.

The second player then gets to choose “O” and draw it anywhere on the square grid. So, the players switch between drawing an “X” and an “O” on the empty spaces until one of them draws three marks in a row, either horizontally, vertically, or diagonally.

If that happens, the player wins the game. If not, the game ends when all the spaces are taken.

How To Make Tic Tac Toe In Python With Source Code?

Here’s a step-by-step process on How To Make A Tic Tac Toe Game With Source Codes.

Step 1: Install Libraries

First, Install all the required libraries.

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

Step 2: Create A Form

Next, we will create a form to display.

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

#initialize global variables
width = 400
height = 400
white = (255, 255, 255)
line_color = (10,10,10)

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

#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 By Python For Free")



# run the game loop forever
while(True):

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


Step 3: Create Game Opening

Next, we will create a game-opening to display the image of our game.

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

#initialize global variables
width = 400
height = 400
white = (255, 255, 255)
line_color = (10,10,10)

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

#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 By Python For Free")

#loading the images
opening = pg.image.load('display.png')


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


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


game_opening()




Step 4: Draw Line

Next, we will draw a line before gameplay.

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]

#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 By Python For Free")

#loading the images
opening = pg.image.load('display.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))


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)

game_opening()

# run the game loop forever
while(True):
    for event in pg.event.get():
     pg.display.update()
     CLOCK.tick(fps)

Step 5: Add Functions

Now, we will add functions to every row and column that will display (X, O).

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]

#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 By Python For Free")

#loading the images
opening = pg.image.load('display.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))


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)
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)



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)



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]


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 == MOUSEBUTTONDOWN:
            # the user clicked; place an X or O
            userClick()


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

Step 6: Add Functions To Check Which Is The Winner

Lastly, we will add functions to check which of the two players got to win in the 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]

#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 By Python For Free")

#loading the images
opening = pg.image.load('display.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))


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()


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 ((135, 206, 235), (0, 400, 500, 100))
    text_rect = text.get_rect(center=(width/2, 500-50))
    screen.blit(text, text_rect)
    pg.display.update()

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()


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)



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()



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]


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 == MOUSEBUTTONDOWN:
            # the user clicked; place an X or O
            userClick()
            if(winner or draw):
                reset_game()

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


Download Full Source Code!

Visit this page to download the Full Source Code of the Tic Tac Toe Game Using Tkinter for Free!

Frequently Asked Questions

How do you play this Python Tic Tac Toe game?

Two players take turns placing X and O on a 3×3 grid. Click any empty cell to place your mark (the current player’s symbol toggles after each move). The first player to align 3 marks horizontally, vertically, or diagonally wins. If all 9 cells fill without a winner, the game is a draw. The simple AI version included uses the minimax algorithm so the computer never loses, useful for demonstrating game-tree search algorithms in your defense.

What Python version do I need to run this game?

Python 3.8 or newer works. We recommend Python 3.11 or 3.12 because Pygame ships pre-built wheels for those versions (faster pip install, no compilation errors). Python 3.13 may need a slightly older Pygame release because some wheels lag the latest CPython. Verify your version with python –version on Windows or python3 –version on Mac/Linux.

How do I install Pygame for this project?

Run pip install pygame in your terminal (Windows: open Command Prompt, Mac/Linux: open Terminal). On Windows, if pip is not recognized, try python -m pip install pygame instead. On Linux, you may need sudo apt install python3-pygame if pip fails. Verify with python -c “import pygame; print(pygame.version.ver)”.

Can I use this Python game as my BSIT capstone project?

On its own, no, most Philippine BSIT panels expect a full system with users, data, reports, and a real-world problem. A single Pygame game is too narrow for capstone scope. BUT, you can use this game as ONE module inside a larger capstone (e.g. a gamified learning system, a math practice tool for elementary students with this game as the reward layer, or an arcade-style POS for an internet cafe). Pair the game with a Django backend, a database, and analytics for a defensible capstone.

Can I package this game as a standalone .exe to distribute?

Yes, use PyInstaller. Run pip install pyinstaller then pyinstaller –onefile –windowed your_game.py from the project folder. PyInstaller bundles Python and Pygame into a single .exe (Windows) or .app (Mac) that runs without Python installed on the target machine. Include asset files (images, sounds) with –add-data “assets;assets”. Output goes to the dist/ folder.

Where do I get help if the game does not run?

Check the top 3 most common failures: (1) Pygame is not installed correctly, re-run pip install pygame. (2) The game cannot find an asset file (image/sound), make sure you run python from the project folder so relative paths resolve. (3) Wrong Python version, this code expects Python 3.8+; older Python 2.x or 3.6 raises syntax errors. If you still hit a wall, drop a comment on this article with the exact error message, our team monitors comments daily.

Conclusion

We have completely discussed a step-by-step guide on How To Make Tic Tac Toe In Python, which we learned with the help of source codes. I hope this Python Game Tutorial will help you a lot!

Glay Eliver

Programmer & Technical Writer at PIES IT Solution

Glay Eliver is a programmer and writer at PIES IT Solution, author of over 600 tutorials at itsourcecode.com. Specializes in JavaScript tutorials, Microsoft Office how-tos (Excel, Word, PowerPoint), and Python error debugging covering ImportError, TypeError, AttributeError, ModuleNotFoundError, and JavaScript ReferenceError. Authored several of the site’s highest-traffic Excel and MS Office reference articles.

Expertise: JavaScript · MS Excel · MS Word · MS PowerPoint · Python · Python ImportError · Python TypeError · Python AttributeError · ModuleNotFoundError · JavaScript ReferenceError · Pygame  · View all posts by Glay Eliver →

Leave a Comment