Stage 5: robot opponent (pool, seed-derived strategy, move driver, matchmaker substitution)
- internal/robot: durable kind='robot' account pool (migration 00004); every per-game and per-turn choice derived deterministically from the game seed (restart-stable FNV mix); a background move driver; margin targeting (band 1-30, closest-to-band); right-skewed [2,90]min delays (median ~10m); opponent-anchored sleep with +/-3h drift; daytime nudge reply + proactive 12h nudge; friend/chat blocked via profile toggles. - engine.Candidates (decoded ranked plays); game.Candidates + RobotTurns; social.LastNudgeAt. - matchmaker: 10s wait then robot substitution (reaper) + Poll delivery seam. - config (BACKEND_ROBOT_DRIVE_INTERVAL, BACKEND_LOBBY_ROBOT_WAIT, BACKEND_LOBBY_REAPER_INTERVAL); main wiring + boot-time pool provisioning. - metrics: robot account_stats (authoritative balance) + robot_games_finished_total OTel counter + per-finish log. - docs: PLAN, ARCHITECTURE, FUNCTIONAL(+ru), TESTING, README; account.go comment. - tests: robot strategy units, matchmaker reaper/Poll, engine.Candidates; inttest robot full-game / substitution / proactive-nudge.
This commit is contained in:
@@ -21,10 +21,12 @@ import (
|
||||
|
||||
// Identity kinds recognised by the backend. Email is modelled as an identity
|
||||
// alongside platform identities; its confirmed flag is driven by the email
|
||||
// confirm-code flow in a later stage.
|
||||
// confirm-code flow in a later stage. Robot is a synthetic kind: each pooled
|
||||
// robot opponent is a durable account bound to one robot identity (Stage 5).
|
||||
const (
|
||||
KindTelegram = "telegram"
|
||||
KindEmail = "email"
|
||||
KindRobot = "robot"
|
||||
)
|
||||
|
||||
// uniqueViolation is the PostgreSQL SQLSTATE for a unique-constraint violation.
|
||||
@@ -34,10 +36,12 @@ const uniqueViolation = "23505"
|
||||
var ErrNotFound = errors.New("account: not found")
|
||||
|
||||
// Account is a durable internal account. AwayStart and AwayEnd bound the daily
|
||||
// local-time window (in TimeZone) during which the player is asleep: the
|
||||
// turn-timeout sweeper does not auto-resign them inside it, and the robot reuses
|
||||
// it for its own sleep in a later stage. HintBalance is the player's wallet of
|
||||
// purchasable hints, spent after a game's per-seat allowance.
|
||||
// local-time window (in TimeZone) during which the player is asleep, so the
|
||||
// turn-timeout sweeper does not auto-resign them inside it. (The robot opponent's
|
||||
// own sleep is anchored to its human opponent's timezone with a per-game drift,
|
||||
// computed in internal/robot, not from a robot account's away window.) HintBalance
|
||||
// is the player's wallet of purchasable hints, spent after a game's per-seat
|
||||
// allowance.
|
||||
type Account struct {
|
||||
ID uuid.UUID
|
||||
DisplayName string
|
||||
|
||||
Reference in New Issue
Block a user