feat(game): official first-move tile draw + admin step-by-step replay
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 17s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m19s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 17s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m19s
Decide who moves first by the official rule: each seated player draws one tile, the one closest to "A" leads (a blank beats every letter), ties re-drawing until a single leader remains. Each draw uses honest per-draw crypto/rand entropy (not the deterministic bag seed), so the recorded draw — not a seed — is the only account of the outcome. The leader takes seat 0, so the engine and journal replay are unchanged. The draw is recorded with the game (game_setup_draws, migration 00013) for future tournaments, designed as a discrete "player N draws a tile" step. Friend/AI games draw at creation. Auto-match draws when the game opens, against a synthetic uuid.Nil opponent whose draw rows (NULL account_id) are back-filled to the real opponent on join — so the opener's seat is fixed up front and the existing open-game pre-move is preserved with no reseating. Admin /_gm/games/:id gains the recorded draw list and a simple step-by-step board replay (game.ReplayTimeline + a vanilla-JS stepper): a board with A-O/1-15 headers and highlighted premium squares, placed letters with their tile value as a subscript, rack panels around the board (seat 0 top, 1 bottom, 2 left, 3 right) with the current player highlighted, and a per-move log with the tiles drawn and the bag remainder. Docs: ARCHITECTURE §6/§9, FUNCTIONAL (+_ru), PRERELEASE (FM row), design spec.
This commit is contained in:
@@ -268,6 +268,27 @@ type GameDetailView struct {
|
||||
// RobotTargetPct is the configured global play-to-win rate, in percent.
|
||||
HasRobot bool
|
||||
RobotTargetPct int
|
||||
// ReplayJSON is the game-replay payload (board, seats, per-step racks/scores/bag) the
|
||||
// game_detail page feeds to its vanilla-JS stepper; HasReplay gates the replay section.
|
||||
ReplayJSON template.JS
|
||||
HasReplay bool
|
||||
// SetupDraws is the first-move draw — one row per tile drawn (docs/ARCHITECTURE.md §6) —
|
||||
// and FirstMover is the resolved name of the seat-0 player the draw elected.
|
||||
SetupDraws []SetupDrawRow
|
||||
FirstMover string
|
||||
}
|
||||
|
||||
// SetupDrawRow is one tile drawn in the first-move seeding (docs/ARCHITECTURE.md §6): the
|
||||
// round, the player (Name/AccountID, or "(opponent)" with an empty AccountID for an
|
||||
// auto-match synthetic draw not yet back-filled), the drawn letter (upper-cased; "?" for a
|
||||
// blank) and its draw rank.
|
||||
type SetupDrawRow struct {
|
||||
Round int
|
||||
Name string
|
||||
AccountID string
|
||||
Letter string
|
||||
Blank bool
|
||||
Rank int
|
||||
}
|
||||
|
||||
// SeatRow is one seat of a game. For a robot seat (IsRobot) RobotIntent is the game's
|
||||
|
||||
Reference in New Issue
Block a user