feat(stats): best-move word, moves & hint-share, and a hint-count fix (#81)
The statistics screen gains real depth, plus a hint-count bug fix found along the way. - Best move per variant: the screen shows the actual best-move word (drawn as game tiles; a wildcard shows its letter but no value), broken down by game variant, empty variants omitted. New account_best_move table, written at game finish. - Moves & hint share: two new lifetime tiles — the player's play count and the share of plays that used a hint — from summed account_stats counters (moves, hints_used). Honest-AI games are excluded, like the rest of the stats. - Hint-count fix: the in-game hint badge no longer goes stale across games. The global wallet now rides the wire apart from the per-game allowance (wallet_balance on StateView/HintResult/StatsView), so the client reads the live wallet rather than a per-game snapshot; game_players.hints_used now counts every hint (allowance + wallet), its true per-game total. - Account merge: sums the new moves/hints_used counters and merges the per-variant best moves (higher score kept), which it previously dropped. - Admin: the user card shows Moves and Hints used. - UI polish: tab/label wording, game-over text, and e2e selectors hardened against label changes. All wire additions are trailing (backward-compatible). Docs (ARCHITECTURE, FUNCTIONAL +ru, UISN_DESIGN) updated in step.
This commit was merged in pull request #81.
This commit is contained in:
@@ -91,15 +91,63 @@ func encodeRedeemResult(r backendclient.RedeemResultResp) []byte {
|
||||
return b.FinishedBytes()
|
||||
}
|
||||
|
||||
// encodeStats builds a StatsView payload.
|
||||
// buildBestMoveTile builds a BestMoveTile table and returns its offset.
|
||||
func buildBestMoveTile(b *flatbuffers.Builder, t backendclient.BestMoveTileResp) flatbuffers.UOffsetT {
|
||||
letter := b.CreateString(t.Letter)
|
||||
fb.BestMoveTileStart(b)
|
||||
fb.BestMoveTileAddLetter(b, letter)
|
||||
fb.BestMoveTileAddValue(b, int32(t.Value))
|
||||
fb.BestMoveTileAddBlank(b, t.Blank)
|
||||
return fb.BestMoveTileEnd(b)
|
||||
}
|
||||
|
||||
// buildBestMove builds a BestMoveView table — its word tile vector first, per the
|
||||
// bottom-up rule — and returns its offset.
|
||||
func buildBestMove(b *flatbuffers.Builder, m backendclient.BestMoveResp) flatbuffers.UOffsetT {
|
||||
tiles := make([]flatbuffers.UOffsetT, len(m.Word))
|
||||
for i, t := range m.Word {
|
||||
tiles[i] = buildBestMoveTile(b, t)
|
||||
}
|
||||
fb.BestMoveViewStartWordVector(b, len(tiles))
|
||||
for i := len(tiles) - 1; i >= 0; i-- {
|
||||
b.PrependUOffsetT(tiles[i])
|
||||
}
|
||||
word := b.EndVector(len(tiles))
|
||||
variant := b.CreateString(m.Variant)
|
||||
fb.BestMoveViewStart(b)
|
||||
fb.BestMoveViewAddVariant(b, variant)
|
||||
fb.BestMoveViewAddScore(b, int32(m.Score))
|
||||
fb.BestMoveViewAddWord(b, word)
|
||||
return fb.BestMoveViewEnd(b)
|
||||
}
|
||||
|
||||
// encodeStats builds a StatsView payload, embedding the per-variant best moves (each a
|
||||
// BestMoveView with its word tiles) when present.
|
||||
func encodeStats(r backendclient.StatsResp) []byte {
|
||||
b := flatbuffers.NewBuilder(64)
|
||||
b := flatbuffers.NewBuilder(256)
|
||||
var bestMoves flatbuffers.UOffsetT
|
||||
if len(r.BestMoves) > 0 {
|
||||
offs := make([]flatbuffers.UOffsetT, len(r.BestMoves))
|
||||
for i, m := range r.BestMoves {
|
||||
offs[i] = buildBestMove(b, m)
|
||||
}
|
||||
fb.StatsViewStartBestMovesVector(b, len(offs))
|
||||
for i := len(offs) - 1; i >= 0; i-- {
|
||||
b.PrependUOffsetT(offs[i])
|
||||
}
|
||||
bestMoves = b.EndVector(len(offs))
|
||||
}
|
||||
fb.StatsViewStart(b)
|
||||
fb.StatsViewAddWins(b, int32(r.Wins))
|
||||
fb.StatsViewAddLosses(b, int32(r.Losses))
|
||||
fb.StatsViewAddDraws(b, int32(r.Draws))
|
||||
fb.StatsViewAddMaxGamePoints(b, int32(r.MaxGamePoints))
|
||||
fb.StatsViewAddMaxWordPoints(b, int32(r.MaxWordPoints))
|
||||
fb.StatsViewAddMoves(b, int32(r.Moves))
|
||||
fb.StatsViewAddHintsUsed(b, int32(r.HintsUsed))
|
||||
if len(r.BestMoves) > 0 {
|
||||
fb.StatsViewAddBestMoves(b, bestMoves)
|
||||
}
|
||||
b.Finish(fb.StatsViewEnd(b))
|
||||
return b.FinishedBytes()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user