feat: honest AI opponent in quick game
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Successful in 49s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m12s

New Game's quick game gains an explicit opponent selector — 🤖 AI (default)
or 👤 Random player. AI starts a game seated with a pooled robot that joins
and moves at once: no per-move timeout (a 7-day inactivity loss reusing the
turn-timeout sweeper), chat/nudge disabled, no statistics, the opponent shown
as 🤖 everywhere. The random path (disguised robot) is unchanged.

Driven by one game flag (games.vs_ai), set only on AI-started games so the
disguised path is never revealed; Matchmaker.StartVsAI seats the robot
directly (no open pool); the robot replies event-driven via the game service's
after-commit/after-create hook. Wire: vs_ai on EnqueueRequest + GameView.
This commit is contained in:
Ilia Denisov
2026-06-15 20:14:24 +02:00
parent 91d5c341ef
commit aa765a0c06
56 changed files with 901 additions and 86 deletions
+14 -2
View File
@@ -84,8 +84,14 @@ Russian → Scrabble + Erudite; a bilingual service shows all three, and the web
unrestricted). Variants are shown by their **display name** — both Scrabble variants read
"Scrabble"/"Скрэббл" and Erudit reads "Erudite"/"Эрудит" (by the interface language), and
the same name titles the in-game screen. This gates only **starting** a new game — both auto-match and a friend
invitation — so a player still sees and plays existing games of any language. Auto-match
(always 2 players) drops you **straight into the game and you wait inside it**: if it is your turn you
invitation — so a player still sees and plays existing games of any language.
**Quick game** lets you choose your opponent — an **AI** (the default) or a **random player**.
With **AI** you start at once against a 🤖 that joins and replies immediately: there is no waiting,
chat and nudge are off, add-friend is never shown, and the word-check tool still works; instead of a
per-move clock you lose only after **7 days without a move** (so you can abandon an AI game freely,
and the AI itself never runs out of time). Choosing a **random player** is auto-match
(always 2 players), which drops you **straight into the game and you wait inside it**: if it is your turn you
can already move, otherwise you watch your tiles. While no opponent has joined, the opponent card (and
the game's row in the lobby) reads **"searching for opponent"**, and resign, chat and nudge are
unavailable. Another player searching the same variant and rule joins your game; failing that, a robot
@@ -142,6 +148,12 @@ carries a human-like, language-appropriate name (a Russian game draws mostly Rus
names); it does not chat, and **silently ignores friend requests** — a request to a
robot stays pending and expires, exactly like a human who never responds.
The same robot also backs the **honest-AI quick game** the player chooses directly (above). There
it makes no pretence: it is shown as **🤖** everywhere, joins and moves at once (no thinking time
or night pause), keeps the same strength (it still plays to win only about 40% of the time), and
chat, nudge and add-friend are off. AI games are **practice** — they never count toward a player's
statistics.
### Social: friends, block, chat, nudge
Become friends in two ways: redeem a **one-time code** the other player issues (six
digits, valid for twelve hours), or send a **request to someone you have played