Skip to main content
The N-party Battleship tutorial is a focused mental-model tutorial. It teaches hidden state: an app can update private state and reveal only the facts a product policy allows, without giving the backend a full plaintext god view. Runnable source:

What this teaches

Battleship is useful because the privacy failure is obvious. A hidden-board game should not require the service, spectators, support tools, or analytics jobs to see every unshot ship location. The tutorial isolates this product shape:
Use it after the Rust SDK quickstart or the private matchmaking app when you want to understand private state transitions in isolation.

Privacy boundary

The tutorial’s core lesson is recipient specificity. “Reveal hit/miss” is incomplete until the product says who receives it and when.

Reveal policies

The tutorial compares three policies:
  1. Public combat log
    • Everyone sees the coordinate and result.
    • The board still stays hidden unless the game explicitly allows review.
  2. Private result
    • Attacker and target see the detailed hit/miss result.
    • Bystanders may see only that a turn happened.
  3. Delayed reveal
    • Details stay hidden during live play.
    • Selected logs may open after elimination or game end.
None of these is universally correct. The point is that the policy is explicit before the app is implemented.

Code map

Read the files in this order:
  1. normal/battleship.rs: see the omniscient-referee backend.
  2. private/battleship.rs: see recipient-specific authorized views.
  3. src/client.rs: see the attacker and target-board payloads.
  4. src/app.rs: see the Rust service generate the local run, attach inputs, and decode the shot result.
  5. src/main.stfl: see oblivious lookup, private hit-mask update, private remaining-health update, and opened output fields.
  6. tests/: see reveal-policy behavior and hidden-state expectations.

Run it

From the tutorial repository root:
Then run the Stoffel project directly:
The direct CLI run returns the opened shot outcome encoded by the tutorial.

What not to copy

Do not copy Battleship as a claim that every game needs MPC. Copy the hidden-state design habit:
  1. Separate public liveness state from private app state.
  2. Define the recipient-specific view before coding.
  3. Update private state without turning it into a backend-readable board.
  4. Open only the facts named by the reveal policy.
  5. Treat logs, support tools, analytics, and spectators as product surfaces with explicit access rules.

Return to the app-shaped path

After this focused tutorial, return to Build a private matchmaking service to see how private computation fits into a richer Rust service, or use the Rust SDK quickstart for the smallest app-shaped Rust service boundary. Use Private lottery reveal boundary for the smaller “one opened result” mental model.