No description
  • Java 49.5%
  • JavaScript 31.5%
  • CSS 18.3%
  • HTML 0.3%
  • Dockerfile 0.2%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-03 16:47:10 +00:00
backend initial commit 2026-11-03 16:47:10 +00:00
docs initial commit 2026-11-03 16:47:10 +00:00
frontend initial commit 2026-11-03 16:47:10 +00:00
tests initial commit 2026-11-03 16:47:10 +00:00
.gitignore initial commit 2026-11-03 16:47:10 +00:00
docker-compose.yml initial commit 2026-11-03 16:47:10 +00:00
PROTOCOL.md initial commit 2026-11-03 16:47:10 +00:00
README.md initial commit 2026-11-03 16:47:10 +00:00
run-tests.sh initial commit 2026-11-03 16:47:10 +00:00

MyBattleship

A two-player, real-time online Battleship game built from the Group 1 design documents (Group1Assign2.pdf and RefinedRequirementsSpecification-Group1.pdf).

The game is server-authoritative: all placement, shot resolution, mine chains, scoring, turn timers and win detection happen on the Java backend. The React client is a renderer that sends intents over WebSocket.

Game flow


What is implemented

  • React single-page client with five screens: home/lobby browser, waiting room, fleet deployment, tactical combat and the win/loss overlay.
  • Java 21 backend with no runtime dependencies: a small HTTP + WebSocket server, an authoritative game engine and an in-memory lobby service.
  • 10 × 10 boards with three icebergs per player and five mines seeded after both fleets deploy.
  • Fleet of five ships: Carrier 5, Battleship 4, Cruiser 3, Submarine 2, Destroyer 1.
  • Interactive placement with hover previews, green/red validity highlighting, R rotation, server-side rejection reasons and a fleet dock.
  • Fog-of-war combat: hidden enemy ships and mines; misses, hits, iceberg reveals, cross-shaped mine blasts and chain reactions.
  • 30-second turn timer, automatic turn pass, random first player and disconnect grace/forfeit.
  • Scoring and persistent scoreboard: per-match score plus lifetime wins/losses and ships sunk, kept even after lobbies expire.
  • Lobby lifecycle: public/private lobbies, six-character codes, ready check, host start, idle cleanup and a finished-lobby TTL so results can be reviewed.
  • Rematch flow, session resume after a refresh, reconnect handling, battle log and a synthesised audio pipeline (music plus water/hit/mine/ice effects).
  • Docker deployment matching the design's Nginx → Java architecture, with WebSocket proxying and an HTTPS-ready reverse-proxy boundary.

Quick start

Option A — single Java process (production-style local run)

Requirements: Java 21+ and Node 22+ (Vite 8 / React 19).

# Build the React bundle once
cd frontend
npm install
npm run build
cd ..

# Compile and start the Java server (serves frontend/dist on :8080)
./backend/run.sh

Open http://localhost:8080. The backend serves the React build, the /api endpoints and the /ws WebSocket on the same port.

Option B — frontend dev server with hot reload

Terminal 1:

./backend/run.sh

Terminal 2:

cd frontend
npm install
npm run dev

Open http://localhost:5173. Vite proxies /ws and /api to the Java server on :8080.

Option C — Docker Compose

docker compose up --build

Open http://localhost:8080. Nginx serves the React build and proxies /ws and /api to the Java container, matching the deployment diagram in the design document. Put this stack behind a TLS-terminating reverse proxy for HTTPS.

Docker error: Extension DNAT revision 0 not supported

This is a host Docker/kernel problem, not a project problem. Docker must install an iptables DNAT rule for ports: "8080:80". If it reports:

Unable to enable DNAT rule ... iptables ... Extension DNAT revision 0 not supported

the running kernel does not have matching netfilter modules available. Check:

uname -r          # running kernel
ls /lib/modules   # kernels that actually have modules installed

If those do not match (for example running 7.2.11-arch1-1 while only 7.2.14-arch1-1 is installed), reboot into the installed kernel or install the matching kernel modules, then:

sudo modprobe xt_nat
sudo systemctl restart docker
docker compose up --build

Do not change the compose file to network_mode: host for this — published port mapping requires Docker's NAT support, and the error will disappear once the host kernel and its modules match.


How to play

  1. Enter a commander name.
  2. Create a lobby (set an optional password to keep it private) or join an open lobby. Alternatively, share the six-character lobby code and use Join by code.
  3. Both players click I'm Ready (the host can also use Start Game once both are ready). The server creates both boards and seeds three icebergs.
  4. Deploy all five ships. Icebergs and existing hulls block placement; the preview turns red and the server rejects invalid placements with the exact blocking square. Press R or use Rotate to flip the selected ship.
  5. Once both fleets are deployed, the server seeds five mines per board, picks a random first player and starts the 30-second turn clock.
  6. Click a square in enemy waters. Misses, hits, icebergs, mines and chain explosions are resolved centrally. A valid shot ends your turn; an invalid shot (iceberg, already fired, out of bounds) keeps it.
  7. Sink all five enemy ships to win. The overlay shows final score, match duration, enemy losses and lifetime record. Choose Rematch or Return to Lobby.

Scoring

Event Points
Miss 10
Hit a ship segment 100
Sink a ship +300 bonus
Detonate a mine 150 (+300 per ship sunk in the blast)
Win +500

Scores are per match; the scoreboard also stores lifetime totals.


Project structure

mybattleship/
├── backend/
│   ├── src/main/java/
│   │   ├── gameengine/
│   │   │   ├── model/        Board, BoardTile, Ship, Coordinate, enums
│   │   │   ├── placement/    PlacementValidator
│   │   │   ├── combat/       ShotProcessingEngine, ExplosivesLogic, CombatSession
│   │   │   ├── lobby/        GameLobby, LobbyManager, ScoreBoard, Player
│   │   │   └── rules/        GameRulesController
│   │   └── server/           Main, GameServer, WebSocketServer, Json, ClientSession
│   ├── test/java/            EngineTests (dependency-free engine suite)
│   ├── build.sh / run.sh
│   └── Dockerfile
├── frontend/
│   ├── src/
│   │   ├── App.jsx           socket orchestration and screen routing
│   │   ├── components/       Home, Lobby, Placement, Game, Board, FleetPanel, overlay
│   │   ├── lib/              socket hook, audio synthesiser, game helpers
│   │   └── styles.css        full visual system
│   ├── vite.config.js
│   ├── nginx.conf / Dockerfile
│   └── package.json
├── tests/integration.mjs     full protocol/gameplay E2E test
├── PROTOCOL.md               WebSocket message contract
├── docker-compose.yml
└── run-tests.sh

Architecture

Browser (React)
   │  JSON intents over WebSocket (/ws)
   ▼
Nginx (Docker) ── serves frontend/dist, proxies /ws and /api
   │
   ▼
GameServer (Java 21)
   ├── Session registry / resume tokens
   ├── LobbyManager ── GameLobby × N ── ScoreBoard
   ├── PlacementValidator + GameRulesController
   └── CombatSession ── ShotProcessingEngine ── ExplosivesLogic
        │
        └── authoritative Board[10][10] × 2
  • A single-threaded game executor serialises all game mutations, making turn resolution race-free even though WebSocket connections are concurrent.
  • Each client receives a personalised gameState with fog-of-war applied to the opponent board.
  • All action messages are validated against the server's state. The client never computes damage, mine chains, scores or turn changes.
  • See PROTOCOL.md for the complete message reference.

Design documents → implementation

Design artefact Implementation
GameServer controller server/GameServer.java
GameLobby, Player, LobbyStatus gameengine/lobby/
Board, BoardTile, Ship, Shot payload gameengine/model/
PlacementValidator boundary/collision loop gameengine/placement/PlacementValidator.java
ShotProcessingEngine + ShotOutcome gameengine/combat/ShotProcessingEngine.java
ExplosivesLogic cross blast gameengine/combat/ExplosivesLogic.java
ScoreBoard, LobbyManager cleanup gameengine/lobby/ScoreBoard.java, LobbyManager.java
GameRulesController gameengine/rules/GameRulesController.java
Sound pipeline (client) frontend/src/lib/audio.js
Nginx + Java deployment docker-compose.yml, frontend/nginx.conf

Deliberate choices / deviations

  • React was requested by the user; Vite is used for the build. The design documentation described a generic client frontend.
  • No framework backend. The documents specify Java; the server uses plain Java 21 (com.sun.net.httpserver is not even needed — HTTP and WebSocket are implemented directly) so it has zero third-party runtime dependencies and is easy to build with javac.
  • Ship lengths follow the explicit refined requirement (one each of 1–5) rather than the illustrative health-dot counts in the mockup.
  • Finished lobbies remain briefly (assign2's finishedTtl) so both players can see the result and choose a rematch, even though one scenario in the refined specification describes immediate deletion. Assign2 takes precedence.
  • Audio is synthesised with Web Audio rather than shipped asset files, so the game remains fully offline-capable. Effects map to water, ship impacts, icebergs and mine blasts; a looping sea-shanty style track plays quietly.
  • Scoring is a documented, deterministic algorithm (above) because the documents specify a score but do not prescribe exact points.

Configuration

Environment variable Default Meaning
PORT 8080 HTTP/WebSocket port
FRONTEND_DIR frontend/dist (auto-detected) static bundle to serve
TURN_SECONDS 30 turn timer (minimum 5 in code)
DISCONNECT_GRACE_SECONDS 30 reconnect window before forfeit
IDLE_TIMEOUT_SECONDS 600 waiting/abandoned lobby cleanup
FINISHED_TTL_SECONDS 300 finished-lobby retention
TEST_PORT 8091 port used by the integration test

HTTP helpers: GET /api/health, GET /api/lobbies, GET /api/stats, GET /api/config.


Tests

./run-tests.sh

This compiles the backend and runs:

  1. EngineTests — placement bounds/iceberg collisions, mine blast shape and chain reactions, turn consumption, invalid-shot handling, winning shot, scoreboard accumulation and lobby lifecycle.
  2. tests/integration.mjs — a full two-player protocol test. It spawns a server on a test port and verifies lobby creation, full-lobby rejection, fog-of-war, invalid placement, deployment, turn ownership, iceberg shots, scoring, turn timeout, a complete match, game-over payloads, rematch, disconnect forfeit, session resume and the HTTP API.

The UI was additionally exercised with two headless Firefox sessions (create → join → ready → deploy → full match → win/loss overlays).


Limitations / next steps

  • Game state is in memory; a production deployment would add Redis or a database for multi-instance scale and durable scoreboards.
  • Lobby passwords are stored in memory in plain text. Add hashing and rate limiting before exposing the service publicly.
  • TLS is expected to be terminated by the reverse proxy in front of the compose stack.
  • There is no spectator mode or chat; the design documents only require two players.