玩法
再沒有人獨自等待:認識一下這些常客
過去開一個房間就意味著獨自等到放棄。現在有十二位常客——真實的名字、固定的性格、像人一樣的節奏——會來把空位坐滿。

通俗版
在這次更新之前,從來沒有誰會加入你自己開的房間。你選好模式、開一張桌子,然後等待——而且多半是一個人等。更新前六週的資料很直白:
| 我們統計的內容 | 結果 |
|---|---|
| 玩家開了卻從未開局的房間 | 38 個 |
| 放棄前的平均等待時間 | 約 3.2 小時 |
| 一個已坐滿 4/4 卻仍未開局的房間 | 等了 2 天 |
| 有一名以上真人參與的已結束對局 | 231 局中的 46 局 |
現在桌子會自己坐滿。在你開房後的二十秒到四分鐘之間,就會有人坐下。十二位常客輪流出現在大廳裡——用的是普通暱稱,而不是"機器男爵"之類——而且每次遇到的都是同一個人:
- 固定的性格:同一個對手總是打得謹慎,或者總是把價叫得太高;
- 一個不是今早才編出來的註冊日期和經驗等級;
- 屬於自己的節奏——思考一到六秒,而不是像節拍器一樣固定兩秒;
- 偶爾在聊天裡說一句短話,而不是只發貼紙;
- 等待室裡不再有"bot"標籤,因為在牌桌上他們的表現就像玩家。
最後一個空位比其他位置等得更久——三到八分鐘——好讓真人還有時間坐進來。而如果所有人都已入座、房間卻安靜下來,它會在三分鐘後自行開局,而不是無限期地懸在那裡。
他們也會出現在排行榜上。既然他們要打真實的對局,這樣做才誠實——但他們每天能獲得的收益有嚴格上限,因此上升得像一個普通玩家,而不是刷榜。
技術細節
這十二個角色在遊戲守護程式啟動時以冪等方式建立,並用資料表本就支援的一個取值加以標記——因此整個功能沒有任何資料庫遷移,也沒有改動任何遊戲規則。
補位是排程器的一次 tick,而不是每個房間一個定時器。每個延遲都由以房間和座位為種子的隨機數推導而來,並錨定在資料庫中儲存的時間戳上,因此守護程式重啟後會沿用完全相同的計劃,而不會為已排定的房間重新抽取延遲:
ts
// scheduler.ts — seeded per (room, seat), anchored on a DB timestamp
const rng = createRng(`${game.id}:fill:${seat}`);
const isLastSeat = freeSeats === 1;
const delayMs = isLastSeat
? rng.int(LAST_SEAT_MIN_MS, LAST_SEAT_MAX_MS) // 3-8 min: leave room for a human
: rng.int(SEAT_MIN_MS, SEAT_MAX_MS); // 20 s - 4 min
if (Date.now() - Date.parse(game.created_at) < delayMs) continue;| 引數 | 取值 |
|---|---|
| 補位延遲 | 20 秒 – 4 分鐘,按座位取種子 |
| 最後一個座位 | 3 – 8 分鐘 |
| 坐滿且安靜後的自動開局 | 3 分鐘 |
| 機器人思考時間 | 1 – 6 秒,按角色縮放 |
| 角色經驗值 | 每個 UTC 日最多一次獎勵 |
有三個缺陷只有真正跑起來才暴露,而且任何單元測試都不會發現:已坐滿的房間被排除在補位的候選查詢之外,於是自動開局恰恰看不到它存在的意義所在;思考延遲的判定以對局為鍵而非以機器人為鍵,因此某一回合的暫停也會擋住同一個機器人的拍賣出價,直到它被自動跳過自己的出價視窗;而由守護程式開啟的對局不會把排程器從空閒退避中喚醒,導致從開局到第一次機器人擲骰之間隔了 11.6 秒,而不是 49 毫秒。
同一次更新還用一個真實介面替換了兩個編造的數字:大廳裡的"線上人數"此前統計的是緩衝區裡的聊天訊息條數,而首頁的"進行中的對局"則是 8 到 19 之間的隨機遊走。
