Python Tic Tac Toe Game Project

Python project 19

Python Tic Tac Toe Game Project

Build a complete two-player Tic-Tac-Toe game for the terminal. The program displays numbered empty squares, rejects invalid or occupied moves, checks all eight winning lines, recognises a draw, and supports repeat games.

Learn Python with mentor-guided projectsView all project ideas

What you will build

Two local players alternate as X and O. Empty positions display numbers 1 through 9, making moves easy to enter, while the board stores empty strings and player marks internally.

Skills practised

  • Lists and indexes
  • Tuples of winning positions
  • Turn-based loops
  • Validation and return values

Requirements

  • Python 3.10 or later
  • A terminal or command prompt
  • No external packages
  • About 35 minutes to build

Full Python code

Save this code as tic_tac_toe.py, then follow the run instructions below.

"""A two-player command-line Tic-Tac-Toe game."""

from __future__ import annotations


WINNING_LINES = (
    (0, 1, 2),
    (3, 4, 5),
    (6, 7, 8),
    (0, 3, 6),
    (1, 4, 7),
    (2, 5, 8),
    (0, 4, 8),
    (2, 4, 6),
)


def display_board(board: list[str]) -> None:
    cells = [value if value else str(index + 1) for index, value in enumerate(board)]
    print(f"\n {cells[0]} | {cells[1]} | {cells[2]}")
    print("---+---+---")
    print(f" {cells[3]} | {cells[4]} | {cells[5]}")
    print("---+---+---")
    print(f" {cells[6]} | {cells[7]} | {cells[8]}\n")


def winner(board: list[str]) -> str | None:
    for first, second, third in WINNING_LINES:
        if board[first] and board[first] == board[second] == board[third]:
            return board[first]
    return None


def read_move(board: list[str], player: str) -> int:
    while True:
        value = input(f"Player {player}, choose an empty square [1-9]: ").strip()
        if not value.isdigit() or not 1 <= int(value) <= 9:
            print("Enter a number from 1 to 9.")
            continue
        index = int(value) - 1
        if board[index]:
            print("That square is already occupied.")
            continue
        return index


def play_game() -> str | None:
    board = [""] * 9
    player = "X"

    for _ in range(9):
        display_board(board)
        board[read_move(board, player)] = player
        if winner(board):
            display_board(board)
            print(f"Player {player} wins!")
            return player
        player = "O" if player == "X" else "X"

    display_board(board)
    print("The game is a draw.")
    return None


def main() -> None:
    print("Python Tic-Tac-Toe")
    while True:
        play_game()
        if input("Play again? [y/N]: ").strip().lower() != "y":
            break


if __name__ == "__main__":
    main()

How the project works

display_board() substitutes a position number only when a board cell is empty. read_move() converts the chosen number to a zero-based list index and refuses occupied squares.

winner() checks three cells for each possible row, column, and diagonal. The game can finish immediately after a win; if nine accepted moves finish without a winner, the board is full and the result is a draw.

Run the project

  1. Run python tic_tac_toe.py.
  2. Player X chooses an empty position from 1 to 9.
  3. Player O chooses the next position.
  4. Continue until someone wins or the board is full.

Accuracy and safety notes

  • Indexes: displayed positions 1-9 map to list indexes 0-8.
  • State: one list stores the complete board.
  • Separation: display, input, win checking, and game flow use different functions.

Ways to extend it

Add a computer opponent using minimax, match scores, player names, colour output, or a graphical board with Tkinter.

Continue learning Python

Build the next project, return to the Softenant project library, or explore the Python programming course in Vizag for structured lessons, mentor feedback, and portfolio practice.