A full-stack, turn-based Battleship game built for collaborative software engineering practice. The project combines a Flask + PostgreSQL backend with a modular vanilla JavaScript frontend to deliver a persistent multiplayer experience with clear API contracts, deterministic test support, and production-ready deployment paths.
This project implements a distributed multiplayer Battleship game where players can:
- Create player identities.
- Create and join game lobbies.
- Place ships on a shared grid.
- Take turn-based shots against opponents.
- Track game outcomes and lifetime player statistics.
The system was designed to emphasize:
- Correctness through strict request validation and state transition rules.
- Testability via dedicated test-mode API routes.
- Maintainability through clear module boundaries in both frontend and backend.
- Deployment readiness using containerized backend/frontend services and PostgreSQL.
Frontend (Static HTML/CSS/JS)
|
| HTTP (JSON)
v
Backend API (Flask Blueprints)
|
v
PostgreSQL (games, players, moves, ships, game_players)
- Framework: Flask
- Database: PostgreSQL (via psycopg)
- Core modules:
routes.pyfor production/api/*endpoints.test_routes.pyfor deterministic/api/test/*endpoints (gated byTEST_MODE).game_logic.pyfor turn progression, elimination checks, game activation, and final stat updates.db.pyfor connection management.
- Stack: Static HTML, CSS, JavaScript (no heavy framework dependency).
- Design approach: componentized UI and feature modules.
- Key layers:
- API client (
js/api.js) for backend communication. - State management (
js/store.js) for reactive data flow. - Feature screens/components for lobby, placement, gameplay, and results.
- API client (
battleship/
├── backend/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── db.py
│ │ ├── game_logic.py
│ │ ├── routes.py
│ │ ├── test_gate.py
│ │ └── test_routes.py
│ ├── sql/schema.sql
│ ├── tests/
│ ├── Dockerfile
│ └── requirements.txt
└── frontend/
├── index.html
├── css/
├── js/
├── components/
└── Dockerfile
Base path: /api
Content-Type: application/json
- JSON request bodies are required for all POST endpoints.
- IDs are server-generated where applicable (for example, client-supplied
player_idis rejected in player creation). - Input validation is strict (integer checks, coordinate bounds, placement constraints, duplicate-action prevention).
- State transitions are enforced server-side (
waiting→active→finished).
- Player: identity + persistent lifetime stats.
- Game: lobby/configuration and current phase.
- Game Player: player membership and turn/elimination metadata per game.
- Ship: one board coordinate per ship cell (3 ship cells/player).
- Move: one fired shot with result (
hitormiss) and timestamp.
Resets game/move/ship data and player stats to baseline.
Use case: clean environment for repeated test runs.
Creates a new player.
Request body
{ "username": "Johan" }Success response (201)
{ "player_id": 1 }Validation highlights
usernamerequired and unique.player_idcannot be supplied by the client.
Returns identity data for a specific player.
Success response (200)
{ "player_id": 1, "username": "Johan" }Returns lifetime performance statistics.
Success response (200)
{
"games_played": 3,
"wins": 2,
"losses": 1,
"total_shots": 20,
"total_hits": 9,
"accuracy": 45.0
}Creates a game lobby and auto-joins the creator as turn order 0.
Request body
{ "creator_id": 1, "grid_size": 8, "max_players": 2 }Success response (201)
{ "game_id": 10 }Validation highlights
grid_sizemust be integer between 5 and 15.max_playersmust be integer >= 1.creator_idmust reference an existing player.
Adds an existing player to a waiting game.
Request body
{ "player_id": 2 }Success response (200)
{ "message": "Joined game successfully" }Validation highlights
- Game must exist and be
waiting. - Player must exist and not already be in the game.
- Game capacity (
max_players) is enforced.
Returns game metadata.
Success response (200)
{
"game_id": 10,
"grid_size": 8,
"status": "waiting",
"current_turn_index": 0,
"active_players": 2
}Places exactly three ship coordinates for the player.
Request body
{
"player_id": 1,
"ships": [
{ "row": 0, "col": 0 },
{ "row": 1, "col": 1 },
{ "row": 2, "col": 2 }
]
}Success response (200)
{ "message": "Ships placed successfully" }Validation highlights
- Exactly 3 coordinates required.
- No overlap and all coordinates must be within board bounds.
- Placement allowed only during
waitingphase. - After all players place ships, game auto-transitions to
active.
Executes one turn action.
Request body
{ "player_id": 1, "row": 3, "col": 4 }Success response while active (200)
{ "result": "miss", "next_player_id": 2, "game_status": "active" }Success response when game finishes (200)
{ "result": "hit", "next_player_id": null, "game_status": "finished", "winner_id": 1 }Validation highlights
- Game must be
active. - Shooter must belong to game and it must be their turn.
- Coordinates must be in bounds.
- Duplicate shots by same shooter at same coordinate are rejected.
- Eliminations and final winner/stat updates are handled transactionally.
Returns chronological move history.
Success response (200)
{
"moves": [
{ "player_id": 1, "row": 3, "col": 4, "result": "miss", "timestamp": "2026-01-01T00:00:00Z" }
]
}Base path: /api/test
These endpoints support deterministic grading and QA automation.
Resets a game instance to pre-play conditions:
- Deletes moves and ships for that game.
- Returns game to
waiting. - Resets
ships_placedand elimination flags.
Deterministic ship placement for grading workflows.
- Accepts
player_id(orplayerId) withshipsarray. - Replaces prior ships for that player in that game.
- Helps create repeatable scenarios for backend tests.
Returns board-visibility payload for validation, including:
- Player ship cells.
- Hits received.
- 2D board matrix using symbols (
.,S,X).
- Validation failures return
400with{ "error": "..." }. - Not-found resources return
404. - Forbidden state/action cases (for example wrong turn or inactive game fire) return
403. - Concurrency/state conflicts may return
409for race-like collisions.
- Johan Zapata
- Nathan Kitchens
- Designed backend endpoint testing strategy in Postman.
- Designed frontend visual elements and overall UI styling direction.
- Helped align product behavior with user-facing clarity and consistency.
- Designed and integrated PostgreSQL database schema.
- Designed backend endpoint testing strategy in APIDog.
- Helped implement core game logic such as turn handling, player elimiation and win conditions.
AI tools were used as engineering assistants to improve speed, quality, and documentation discipline:
- ChatGPT (Codex):
- Assisted with implementation support, refactoring suggestions, and structured documentation updates.
- Helped enforce consistent API and architecture descriptions.
- Claude:
- Supported iterative reasoning, review feedback synthesis, and alternative implementation perspectives.
- Assisted in communication clarity for project artifacts.
This project reflects disciplined engineering and team collaboration through:
- Separation of concerns: backend game logic, routing, and persistence responsibilities are modularized.
- Deterministic testing workflow: dedicated test-mode endpoints enable reliable verification and grading.
- API contract consistency: strict JSON validation, status code discipline, and controlled state transitions.
- Iterative collaboration: human-led product/testing decisions paired with AI-assisted development and documentation.
- Deployment reproducibility: containerized backend/frontend services with explicit environment configuration.
- Expanded the API section from a brief endpoint list into a detailed contract reference.
- Added request/response JSON examples for core gameplay endpoints.
- Added validation, state-transition, and error-code behavior notes.
- Clarified test/grading endpoint purpose for deterministic backend validation.
- Preserved and reaffirmed team roles, AI collaboration details, and engineering discipline practices.
- Create PostgreSQL Addon and capture/link
DATABASE_URL. - Deploy backend service from
backend/with:DATABASE_URLTEST_MODE(truefor grading,falsefor production)- Port
8000
- Deploy frontend service from
frontend/and setwindow.API_BASEinfrontend/index.htmlto backend URL.
# Backend
cd backend
pip install -r requirements.txt
export DATABASE_URL="postgresql://user:pass@localhost:5432/battleship"
export TEST_MODE=true
flask --app app run --debug --port 5000
# Frontend (new terminal)
cd frontend
npx serve .
# or: python3 -m http.server 3000
# Set window.API_BASE = 'http://localhost:5000' in index.html- Create player identities.
- Create or join a game lobby.
- Place three ships.
- Play alternating turns until one player remains.
- Review final result and updated stats.
Johan Zapata - Designed backend endpoint testing strategy in Postman, designed frontend visual elements and overall UI styling, and helped align product behavior with user facing consistency.
Nathan Kitchens - Designed database schema and integration, contributed to backend implementation and core game logic, and supported overall system functionality and debugging.
ChatGPT (Codex) - Assisted with implementation support, refactor suggestions, and structured documentation updates. Helped enforce consistent API and architecture descriptions.
Claude - Supported iterative reasoning, review feedback synthesis, and alternative implentation perspectives. Assisted in contribution clarity for project artifacts.