Skip to content

Multiplayer Tic-Tac-Toe (Socket Programming)

Abstract

Build a Multiplayer Tic-Tac-Toe game using socket programming. Two players can play over a network with real-time updates of the game board. This project demonstrates network programming, concurrency, and game logic in Python.

Prerequisites

  • Python 3.6 or above
  • Text Editor or IDE
  • Basic understanding of Python syntax
  • Familiarity with socket programming
  • Knowledge of threading for concurrency

Getting Started

Creating a new project

  1. Create a new project folder and name it multiplayer_tic_tac_toemultiplayer_tic_tac_toe.
  2. Create a new file inside the folder and name it multiplayer_tic_tac_toe.pymultiplayer_tic_tac_toe.py.
  3. Open the project folder in your favorite text editor or IDE.
  4. Copy the code below and paste it into the multiplayer_tic_tac_toe.pymultiplayer_tic_tac_toe.py file.

Write the code

⚙️ multiplayer_tic_tac_toe.py
multiplayer_tic_tac_toe.py
"""
Multiplayer Tic-Tac-Toe
 
A Python-based multiplayer Tic-Tac-Toe game using socket programming. Features include:
- Two players can play over a network.
- Real-time updates of the game board.
"""
 
import socket
import threading
 
# Constants
HOST = "127.0.0.1"
PORT = 65432
 
# Game board
board = [" " for _ in range(9)]
current_player = "X"
lock = threading.Lock()
 
def print_board():
    """Print the game board."""
    print("\n")
    for i in range(3):
        print(" | ".join(board[i * 3:(i + 1) * 3]))
        if i < 2:
            print("-" * 5)
 
def check_winner():
    """Check if there is a winner."""
    winning_combinations = [
        [0, 1, 2], [3, 4, 5], [6, 7, 8],  # Rows
        [0, 3, 6], [1, 4, 7], [2, 5, 8],  # Columns
        [0, 4, 8], [2, 4, 6]              # Diagonals
    ]
    for combo in winning_combinations:
        if board[combo[0]] == board[combo[1]] == board[combo[2]] != " ":
            return board[combo[0]]
    if " " not in board:
        return "Draw"
    return None
 
def handle_client(conn, addr):
    """Handle communication with a client."""
    global current_player
    conn.sendall("Welcome to Tic-Tac-Toe!\n".encode())
    conn.sendall("You are player {}\n".format(current_player).encode())
 
    player = current_player
    with lock:
        current_player = "O" if current_player == "X" else "X"
 
    while True:
        conn.sendall("\n".join(board).encode())
        conn.sendall("\nEnter your move (0-8): ".encode())
        move = conn.recv(1024).decode().strip()
 
        if not move.isdigit() or int(move) not in range(9):
            conn.sendall("Invalid move. Try again.\n".encode())
            continue
 
        move = int(move)
        with lock:
            if board[move] == " ":
                board[move] = player
                winner = check_winner()
                if winner:
                    conn.sendall("\nGame Over! Winner: {}\n".format(winner).encode())
                    break
            else:
                conn.sendall("Spot already taken. Try again.\n".encode())
 
    conn.close()
 
def main():
    """Main server function."""
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen(2)
    print("Server started. Waiting for players...")
 
    while True:
        conn, addr = server.accept()
        print(f"Player connected from {addr}")
        threading.Thread(target=handle_client, args=(conn, addr)).start()
 
if __name__ == "__main__":
    main()
 
multiplayer_tic_tac_toe.py
"""
Multiplayer Tic-Tac-Toe
 
A Python-based multiplayer Tic-Tac-Toe game using socket programming. Features include:
- Two players can play over a network.
- Real-time updates of the game board.
"""
 
import socket
import threading
 
# Constants
HOST = "127.0.0.1"
PORT = 65432
 
# Game board
board = [" " for _ in range(9)]
current_player = "X"
lock = threading.Lock()
 
def print_board():
    """Print the game board."""
    print("\n")
    for i in range(3):
        print(" | ".join(board[i * 3:(i + 1) * 3]))
        if i < 2:
            print("-" * 5)
 
def check_winner():
    """Check if there is a winner."""
    winning_combinations = [
        [0, 1, 2], [3, 4, 5], [6, 7, 8],  # Rows
        [0, 3, 6], [1, 4, 7], [2, 5, 8],  # Columns
        [0, 4, 8], [2, 4, 6]              # Diagonals
    ]
    for combo in winning_combinations:
        if board[combo[0]] == board[combo[1]] == board[combo[2]] != " ":
            return board[combo[0]]
    if " " not in board:
        return "Draw"
    return None
 
def handle_client(conn, addr):
    """Handle communication with a client."""
    global current_player
    conn.sendall("Welcome to Tic-Tac-Toe!\n".encode())
    conn.sendall("You are player {}\n".format(current_player).encode())
 
    player = current_player
    with lock:
        current_player = "O" if current_player == "X" else "X"
 
    while True:
        conn.sendall("\n".join(board).encode())
        conn.sendall("\nEnter your move (0-8): ".encode())
        move = conn.recv(1024).decode().strip()
 
        if not move.isdigit() or int(move) not in range(9):
            conn.sendall("Invalid move. Try again.\n".encode())
            continue
 
        move = int(move)
        with lock:
            if board[move] == " ":
                board[move] = player
                winner = check_winner()
                if winner:
                    conn.sendall("\nGame Over! Winner: {}\n".format(winner).encode())
                    break
            else:
                conn.sendall("Spot already taken. Try again.\n".encode())
 
    conn.close()
 
def main():
    """Main server function."""
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen(2)
    print("Server started. Waiting for players...")
 
    while True:
        conn, addr = server.accept()
        print(f"Player connected from {addr}")
        threading.Thread(target=handle_client, args=(conn, addr)).start()
 
if __name__ == "__main__":
    main()
 

Key Features

  • Two-player networked Tic-Tac-Toe
  • Real-time game board updates
  • Server-client architecture
  • Threading for handling multiple players

Explanation

Server Implementation

The server manages connections and game state:

multiplayer_tic_tac_toe.py
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(2)
multiplayer_tic_tac_toe.py
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(2)

Game Logic

The board is updated and checked for winners after each move:

multiplayer_tic_tac_toe.py
def check_winner():
    winning_combinations = [ ... ]
    for combo in winning_combinations:
        if board[combo[0]] == board[combo[1]] == board[combo[2]] != " ":
            return board[combo[0]]
    if " " not in board:
        return "Draw"
    return None
multiplayer_tic_tac_toe.py
def check_winner():
    winning_combinations = [ ... ]
    for combo in winning_combinations:
        if board[combo[0]] == board[combo[1]] == board[combo[2]] != " ":
            return board[combo[0]]
    if " " not in board:
        return "Draw"
    return None

Client Handling

Each client is handled in a separate thread:

multiplayer_tic_tac_toe.py
def handle_client(conn, addr):
    # Communicate with player, update board
multiplayer_tic_tac_toe.py
def handle_client(conn, addr):
    # Communicate with player, update board

Running the Application

  1. Save the file.
  2. Run the server:
python multiplayer_tic_tac_toe.py
python multiplayer_tic_tac_toe.py
  1. Run the client in a separate terminal:
python multiplayer_tic_tac_toe.py
python multiplayer_tic_tac_toe.py

Conclusion

This Multiplayer Tic-Tac-Toe project is a great way to learn about networked games and concurrency in Python. You can extend it by adding a GUI, chat feature, or player statistics.

Was this page helpful?

Let us know how we did