# 问题 5:打牌顺序(标准德州扑克行动顺序调查) > 用户原话:“打牌顺序好像有点问题……现在的逻辑每次都从庄家的下一位开始,但是标准德州扑克是这样的吗?” ## 标准德州扑克的行动顺序(权威规则) ### 翻牌前(preflop) - 小盲(SB)在大盲(BB)**左边**第一个座位,大盲在 SB 左边。 - **第一个行动者 = 大盲左边的玩家(UTG,Under The Gun)**,即顺时针从庄家(按钮)数:庄家 → SB → BB → **UTG 先行动**。 - 行动顺时针进行:UTG → … → SB → BB。 - **大盲有“BB option”**:若无人加注,轮到大盲时他可以选择过牌(看注)或加注。 ### 翻牌后(flop / turn / river) - **第一个行动者 = 小盲(按钮左边第一个仍在手的玩家)**。 - 行动顺时针:SB → … → 庄家(按钮)。 - 即:**翻牌后由庄家左边第一个玩家先行动**(与翻牌前不同,翻牌前是 BB 左边)。 ### 每次有人加注(raise)之后 - 加注会**重置所有其他玩家的“已行动”标记**(他们必须再次面对这个加注做决定)。 - 行动从**加注者顺时针的下一位**开始,逐一回到加注者之前那一位; 所有人都对当前最高注 `call/raise/fold` 且下注额一致、且都“已行动”后,该街才结束。 - 若某人 all-in 且金额不足以构成完整加注(incomplete raise),则**不重置**已行动者的标记 (已行动且面对未匹配注的人只能 call 或 fold,不能再加注)—— 本项目已实现此规则(`holdem.ts:438`)。 ### 单挑(heads-up)特例 - 只有两人时:**庄家 = 小盲**,大盲是另一人。 - 翻牌前:庄家(SB)**先**行动。 - 翻牌后:大盲先行动(因为大盲是“庄家左边第一个”)。 ## 现有代码核对(`holdem.ts`) | 街 | 代码 `firstToAct` | 是否标准 | 结论 | |----|-------------------|----------|------| | preflop 多人 | `nextSeat(bbPid, canAct)` = BB 顺时针下一位 = **UTG** | ✅ 标准 | 正确 | | preflop 单挑 | `sbPid`(= 庄家)先行动 | ✅ 标准(单挑庄家先) | 正确 | | flop/turn/river 多人 | `nextSeat(dealerButton, canAct)` = 庄家顺时针第一人 = **SB** | ✅ 标准 | 正确 | | flop/turn/river 单挑 | `nextSeat(dealerButton, canAct)` = 大盲 | ✅ 标准(单挑大盲先) | 正确 | ### 每次 raise 后的顺序 - `raiseMove`:完整加注时 `for pid: G.acted[pid] = false`(`holdem.ts:443`),即重置其他人的已行动标记 → ✅ 标准。 - `advance()` → `nextActor(G, ctx)` = `nextSeat(ctx.currentPlayer, canAct)`(`holdem.ts:230`): 从**当前行动者(加注者)顺时针下一位**继续 → ✅ 标准。 - `roundComplete` 要求全部 `acted && betThisRound === currentBet` → ✅ 标准(不完整加注不重置已行动者也已处理)。 ## 调查结论 **现有代码的行动顺序实际上符合标准德州扑克规则**(preflop=UTG、postflop=SB、raise 后重置并顺时针推进)。 用户感知到的“每次都从庄家的下一位开始”可能来自以下混淆之一: 1. **单挑时庄家先行动(preflop)** 被误以为“从庄家下一位开始”——其实单挑就是庄家(SB)先动,标准如此。 2. **postflop 从 SB(庄家下一位)开始** 被当成“所有街都从庄家下一位”——但 preflop 是从 UTG(庄家下两位),两街起点不同,代码已区分,属正确。 3. 可能真实存在的 bug 不在“首行动者”,而在 **`advance` 的流转**(例如 `events.endTurn({next})` 在 `ActivePlayers.ALL` 下是否被 boardgame.io 正确采纳)。 ### 仍需落实的验证(防误判) - **加一个确定性集成测试**,打印每一街的 currentPlayer 序列,人工核对: - 3 人:preflop 顺序应为 `UTG(0) → SB(1) → BB(2) →`(BB option)→ flop 起 `SB(1) → ...`。 - 在某玩家中途 raise 后,确认顺序从 raise 者下家继续、且其他人被重新要求行动。 - 若测试发现 `endTurn({next})` 未被采纳(currentPlayer 回到错误座位),则问题在 boardgame.io 的 `ActivePlayers.ALL` + `turn.order` 交互,需改用 `events.setActivePlayers` 或显式 `endTurn` 序列。 ## 拟采用方案 1. 先写 **顺序验证测试**(不改逻辑),确认当前行为。 2. 若测试通过与标准一致 → **无需改顺序逻辑**,仅在文档/UI 上澄清(例如在行动条显示“(庄家左 X 位行动)”), 并在 `HoldemBoard` 高亮当前行动者(已有 `data-actor`)。 3. 若测试暴露异常 → 定位 `advance`/`turn.order` 问题并修复(届时更新本文件结论)。 > 一句话答复用户:**标准德州扑克不是“每次都从庄家下一位”**——翻牌前从大盲下一位(UTG),翻牌后从小盲(庄家下一位); > 当前代码已按此实现,但我会用测试再次核实并保留证据。