Welcome back to our Python game programming series! In Part 1, we covered the basics of pygame and created a simple interactive window. In this second part, we’ll build a complete Tic-Tac-Toe game with a graphical interface, turn management, and win detection.
What We’ll Build
Our Tic-Tac-Toe game will include:
- A graphical 3×3 game board drawn with pygame
- Two-player turn management (X and O)
- Click detection to place marks
- Win detection (rows, columns, diagonals)
- Draw detection
- Game reset functionality
Setting Up
Make sure you have pygame installed: pip install pygame
The Game Structure
import pygame
import sys
# Constants
WINDOW_SIZE = 600
BOARD_SIZE = 3
CELL_SIZE = WINDOW_SIZE // BOARD_SIZE
LINE_WIDTH = 5
CIRCLE_RADIUS = CELL_SIZE // 3
CIRCLE_WIDTH = 15
CROSS_WIDTH = 25
SPACE = CELL_SIZE // 4
# Colors
BG_COLOR = (28, 170, 156)
LINE_COLOR = (23, 145, 135)
CIRCLE_COLOR = (239, 231, 200)
CROSS_COLOR = (66, 66, 66)
pygame.init()
screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE))
pygame.display.set_caption("Tic Tac Toe")
screen.fill(BG_COLOR)
Board Logic
board = [[None] * BOARD_SIZE for _ in range(BOARD_SIZE)]
def draw_lines():
# Horizontal lines
for i in range(1, BOARD_SIZE):
pygame.draw.line(screen, LINE_COLOR, (0, i * CELL_SIZE), (WINDOW_SIZE, i * CELL_SIZE), LINE_WIDTH)
# Vertical lines
for i in range(1, BOARD_SIZE):
pygame.draw.line(screen, LINE_COLOR, (i * CELL_SIZE, 0), (i * CELL_SIZE, WINDOW_SIZE), LINE_WIDTH)
def draw_marks():
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if board[row][col] == 'O':
center = (col * CELL_SIZE + CELL_SIZE // 2, row * CELL_SIZE + CELL_SIZE // 2)
pygame.draw.circle(screen, CIRCLE_COLOR, center, CIRCLE_RADIUS, CIRCLE_WIDTH)
elif board[row][col] == 'X':
start1 = (col * CELL_SIZE + SPACE, row * CELL_SIZE + SPACE)
end1 = (col * CELL_SIZE + CELL_SIZE - SPACE, row * CELL_SIZE + CELL_SIZE - SPACE)
start2 = (col * CELL_SIZE + CELL_SIZE - SPACE, row * CELL_SIZE + SPACE)
end2 = (col * CELL_SIZE + SPACE, row * CELL_SIZE + CELL_SIZE - SPACE)
pygame.draw.line(screen, CROSS_COLOR, start1, end1, CROSS_WIDTH)
pygame.draw.line(screen, CROSS_COLOR, start2, end2, CROSS_WIDTH)
Win Detection
def check_winner(player):
# Check rows
for row in range(BOARD_SIZE):
if all(board[row][col] == player for col in range(BOARD_SIZE)):
return True
# Check columns
for col in range(BOARD_SIZE):
if all(board[row][col] == player for row in range(BOARD_SIZE)):
return True
# Check diagonals
if all(board[i][i] == player for i in range(BOARD_SIZE)):
return True
if all(board[i][BOARD_SIZE-1-i] == player for i in range(BOARD_SIZE)):
return True
return False
def is_board_full():
return all(board[row][col] is not None
for row in range(BOARD_SIZE)
for col in range(BOARD_SIZE))
Main Game Loop
def main():
current_player = 'X'
game_over = False
draw_lines()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
mouseX, mouseY = event.pos
clicked_row = mouseY // CELL_SIZE
clicked_col = mouseX // CELL_SIZE
if board[clicked_row][clicked_col] is None:
board[clicked_row][clicked_col] = current_player
if check_winner(current_player):
print(f"Player {current_player} wins!")
game_over = True
elif is_board_full():
print("It's a draw!")
game_over = True
else:
current_player = 'O' if current_player == 'X' else 'X'
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r: # Reset game
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
board[row][col] = None
game_over = False
current_player = 'X'
screen.fill(BG_COLOR)
draw_lines()
screen.fill(BG_COLOR)
draw_lines()
draw_marks()
pygame.display.update()
main()
What You’ve Learned
By building this game, you’ve practiced:
- Drawing shapes and lines with pygame
- Handling mouse click events
- Mapping screen coordinates to game grid positions
- Implementing game logic (win detection, turn management)
- Game state management
Extensions to Try
Once you have the basic game working, try these improvements:
- Add a score counter for multiple rounds
- Implement a simple AI opponent
- Add sound effects
- Display the winner with a highlighted winning line
Happy coding!