Files
battleship/docs/GAME_DECISIONS.md
T

83 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Production decisions
This document is the binding implementation contract for the MVP. It resolves
the choices left open in `MVP.md`; future code must not widen these limits
without updating this document and `RESOURCE_BUDGET.md`.
## Platform and ownership
- Target: ESP32-C6FH4 (4 MB flash, no PSRAM assumed), custom 2 MiB app and
1,984 KiB LittleFS partitions.
- Stack: PlatformIO Core 6.1.19, `espressif32` 7.0.1, ESP-IDF 6.0.1,
built-in `esp_http_server` WebSocket support, and `esp_littlefs` 1.20.4.
- The ESP32 is authoritative. HTTP and WebSocket callbacks only validate and
enqueue commands; one application task owns game, session, and statistics
mutation.
- Internal coordinates are unsigned `x` and `y` in `[0, 9]`. The browser
renders Russian column labels; it never sends them.
## Fixed game rules
- Board size is 10 by 10. Each side has ships of lengths `4, 3, 3, 2, 2, 2,
1, 1, 1, 1`, placed randomly by the server without touching, including
diagonally.
- A hit retains the turn. A miss changes it. Sinking a ship marks its
surrounding cells as misses. A repeated shot is rejected without state
change. First turn and each fleet are independently random.
- Modes are `HUMAN_VS_HUMAN` and `HUMAN_VS_BOT`. The bot is `ESP32`; it uses
only previously visible shot results and acts after a bounded 500900 ms
server timer.
- Phases are `LOBBY`, `PREPARING`, `IN_PROGRESS`, `FINISHED`, and
`REMATCH_WAIT`. Every accepted state change increments `version`.
## Sessions and capacity
- Roles are `PLAYER_1`, `PLAYER_2`, and `SPECTATOR`; capacity is two players
and eight spectators. New clients become spectators when player slots are
occupied, subject to the spectator limit.
- Display names are 120 Unicode scalar values after removing controls and
markup. The server stores a bounded UTF-8 encoding of at most 80 bytes and
escapes it before HTML rendering.
- A session token is 16 cryptographically random bytes, transported as 32
lowercase hexadecimal characters. It is opaque, never logged, and remains
valid only until board reboot or explicit slot release.
- Active player sessions survive disconnects. Spectator disconnects free their
slot immediately. A player may resume only with the same token; a resumed
session receives a complete role-safe snapshot.
## Lifecycle
1. `join` assigns player 1 if vacant and requested, then player 2 only in the
two-player mode; otherwise it assigns spectator. `resume` never changes a
role.
2. Player 1 may configure a mode only in `LOBBY`. Switching to bot reserves
player 2 as `ESP32`; switching back requires no human player 2 conflict.
3. Player 1 may start only when player 2 is present in human mode, or bot mode
is selected. `PREPARING` is internal and advances atomically to
`IN_PROGRESS` after both fleets validate.
4. A player disconnect does not abort a game. The game waits for that player;
the bot continues only when it is the bot's turn. Player 1 may issue the
explicit `abort` command while a human opponent is disconnected, returning
to `LOBBY` and incrementing `version`.
5. Destroying all ten opponent ships transitions to `FINISHED`, records match
and cumulative statistics, reveals both boards, and rejects shots.
6. In `FINISHED`, a player may confirm `rematch`. Human mode requires both
player confirmations; bot mode requires player 1 only. The server enters
`REMATCH_WAIT` until the required confirmations exist, then creates a new
game ID and returns to `PREPARING`. Names, roles, and cumulative statistics
remain; per-match statistics reset.
7. Board reboot clears sessions, game, and all statistics. Wi-Fi loss does not
mutate them; clients use HTTP polling while WebSocket reconnects.
## Visibility and transport
- Player 1 receives its complete board and only known opponent shot results;
player 2 is symmetric. Spectators see known shot results from both boards.
Unhit ships are replaced by `0` in every unauthorized view.
- `FINISHED` is the sole phase that exposes full boards to every role.
- HTTP commands include the token in the JSON body. WebSocket authentication
is the first `hello` message; the token is never placed in a URL or log.
- WebSocket reconnect delay is 1, 2, 5, then 10 seconds. HTTP polls a complete
snapshot every two seconds only while WebSocket is unavailable. Any skipped
version triggers a full snapshot request.