Tic Tac Toe Game In Python


Let's create a Tic Tac Toe game in Python. First, we will create a simple tic tac toe game that runs on CLI (Command Line Interface) to play the game, and then in the second section of the article, we will create tic tac toe using pygame library.

    Table Of Contents

  1. Game Introduction
  2. Simple Tic Tac Toe Game (CLI)
    1. Define variables
    2. Print board
    3. Create Function To Start Game
    4. Create Function For Player's Turn
    5. Check If Game Is Over
  3. Complete Code (CLI)
  4. Tic Tac Toe Using Pygame
    1. Pygame Introduction
    2. Import Pygame Library
    3. Defining Variables To Be Used
    4. Pygame Setup
    5. Main Game Loop
    6. Set Up Images
    7. Game Intro Function
    8. Draw Lines To Create Board
    9. Draw Bottom Bar To Show Game Status
    10. Start Game Function
    11. Player's Turn Function
    12. Check Winner If Any
    13. Close Game
  5. Complete Code (Pygame)
  6. Conclusion

Game Introduction (tic tac toe)

Tic Tac Toe is a two-player game played on a 3x3 board. On the board, there are 9 square boxes. Each player has a mark, either X or O. They mark the boxes in blank spaces when it's their turn.

Tic Tac Toe Game Board
Tic Tac Toe Game Board

The goal of the game is to get three of your marks in a row (up, down, across, or diagonally) to win. The first player who has three marks in a row wins.

Tic Tac Toe Game Win Combination
Tic Tac Toe Game Win Combination

Any player who first gets any of the combinations shown above will win the game.

This is enough with game rules. Now let's create a simple tic tac toe game that you can play using the command-line interface (CLI).


Simple Tic Tac Toe Game

First, we will create a tic tac toe game that runs on CLI.

On the command line, you will see a board with 9 boxes made up of pipes (|) and underscores (_) and can choose any of the boxes by inputting the number of the box. For example, if you want to choose box number 3, you will input 3.

Let's start creating the game step by step. We will discuss and write the code in exact flow for you to create and understand. We will also discuss some of the bugs that you may accidentally create.


I. Define necessary variables & take inputs

We will start by asking players to choose their mark either X or O.

Also, create a list of size 9 to store the position of marks of both players in the game.

# create necessary variables

player1 = input("Player 1, choose X or O: ")
if player1 == "x":
    player2 = "O"
    player1 = "X"
else:
    player2 = "X"
    player1 = "O"

print(f"Player 1 is {player1} and Player 2 is {player2}")

# board array
board = [" " for x in range(9)]

According to the above code, if the player inputs x, then player 2 gets the O mark and player 1 gets the X mark. If the player inputs anything else then player 1 gets O mark and player 2 gets X mark.

To create a list of size 9, filled with " " (space) characters, we are using list comprehension.


The board is created using pipes (|) and underscores (_) in the terminal. So to do this you should have a good understanding of printing in python.

Keep the size of each box equal to 5 characters length so that when you print the board, player marks will be aligned in the center of each box. This will improve the look of the board.

# print board
def printBoard():
    print("     |     |     ")
    print("  " + board[0] + "  |  " + board[1] + "  |  " + board[2] + "  ")
    print("_____|_____|_____")
    print("     |     |     ")
    print("  " + board[3] + "  |  " + board[4] + "  |  " + board[5] + "  ")
    print("_____|_____|_____")
    print("     |     |     ")
    print("  " + board[6] + "  |  " + board[7] + "  |  " + board[8] + "  ")
    print("     |     |     ")

We will need to print a new board after each move. So we will create a function to print the board.


III. Create Function To Start Game

To start the game it's a good idea to welcome the player. So print a nice welcome message.

Then we will call the printBoard() function to print the board.

Then we will start the player's turn with player1.

# start game
def startGame():
    print("Welcome to Tic Tac Toe!")
    printBoard()
    playerTurn("1")

We are going to create the playerTurn() function to handle the turn of each player.


IV. Create Function For Player's Turn

The function playerTurn() handles a lot of things within this game.

The playerTurn() function takes 1 parameter, turn. This parameter is used to determine which player is playing. If the turn is 1, then it's player 1's turn. If the turn is 2, then it's player 2's turn.

  1. First, the function print whose turn it is and then takes input from the player for the position of the mark.
  2. Then we will keep asking the player to input the position of the mark until the player inputs a valid position.
  3. Then we will convert the position to an integer and determine the symbol of the mark.
  4. If the position is empty then we will assign the mark to the position, print the board, and check if the game is over or not.
  5. If it is over then return, otherwise change the turn to the other player, and continue the game.
# player's turn
def playerTurn(turn):
    print(f"Player {turn}, it's your turn.")
    position = input("Choose a position from 1-9: ")
    # keep asking for input until valid position is chosen
    while position not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
        position = input("Invalid position. Choose a position from 1-9: ")

    # convert position to int
    position = int(position)
    # determine symbol
    symbol = player1 if turn == "1" else player2
    # if choosen position is empty
    if board[position - 1] == " ":
        board[position - 1] = symbol
        printBoard()
        # check if player has won
        if checkWin():
            return
        
        # change turn
        turn = "2" if turn == "1" else "1"
        playerTurn(turn)
    else:
        print("That position is already taken.")
        playerTurn(turn)

V. Create Function To Check If Game Is Over

The function checkWin() used above checks if the game is over or not.

To check if the game is over we will use a list of winning combinations. If any of the winning combinations is found, then the game is over.

Use for loop to check all 3 combinations of rows and columns.

Also, check if the board is full. If it is full, then it's a tie.

# check if game is over
def checkWin():
    # check rows
    for i in range(0, 3):
        if board[i] == board[i + 3] == board[i + 6] != " ":
            if board[i] == player1:
                print("Player 1 wins!")
            elif board[i] == player2:
                print("Player 2 wins!")
            return True
    # check columns
    for i in range(0, 9, 3):
        if board[i] == board[i + 1] == board[i + 2] != " ":
            if board[i] == player1:
                print("Player 1 wins!")
            elif board[i] == player2:
                print("Player 2 wins!")
            return True
    # check diagonals
    if board[0] == board[4] == board[8] != " ":
        if board[0] == player1:
            print("Player 1 wins!")
        elif board[0] == player2:
            print("Player 2 wins!")
        return True
    if board[2] == board[4] == board[6] != " ":
        if board[2] == player1:
            print("Player 1 wins!")
        elif board[2] == player2:
            print("Player 2 wins!")
        return True
    # check if board is full
    if " " not in board:
        print("It's a tie!")
        return True

Complete Code For Tic Tac Toe Game

Here is the complete code for our simple Tic Tac Toe game.

# complete code for Tic Tac Toe game
# tic tac toe game
player1 = input("Player 1, choose X or O: ")
if player1 == "x":
    player2 = "O"
    player1 = "X"
else:
    player2 = "X"
    player1 = "O"

print(f"Player 1 is {player1} and Player 2 is {player2}")

# board array
board = [" " for x in range(9)]

def startGame():
    print("Welcome to Tic Tac Toe!")
    printBoard()
    playerTurn("1")

def printBoard():
    print("     |     |     ")
    print("  " + board[0] + "  |  " + board[1] + "  |  " + board[2] + "  ")
    print("_____|_____|_____")
    print("     |     |     ")
    print("  " + board[3] + "  |  " + board[4] + "  |  " + board[5] + "  ")
    print("_____|_____|_____")
    print("     |     |     ")
    print("  " + board[6] + "  |  " + board[7] + "  |  " + board[8] + "  ")
    print("     |     |     ")

def playerTurn(turn):
    print(f"Player {turn}, it's your turn.")
    position = input("Choose a position from 1-9: ")
    # keep asking for input until valid position is chosen
    while position not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
        position = input("Invalid position. Choose a position from 1-9: ")

    # convert position to int
    position = int(position)
    # determine symbol
    symbol = player1 if turn == "1" else player2
    # if choosen position is empty
    if board[position - 1] == " ":
        board[position - 1] = symbol
        printBoard()
        # check if player has won
        if checkWin():
            return
        
        # change turn
        turn = "2" if turn == "1" else "1"
        playerTurn(turn)
    else:
        print("That position is already taken.")
        playerTurn(turn)

def checkWin():
    # check rows
    for i in range(0, 3):
        if board[i] == board[i + 3] == board[i + 6] != " ":
            if board[i] == player1:
                print("Player 1 wins!")
            elif board[i] == player2:
                print("Player 2 wins!")
            return True
    # check columns
    for i in range(0, 9, 3):
        if board[i] == board[i + 1] == board[i + 2] != " ":
            if board[i] == player1:
                print("Player 1 wins!")
            elif board[i] == player2:
                print("Player 2 wins!")
            return True
    # check diagonals
    if board[0] == board[4] == board[8] != " ":
        if board[0] == player1:
            print("Player 1 wins!")
        elif board[0] == player2:
            print("Player 2 wins!")
        return True
    if board[2] == board[4] == board[6] != " ":
        if board[2] == player1:
            print("Player 1 wins!")
        elif board[2] == player2:
            print("Player 2 wins!")
        return True
    # check if board is full
    if " " not in board:
        print("It's a tie!")
        return True

# start game
startGame()

Here is a screenshot of a game:

python tic tac toe output 1

Tic Tac Toe Using Pygame

We have just completed a simple Tic Tac Toe game above which can be played on the terminal.

After playing the game you would have observed that the game that runs on the terminal is not very user-friendly. For every action, you have to give input by keyboard and then have to press enter to see the result.

If you talk about real-time interaction with such a game, it's nothing.

To overcome such problems we can create a game using Pygame. It creates a proper GUI for us to interact with the game.

Let's know about Pygame in brief.


Pygame Introduction

Pygame is a cross-platform Python module that is used to create a game in Python.

It is based on the SDL library which gives us the ability to control the screen and the keyboard.

Pygame is not part of the Python core module. You need to install it separately.

To install Pygame use the following command:

pip install pygame
# or
pip3 install pygame

Now you have installed Pygame in your system, let's start using it to create a Tic Tac Toe game.

I. Import Necessary Modules

The game requires a few Python modules to run among which Pygame is the most important one. Let's import them.

import pygame as pg           # main Pygame module as pg
import sys                    # system module for exiting the game
import time                   # time module for delaying the game

When you import a module, it is automatically loaded into your system. You can also choose to rename the module for your own purpose (generally shorting number) if the module name is long. For example, if you import pygame module as pg, you can use pg as a module name.


II. Defining Variables To Be Used

Variables are the most used concept in a programming language. We are going to use a lot of variables in this game. So let's define them.

# define variables
# colors
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)

# game settings
WIDTH, HEIGHT = 400, 500                # game screen size
BOARD_HEIGHT = HEIGHT - 100             # board height
RUN = True
turn = 'X'                              # player's turn
FPS = 30                                # game refresh rate
board = [[None]*3 for i in range(3)]    # board array

It may be overwhelming for you where these variables are coming from. How do we know these variables will be used later in the game?🤔

The simple answer is no one knows it unless you are very experienced or you have already created this one.


III. Pygame Setup

To begin creating the game let's set things up.

You need to call the pygame.init() function to initialize the Pygame library. Even if you do not call this function, you will still be able to use the Pygame library but some of the functions may not work. So it is recommended to call this function.

For the game to run we need to have a window. So let's create a window using the pygame.display.set_mode() function.

# initial game setup
pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption('Tic Tac Toe (TutorialsTonight)')

The reference of the window we have created above is stored in a variable called screen. Because we are going to do a lot of things with the screen so we must store it in a variable.

Also, define a caption or title for your game using the pg.display.set_caption() function.

If you run the code discussed till now, you will see a window with the title Tic Tac Toe (TutorialsTonight). The window will be of size 400x500. It will be created and immediately closed because you need to have the main game loop to run the game.

Here is how our window looks.

Pygame tic tac toe output 1

IV. Main Game Loop

Now we are ready to start the game. All Pygame has a loop called the main loop which runs the game.

This loop is executed over and over again and looks for events like a mouse click, key press, etc until the game is over.

Let's look at the loop. Its code is discussed below.

# main game loop
while RUN:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            RUN = False
            sys.exit()
        if event.type == pg.MOUSEBUTTONDOWN:
            # x, y = pg.mouse.get_pos()
            # player_turn(x, y)

    pg.display.update()
    pg.time.Clock().tick(FPS)

Code Explanation:

To constantly check for any events from the player the main loop is used. Pygame has a function called pg.event.get() which returns a list of events. This list is then iterated over and the events are checked for.

To close the game, we need to check if the event is pg.QUIT. If it is, we need to exit the game.

For this game, we only need to look up for mouse click event. So we checked for the pg.MOUSEBUTTONDOWN event.

When the player clicks on the screen, we need to get the position of the mouse click and will run a function called player_turn() (Discussed later).

We have to update the screen after every event. So we used the pg.display.update() function.

The pg.time.Clock().tick(FPS) function is used to set the game refresh rate. This is the number of times the game loop will run per second. So if you set the FPS to 30, the game loop will run 30 times per second.


V. Set Up Images

The images play a very important role in the game. Pygame basically renders the images on the screen very fast and efficiently. If needed it changes image position or add new images. All these happen so fast that the player has a feeling of the game is running smoothly.

So, let's set up the images.

We are going to use 3 images in this game (which we have already created):

  1. Game intro image
  2. Image for symbol X
  3. Image for symbol O
Tic Tac Toe Require Images

You can download the entire game with the images below.

# load game images
x_image = pg.image.load('x.png')
o_image = pg.image.load('o.png')
intro_image = pg.image.load('tic-tac-toe-intro.png')

# tranform image to desired size
x_image = pg.transform.scale(x_image, (80, 80))
o_image = pg.transform.scale(o_image, (80, 80))
intro_image = pg.transform.scale(intro_image, (WIDTH, HEIGHT))

The images are loaded using the pg.image.load() function. The URL of the image is passed as the argument.

IF needed you can scale the images using the pg.transform.scale() function. The first argument is the image and the second argument is the size of the image.


VI. Game Intro Function

Now we are ready to start the game. The game starts with an intro screen. This screen will be shown for a few seconds and then the game will start.

The function game_intro() sticks the intro image on the screen and updates the display.

After 1 second fill the screen with white color to make the intro image disappear.

# game intro function
def game_intro():
    screen.blit(intro_image, (0,0))
    pg.display.update()
    time.sleep(1)
    screen.fill(WHITE)

The color WHITE is defined above as WHITE = (255, 255, 255).

The blit() function is used to draw the image on the screen. The first argument is the image and the second argument is the position of the image.


VII. Draw Lines To Create Board

The tic tac toe game has a board with 9 square boxes. We are going to draw lines to create the board.

# draw board lines
def draw_line():
    pg.draw.line(screen, BLACK, (WIDTH/3, 10),(WIDTH/3, BOARD_HEIGHT - 10), 3)
    pg.draw.line(screen, BLACK, (WIDTH*2/3, 10),(WIDTH*2/3, BOARD_HEIGHT - 10), 3)
    pg.draw.line(screen, BLACK, (10, BOARD_HEIGHT/3),(WIDTH - 10, BOARD_HEIGHT/3), 3)
    pg.draw.line(screen, BLACK, (10, BOARD_HEIGHT*2/3),(WIDTH - 10, BOARD_HEIGHT*2/3), 3)

To draw a line we used the pg.draw.line() function. The first argument is the screen where the line is to be drawn. The second argument is the color of the line. The third and fourth arguments are the start and end points of the line.


VIII. Draw Bottom Bar To Show Game Status

Creating a bottom bar in the game gives the player visual feedback about the game. This bar will show the game status like whose turn it is or if the game is won or drawn.

# Show status of game (Whose Turn or Who Won)
def show_status(message):
    font = pg.font.Font(None, 30)
    # draw a rectangle at the bottom of the screen
    pg.draw.rect(screen, BLACK, (0, BOARD_HEIGHT, WIDTH, 100))

    if message == 'X':
        status_text = font.render("X's turn", True, WHITE)
    elif message == 'O':
        status_text = font.render("O's turn", True, WHITE)
    else:
        status_text = font.render(message, True, WHITE)

    screen.blit(status_text, ((WIDTH - status_text.get_width())/2, BOARD_HEIGHT + 50))
    pg.display.update()

The function has an argument that checks if the message is either 'X' or 'O' then it displays the message as 'X's turn' or 'O's turn. If the message is something different like 'Game Drawn' or 'X Won' then it displays the message as the same.


IX. Start Game Function

It's time to call all the functions we have created. The function start_game() is the main function that starts the game.

# start the game
def start_game():
    game_intro()
    draw_line()
    show_status(turn)
    pg.display.update()

start_game()

X. Player Turn Function

The game is started but the player can't interact with the game now because there is no functionality that can handle the player's click. So we need to create a function that will handle the player's click.

Let's create a function called player_turn(). It takes the position of the click as 2 arguments x and y.

# function to handle player's move
def player_turn(x, y):
    global turn

    # return if x,y is out of bounds
    if x < 10 or x > WIDTH - 20 or y < 10 or y > BOARD_HEIGHT - 20:
        return

    # get index of box clicked
    x_index = int(x // (WIDTH/3))
    y_index = int(y // (BOARD_HEIGHT/3))

    # check if box is already filled
    if board[x_index][y_index] is not None:
        return

    # get position on board to draw x or o
    PADDING = 30
    if board[x_index][y_index] == None:
        if x_index == 0:
            if y_index == 0:
                x_pos = PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING
        elif x_index == 1:
            if y_index == 0:
                x_pos = WIDTH/3 + PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = WIDTH/3 + PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = WIDTH/3 + PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING
        elif x_index == 2:
            if y_index == 0:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING

    if turn == 'X':
        screen.blit(x_image, (x_pos, y_pos))
        board[x_index][y_index] = 'X'
        turn = 'O'
        show_status(turn)
        check_winner('X')
    else:
        screen.blit(o_image, (x_pos, y_pos))
        board[x_index][y_index] = 'O'
        turn = 'X'
        show_status(turn)
        check_winner('O')

XI. Check Winner If Any

Now we need to check if the game is won or drawn. The function check_winner() takes the turn of the player as an argument.

The function will execute a for loop and check if any row or column has the same value as the turn of the player. If it is then draw a red line connection to the matching boxes.

Do the same thing for the diagonal of the board.

Show the status of the game after the line is drawn and close the game.

# function to check if the game is won or drawn
def check_winner(turn):
    # check row and column
    for i in range(3):
        # checking row
        if board[0][i] == turn and board[1][i] == turn and board[2][i] == turn:
            pg.draw.line(screen, RED, (10, (2*i+1)*BOARD_HEIGHT/6),(WIDTH - 10, (2*i+1)*BOARD_HEIGHT/6), 3)
            show_status(turn + ' Wins!')
            close_game()
        # checking column
        if board[i][0] == turn and board[i][1] == turn and board[i][2] == turn:
            pg.draw.line(screen, RED, ((2*i+1)*WIDTH/6, 10),((2*i+1)*WIDTH/6, BOARD_HEIGHT - 10), 3)
            show_status(turn + ' Wins!')
            close_game()
    # check diagonal
    if board[0][0] == turn and board[1][1] == turn and board[2][2] == turn:
        pg.draw.line(screen, RED, (10, 10), (WIDTH - 10, BOARD_HEIGHT - 10), 5)
        show_status(turn + ' Wins!')
        close_game()
    if board[0][2] == turn and board[1][1] == turn and board[2][0] == turn:
        pg.draw.line(screen, RED, (10, BOARD_HEIGHT - 10), (WIDTH - 10, 10), 5)
        show_status(turn + ' Wins!')
        close_game()
    # check if board is full print tie
    boxes = 0
    for i in range(3):
        for j in range(3):
            if board[i][j] is not None:
                boxes += 1
    if boxes == 9:
        show_status("It's a Tie!")
        close_game()

    return False

XII. Close Game

After a player wins or draws the game, we need to close the game. The function close_game() will show the status of the game and close the game.

# close game
def close_game():
    time.sleep(1.5)
    pg.quit()
    sys.exit()

Complete Code Pygame Tic Tac Toe

Here is the complete code of the game.

import pygame as pg           # main Pygame module as pg
import sys                    # system module for exiting the game
import time                   # time module for delaying the game

# define variables
# colors
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)

# game settings
WIDTH, HEIGHT = 400, 500                # game screen size
BOARD_HEIGHT = HEIGHT - 100             # board height
RUN = True
turn = 'X'                              # player's turn
FPS = 30                                # game refresh rate
board = [[None]*3 for i in range(3)]    # board array

# initial game setup
pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption('Tic Tac Toe (TutorialsTonight)')

# game images
x_image = pg.image.load('x.png')
o_image = pg.image.load('o.png')
intro_image = pg.image.load('tic-tac-toe-intro.png')

# tranform image to desired size
x_image = pg.transform.scale(x_image, (80, 80))
o_image = pg.transform.scale(o_image, (80, 80))
intro_image = pg.transform.scale(intro_image, (WIDTH, HEIGHT))

# game intro
def game_intro():
    screen.blit(intro_image, (0,0))
    pg.display.update()
    time.sleep(1)
    screen.fill(WHITE)

# draw board lines
def draw_line():
    pg.draw.line(screen, BLACK, (WIDTH/3, 10),(WIDTH/3, BOARD_HEIGHT - 10), 3)
    pg.draw.line(screen, BLACK, (WIDTH*2/3, 10),(WIDTH*2/3, BOARD_HEIGHT - 10), 3)
    pg.draw.line(screen, BLACK, (10, BOARD_HEIGHT/3),(WIDTH - 10, BOARD_HEIGHT/3), 3)
    pg.draw.line(screen, BLACK, (10, BOARD_HEIGHT*2/3),(WIDTH - 10, BOARD_HEIGHT*2/3), 3)

# Show status of game (Whose Turn or Who Won)
def show_status(message):
    font = pg.font.Font(None, 30)
    # draw a rectangle at the bottom of the screen
    pg.draw.rect(screen, BLACK, (0, BOARD_HEIGHT, WIDTH, 100))

    if message == 'X':
        status_text = font.render("X's turn", True, WHITE)
    elif message == 'O':
        status_text = font.render("O's turn", True, WHITE)
    else:
        status_text = font.render(message, True, WHITE)

    screen.blit(status_text, ((WIDTH - status_text.get_width())/2, BOARD_HEIGHT + 50))
    pg.display.update()

# function to handle player's move
def player_turn(x, y):
    global turn

    # return if x,y is out of bounds
    if x < 10 or x > WIDTH - 20 or y < 10 or y > BOARD_HEIGHT - 20:
        return

    # get index of box clicked
    x_index = int(x // (WIDTH/3))
    y_index = int(y // (BOARD_HEIGHT/3))

    # check if box is already filled
    if board[x_index][y_index] is not None:
        return

    # get position on board to draw x or o
    PADDING = 30
    if board[x_index][y_index] == None:
        if x_index == 0:
            if y_index == 0:
                x_pos = PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING
        elif x_index == 1:
            if y_index == 0:
                x_pos = WIDTH/3 + PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = WIDTH/3 + PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = WIDTH/3 + PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING
        elif x_index == 2:
            if y_index == 0:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = PADDING
            elif y_index == 1:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = BOARD_HEIGHT/3 + PADDING
            else:
                x_pos = WIDTH*2/3 + PADDING
                y_pos = BOARD_HEIGHT*2/3 + PADDING

    if turn == 'X':
        screen.blit(x_image, (x_pos, y_pos))
        board[x_index][y_index] = 'X'
        turn = 'O'
        show_status(turn)
        check_winner('X')
    else:
        screen.blit(o_image, (x_pos, y_pos))
        board[x_index][y_index] = 'O'
        turn = 'X'
        show_status(turn)
        check_winner('O')


# close game
def close_game():
    time.sleep(1.5)
    pg.quit()
    sys.exit()

# check if there is a winner
def check_winner(turn):
    # check row and column
    for i in range(3):
        # checking row
        if board[0][i] == turn and board[1][i] == turn and board[2][i] == turn:
            pg.draw.line(screen, RED, (10, (2*i+1)*BOARD_HEIGHT/6),(WIDTH - 10, (2*i+1)*BOARD_HEIGHT/6), 3)
            show_status(turn + ' Wins!')
            close_game()
        # checking column
        if board[i][0] == turn and board[i][1] == turn and board[i][2] == turn:
            pg.draw.line(screen, RED, ((2*i+1)*WIDTH/6, 10),((2*i+1)*WIDTH/6, BOARD_HEIGHT - 10), 3)
            show_status(turn + ' Wins!')
            close_game()
    # check diagonal
    if board[0][0] == turn and board[1][1] == turn and board[2][2] == turn:
        pg.draw.line(screen, RED, (10, 10), (WIDTH - 10, BOARD_HEIGHT - 10), 5)
        show_status(turn + ' Wins!')
        close_game()
    if board[0][2] == turn and board[1][1] == turn and board[2][0] == turn:
        pg.draw.line(screen, RED, (10, BOARD_HEIGHT - 10), (WIDTH - 10, 10), 5)
        show_status(turn + ' Wins!')
        close_game()
    # check if board is full print tie
    boxes = 0
    for i in range(3):
        for j in range(3):
            if board[i][j] is not None:
                boxes += 1
    if boxes == 9:
        show_status("It's a Tie!")
        close_game()

    return False

# start the game
def start_game():
    game_intro()
    draw_line()
    show_status(turn)
    pg.display.update()

start_game()

# main game loop
while RUN:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            RUN = False
            sys.exit()
        if event.type == pg.MOUSEBUTTONDOWN:
            x, y = pg.mouse.get_pos()
            player_turn(x, y)

    pg.display.update()
    pg.time.Clock().tick(FPS)

Output:

tic tac toe game in python

Download the complete game here.


Conclusion

Simple tic tac toe game that works in the terminal and Pygame tic tac toe game created using Pygame, we have discussed these 2 in this article with their complete code.

Why stop now, create a BMI calculator using Python.

Also check out Rock Paper Scissors game in Python.

Happy Coding! 😇