# Saved games A game played against the computer (or on one device) is kept as it is played, and can be picked up again after the app has been closed. ## What the player sees - **Main menu → Continue.** Each game left half-played is listed, most recent first ("Chess · saved 5 minutes ago"); tapping it resumes. - **A game's setup screen** shows a *Game in progress* card with **Resume** and **Discard**. Starting a new game from that screen replaces the saved one. - **Leaving the table** (the back arrow, or the app being closed or sent to the background) keeps the position. **End game → End the game** is the deliberate way to throw it away. - A game that is **finished** is not kept. - A **networked** table is not kept: the other player's seat cannot be held for them. Only a table with no remote human at it (`PlayerKind.HUMAN_REMOTE`) is saved. One slot per game: there is one saved Chess game, one saved Katan game, and so on. ## How it works | Piece | Where | Does | | --- | --- | --- | | `SavedMatch`, `SavedGameStore` | `game/engine/SavedGame.kt` | one JSON file per game under `filesDir/saved-games/`, written atomically (temp file, then renamed); an unreadable file is deleted and read as absent | | `MatchController.onHostState`, `restore` | `net/MatchController.kt` | the host reports every position it reaches; `restore(json)` starts the table from a saved position instead of dealing | | `MatchSaver` | `net/MatchSaver.kt` | takes the newest position and writes it off the main thread; `flush()` writes synchronously on leaving or on `ON_STOP`; `discard()` forgets the game | | `StartMatch` | `ui/PlayScreen.kt` | wires the two together for every game; consumes the resume state once, so a solitaire "new deal" is not put back | | `LocalEndGameHandle` | `ui/EndGameHandle.kt` | how each *End game* dialog tells the table to forget its save | What is saved is `rules.encodeState` of the **host's true state** (hidden cards included), plus the `TableConfig` (seed, seats, options) and the local seat. Nothing in the store knows which game it is holding, so a new game is saved with no work, provided its state encodes. A save this build cannot decode (one written by an older version whose state has since changed shape) is thrown away and a fresh game is dealt. ## Tests - `SavedGameStoreTest` — the files: round trip, one slot, ordering, corruption, a cut-off write. - `MatchSaverTest` — saving as a table is played, resuming from a save, finished games, flush, discard. - `SaveRoundTripAllGamesTest` — **every game in the catalogue**: the whole state is encoded and decoded at every move of a computer-played game, and play carries on from the decoded copy. A new game should be added to it.