Building a Tic-Tac-Toe Using Pygame

PythonPythonBeginner
Practice Now

Introduction

This project will guide you through the steps to create a Tic-Tac-Toe game using Pygame. Tic-Tac-Toe is a two-player game where the goal is to get three of your symbols in a row, either horizontally, vertically, or diagonally. In this project, you will learn how to set up the game window, draw the game board, handle player and AI moves, and determine the winner. By the end of this project, you will have a fully functional Tic-Tac-Toe game that you can play against an AI opponent.

👀 Preview

Tic-Tac-Toe Using Pygame

ðŸŽŊ Tasks

In this project, you will learn:

  • How to create the project files and import the necessary libraries
  • How to initialize PyGame and set up the game window
  • How to define the symbols, colors, and game state
  • How to define the button properties and create helper functions
  • How to create the main game loop and implement the helper functions
  • How to fill in the remaining code inside the main game loop

🏆 Achievements

After completing this project, you will be able to:

  • Use Pygame to create a graphical game
  • Draw graphics on a window using Pygame
  • Handle user input and update the game state
  • Implement game logic such as checking for a win condition
  • Create a game loop to keep the game running

Create the project files

To begin, create a new file named tic_tac_toe.py. Open the file in your preferred text editor.

cd ~/project
touch tic_tac_toe.py
âœĻ Check Solution and Practice

Import the necessary libraries

In tic_tac_toe.py, import the necessary libraries: pygame and random. These libraries will be used for handling the game graphics and generating random AI moves, respectively.

import pygame
import random

Install the pygame library using the following command:

sudo pip install pygame
âœĻ Check Solution and Practice

Initialize PyGame and set up the game window

In tic_tac_toe.py, initialize PyGame using pygame.init(). Then, set up the game window by defining the window width and height, background color, line color, and cell size. Also, create a PyGame window with the specified width and height and set the window caption.

pygame.init()

WIDTH = 600
HEIGHT = 600
BACKGROUND_COLOR = (40, 40, 40)
LINE_COLOR = (70, 70, 70)
CELL_SIZE = WIDTH // 3

win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tic-Tac-Toe")
âœĻ Check Solution and Practice

Define the symbols and colors

In tic_tac_toe.py, define the symbols and colors for the player and AI. These symbols and colors will be used to draw the player and AI moves on the game board.

PLAYER_SYMBOL = "X"
AI_SYMBOL = "O"
PLAYER_COLOR = (0, 255, 0)
AI_COLOR = (255, 0, 0)
EMPTY_COLOR = (0, 0, 0)
âœĻ Check Solution and Practice

Define the game state

In tic_tac_toe.py, define the initial game state. This includes the game board, the current turn (either "player" or "ai"), a flag indicating if the game is over, and the winner of the game.

board = [["" for _ in range(3)] for _ in range(3)]
turn = "player"
game_over = False
winner = None
âœĻ Check Solution and Practice

Define button properties

In tic_tac_toe.py, define the properties for the reset button, including the button width, height, color, text color, and font size. Also, create a reset_button_rect object using the pygame.Rect class to represent the button's position and size.

BUTTON_WIDTH = 200
BUTTON_HEIGHT = 50
BUTTON_COLOR = (50, 50, 50)
BUTTON_TEXT_COLOR = (255, 255, 255)
BUTTON_FONT = pygame.font.Font(None, 30)

reset_button_rect = pygame.Rect(
    (WIDTH - BUTTON_WIDTH) // 2,
    (HEIGHT - BUTTON_HEIGHT) // 2,
    BUTTON_WIDTH,
    BUTTON_HEIGHT,
)
âœĻ Check Solution and Practice

Create helper functions

In tic_tac_toe.py, define several helper functions that will be used throughout the game.

  • draw_board(): This function will draw the game board on the window.

  • draw_symbols(): This function will draw the player and AI symbols on the game board.

  • is_board_full(): This function will check if the game board is full.

  • is_winner(): This function will check if a player has won the game.

  • make_move(): This function will make a move on the game board.

  • player_move(): This function will handle the player's move.

  • ai_move(): This function will handle the AI's move.

  • check_game_over(): This function will check if the game is over.

  • draw_winner(): This function will draw the winner message on the window.

  • draw_reset_button(): This function will draw the reset button on the window.

  • reset_game(): This function will reset the game state.

## Helper functions
def draw_board():
    ## Draw the game board
    pass

def draw_symbols():
    ## Draw the player and AI symbols on the game board
    pass

def is_board_full():
    ## Check if the game board is full
    pass

def is_winner(symbol):
    ## Check if a player has won the game
    pass

def make_move(x, y, symbol):
    ## Make a move on the game board
    pass

def player_move():
    ## Handle the player's move
    pass

def ai_move():
    ## Handle the AI's move
    pass

def check_game_over():
    ## Check if the game is over
    pass

def draw_winner():
    ## Draw the winner message on the window
    pass

def draw_reset_button():
    ## Draw the reset button on the window
    pass

def reset_game():
    ## Reset the game state
    pass
âœĻ Check Solution and Practice

Create the main game loop

In tic_tac_toe.py, create the main game loop using a while loop. This loop will run until the user closes the game window. Inside the game loop, handle the user's input events and update the game state accordingly.

## Main game loop
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if reset_button_rect.collidepoint(event.pos):
                reset_game()
            elif not game_over and turn == "player":
                player_move()

    if not game_over and turn == "ai":
        ai_move()
        check_game_over()

    draw_board()
    draw_symbols()

    if game_over:
        draw_winner()
        draw_reset_button()

    pygame.display.flip()

## Quit the game
pygame.quit()
âœĻ Check Solution and Practice

Implement the helper functions

Now, let's implement the helper functions we defined earlier. Start by completing the draw_board() function. This function will draw the game board on the window by drawing vertical and horizontal lines using the pygame.draw.line() function.

## Helper functions
def draw_board():
    win.fill(BACKGROUND_COLOR)

    ## Draw vertical lines
    for x in range(1, 3):
        pygame.draw.line(
            win, LINE_COLOR, (CELL_SIZE * x, 0), (CELL_SIZE * x, HEIGHT), 2
        )

    ## Draw horizontal lines
    for y in range(1, 3):
        pygame.draw.line(win, LINE_COLOR, (0, CELL_SIZE * y), (WIDTH, CELL_SIZE * y), 2)
âœĻ Check Solution and Practice

Implement the remaining helper functions

Next, implement the remaining helper functions: draw_symbols(), is_board_full(), is_winner(), make_move(), player_move(), ai_move(), check_game_over(), draw_winner(), draw_reset_button(), and reset_game().

## Helper functions
def draw_symbols():
    for x in range(3):
        for y in range(3):
            symbol = board[x][y]
            if symbol == PLAYER_SYMBOL:
                color = PLAYER_COLOR
            elif symbol == AI_SYMBOL:
                color = AI_COLOR
            else:
                color = EMPTY_COLOR
            if symbol != "":
                pygame.draw.circle(
                    win,
                    color,
                    (x * CELL_SIZE + CELL_SIZE // 2, y * CELL_SIZE + CELL_SIZE // 2),
                    CELL_SIZE // 2 - 10,
                    2,
                )

def is_board_full():
    for row in board:
        if "" in row:
            return False
    return True

def is_winner(symbol):
    for row in board:
        if all(cell == symbol for cell in row):
            return True
    for col in range(3):
        if all(board[row][col] == symbol for row in range(3)):
            return True
    if all(board[i][i] == symbol for i in range(3)):
        return True
    if all(board[i][2 - i] == symbol for i in range(3)):
        return True
    return False

def make_move(x, y, symbol):
    if board[x][y] == "":
        board[x][y] = symbol
        return True
    return False

def player_move():
    global turn
    mouse_pos = pygame.mouse.get_pos()
    cell_x = mouse_pos[0] // CELL_SIZE
    cell_y = mouse_pos[1] // CELL_SIZE

    if make_move(cell_x, cell_y, PLAYER_SYMBOL):
        turn = "ai"

def ai_move():
    global turn
    empty_cells = []
    for x in range(3):
        for y in range(3):
            if board[x][y] == "":
                empty_cells.append((x, y))

    if empty_cells:
        x, y = random.choice(empty_cells)
        make_move(x, y, AI_SYMBOL)

    turn = "player"

def check_game_over():
    global game_over, winner
    if is_winner(PLAYER_SYMBOL):
        game_over = True
        return "player"
    elif is_winner(AI_SYMBOL):
        game_over = True
        return "ai"
    elif is_board_full():
        game_over = True
        return "tie"
    return None

def draw_winner():
    font = pygame.font.Font(None, 50)
    if winner == "player":
        text = font.render("Player Wins!", True, PLAYER_COLOR)
    elif winner == "ai":
        text = font.render("AI Wins!", True, AI_COLOR)
    else:
        text = font.render("It's a Tie!", True, (255, 255, 255))
    text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 3))
    win.blit(text, text_rect)

def draw_reset_button():
    pygame.draw.rect(win, BUTTON_COLOR, reset_button_rect)
    button_text = BUTTON_FONT.render("Reset", True, BUTTON_TEXT_COLOR)
    button_text_rect = button_text.get_rect(center=reset_button_rect.center)
    win.blit(button_text, button_text_rect)

def reset_game():
    global board, turn, game_over, winner
    board = [["" for _ in range(3)] for _ in range(3)]
    turn = "player"
    game_over = False
    winner = None

In above code, the draw_symbols() function will draw the symbols on the board. The is_board_full() function will check if the board is full. The is_winner() function will check if the given symbol has won the game. The make_move() function will make a move on the board. The player_move() function will handle the player's move. The ai_move() function will handle the AI's move. The check_game_over() function will check if the game is over. The draw_winner() function will draw the winner message. The draw_reset_button() function will draw the reset button. The reset_game() function will reset the game.

âœĻ Check Solution and Practice

Fill in the remaining code

Finally, fill in the remaining code inside the main game loop to call the helper functions at the appropriate places. This includes calling the draw_board() and draw_symbols() functions to draw the game board and symbols, calling the check_game_over() function to check if the game is over, and calling the draw_winner() and draw_reset_button() functions to draw the winner message and reset button, respectively.

## Main game loop
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if reset_button_rect.collidepoint(event.pos):
                reset_game()
            elif not game_over and turn == "player":
                player_move()

    if not game_over and turn == "ai":
        ai_move()
        winner = check_game_over()

    draw_board()
    draw_symbols()

    if game_over:
        draw_winner()
        draw_reset_button()

    pygame.display.flip()

## Quit the game
pygame.quit()

Run the game using the following command:

python tic_tac_toe.py
Alt text
âœĻ Check Solution and Practice

Summary

Congratulations! You have successfully created a Tic-Tac-Toe game using Pygame. In this project, you learned how to set up the game window, draw the game board, handle player and AI moves, and determine the winner. You also learned how to implement helper functions to simplify the code and make it more modular.

Other Python Tutorials you may like