Tic-Tac-Toe in Python
Intermediate · Games · about 75 minutes to build · 123 lines
Two players take turns on one keyboard, or you play X against a computer that takes winning squares and blocks yours.
The program
Press Run and answer its questions in the box that appears under the code.
Open it in the full editor to save it, share it and keep building.
Sample run
What the program printed, and what was typed (in yellow).
=== Tic-Tac-Toe === 1. Two players 2. Play against the computer 3. Quit Choose 1, 2 or 3: 2 You are X and you go first. 1 | 2 | 3 ---+---+--- 4 | 5 | 6 ---+---+--- 7 | 8 | 9 Player X, choose a square (1-9): 1 The computer takes square 5. X | 2 | 3 ---+---+--- 4 | O | 6 ---+---+--- 7 | 8 | 9 Player X, choose a square (1-9): 9 The computer takes square 7. X | 2 | 3 ---+---+--- 4 | O | 6 ---+---+--- O | 8 | X Player X, choose a square (1-9): 5 That square is taken. Player X, choose a square (1-9): 3 The computer takes square 2. X | O | X ---+---+--- 4 | O | 6 ---+---+--- O | 8 | X Player X, choose a square (1-9): 6 X | O | X ---+---+--- 4 | O | X ---+---+--- O | 8 | X You win. 1. Two players 2. Play against the computer 3. Quit Choose 1, 2 or 3: 3 Goodbye.
How it is built
1. The board and the winning lines
The board is a list of nine strings, one per square, numbered 0 to 8 in the code and 1 to 9 for the player. WIN_LINES lists the eight rows, columns and diagonals, so finding a winner is one loop.
EMPTY = " " # The eight lines of three that win: rows, columns and diagonals (squares 0-8). WIN_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), ] CENTER = 4 CORNERS = (0, 2, 6, 8)
2. Finding a winner
A line wins when its three squares hold the same mark and are not empty. The chained comparison board[a] == board[b] == board[c] checks all three at once.
def find_winner(board): """Return "X" or "O" if that mark has three in a line, otherwise None.""" for a, b, c in WIN_LINES: if board[a] != EMPTY and board[a] == board[b] == board[c]: return board[a] return None
3. Looking one move ahead
For each free square, the function puts the mark on a copy of the board and asks find_winner whether that move wins. Working on board.copy() leaves the real board untouched.
def winning_square(board, mark): """Return a square that completes three in a line for mark, or None.""" for square in free_squares(board): trial = board.copy() trial[square] = mark if find_winner(trial) == mark: return square return None
4. How the computer chooses
The computer looks for its own winning square first, then for the square that blocks the player, then takes the center, then a free corner. A player who takes two opposite corners can still beat it, which keeps the game fun.
def computer_move(board, mark, opponent): """Pick a square: win if possible, else block, else center, corner, any.""" for target in (mark, opponent): square = winning_square(board, target) if square is not None: return square if board[CENTER] == EMPTY: return CENTER corners = [c for c in CORNERS if board[c] == EMPTY] return random.choice(corners or free_squares(board))
5. Taking turns
mark switches between X and O after every move, and the computer plays O when vs_computer is True. The game ends when someone has three in a line or no EMPTY square is left, which is a draw.
def play_game(vs_computer): """Play one game; X always moves first.""" board = [EMPTY] * 9 mark = "X" while True: if vs_computer and mark == "O": square = computer_move(board, "O", "X") print(f" The computer takes square {square + 1}.") else: show_board(board) square = ask_move(board, mark) board[square] = mark winner = find_winner(board) if winner or EMPTY not in board: show_board(board) if winner and vs_computer: print("\nYou win." if winner == "X" else "\nThe computer wins.") elif winner: print(f"\nPlayer {winner} wins.") else: print("\nIt's a draw.") return mark = "O" if mark == "X" else "X"
Make it bigger
- Let the player choose to go second, so the computer opens the game.
- Make the computer unbeatable with the minimax algorithm, which plays out every possible game to the end.
- Keep a running score of X wins, O wins and draws across games.
- Grow the board to 4 x 4 with four in a row to win, building
WIN_LINESwith loops instead of by hand.
What it practises
- lists
- tuples of winning lines
- functions
- a simple game AI
- input validation