A real-time multiplayer Tic-tac-toe game built with FastAPI (backend) and React,Vite (frontend). The game supports multiple concurrent games and provides a clean, modern interface.
![Screenshot from 2024-12-14 21-06-32](/YoraiLevi/multiplayer-tictactoe/raw/master/pictures/Screenshot%20from%202024-12-14%2021-06-32.png)
![Screenshot from 2024-12-14 21-06-34](/YoraiLevi/multiplayer-tictactoe/raw/master/pictures/Screenshot%20from%202024-12-14%2021-06-34.png)
![Screenshot from 2024-12-14 21-05-52](/YoraiLevi/multiplayer-tictactoe/raw/master/pictures/Screenshot%20from%202024-12-14%2021-05-52.png)
![Screenshot from 2024-12-14 21-06-26](/YoraiLevi/multiplayer-tictactoe/raw/master/pictures/Screenshot%20from%202024-12-14%2021-06-26.png)
├── backend/
│ ├── src/
│ │ └── app/
│ │ ├── models/ # Data models and game state
│ │ ├── services/ # Game logic and WebSocket management
│ │ ├── routes/ # API endpoints
│ │ └── middleware/ # Logging middleware
│ ├── tests/ # API and WebSocket tests
│ └── run.sh # Server startup script
└── frontend/
└── src/
├── components/ # React components
├── services/ # API client
└── types/ # TypeScript definitions
-
Create and activate a virtual environment:
cd backend python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Start the server:
./run.sh --reload
The server will run on http://localhost:8000
-
Install dependencies:
cd frontend npm install
-
Start the development server:
./run.sh
The frontend will run on http://localhost:5173
To start both at once, make sure you have the python's virtual environment activated:
source ./backend/.venv/bin/activate
./run.sh
backend/src/app/models/game.py & frontend/src/types/game.ts
-
Game State
{ game_id: string; // Unique identifier player_id?: string; // Current player's ID board: Board; // 3x3 matrix current_turn?: Symbol; // 'X' or 'O' status: GameStatus; // 'waiting'|'in_progress'|'finished' winner?: Symbol; // Winner symbol or null for draw player_count: number; // Number of players (1 or 2) }
-
Game Move
{ player_id: string; // Player making the move position: [number, number] // Board coordinates [row, col] }
backend/src/app/services/game_service.py
-
Game Creation
- Player creates a new game (becomes Player X)
- Receives a unique game ID to share
- Waits for opponent to join
-
Joining a Game
- Second player joins using game ID (becomes Player O)
- Game status changes to 'in_progress'
- Players alternate making moves
-
Making Moves
- Validates:
- Correct player's turn
- Valid board position
- Position is unoccupied
- Updates game state
- Checks for win/draw condition
Websocket broadcasts new state to all players- not implemented, Polling every second is used instead
- Validates:
-
Win Condition Check After each move, checks for:
- Three matching symbols in any row
- Three matching symbols in any column
- Three matching symbols in either diagonal
- Full board with no winner (draw)
backend/src/app/routes/games.py
POST /api/games
- Create new gamePOST /api/games/{id}/join
- Join existing gamePOST /api/games/{id}/move
- Make a moveGET /api/games/{id}
- Get game state
- Real-time Updates: Game state is polled every second
- Multiple Games: Server supports concurrent game sessions
- Error Handling: Comprehensive error messages and validation
- User Experience:
- Easy game ID sharing - copy to clipboard!
- Clear turn indicators!
- Visual feedback for valid moves!
-
Backend
- Clean separation of concerns (models, services, routes)
- Centralized game logic in GameService
- Comprehensive test coverage for RESTAPI
- Type safety with Pydantic models
-
Frontend
- Component-based architecture
- TypeScript for type safety
- Centralized game service for API calls
- CSS modules for style isolation
- Invalid moves return appropriate HTTP status codes:
- 400: Bad Request (invalid position)
- 422: Unprocessable Entity (wrong turn/game rules)
- 404: Not Found (game doesn't exist)
- Persistent storage for game history
- User authentication
- Game replay,undo move feature
- Spectator mode
- Game statistics and leaderboards
- Websocket for real-time updates
- More UI Fluff
- Timeouts for inactive games
- Resource cleanup (memory after game ends)