# 立直麻将(Mahjong)实现验证清单 > 依据:`docs/mahjong/00-rules.md`(雀魂标准,四麻+三麻,半庄战)。 > 目的:供人工审核实现与规则的一致性。逐条列出**期望行为 / 实现状态 / 证据 / 风险**。 > **版本**:v4(2026-10-03,P0+P1+P2 主要项修复完成;测试清单据实重核)。v1~v3 快照见 git 历史。 > 代码:`packages/engine/src/games/mahjong*.ts`、`apps/web/src/MahjongBoard.tsx`。 ## 图例 **级别(重要度)**:**P0** 核心(缺失/错误会导致对局不成立或算错分)|**P1** 重要|**P2** 次要/边角 **实现状态**:✅ 已实现且有单测 | 🟩 已实现(无专门单测/间接覆盖)| 🧪 已实现且浏览器冒烟实测 | ⚠️ 部分/简化/有边界问题 | ❌ 未实现 **测试**:麻将单测 **78 条**(`mahjong-tiles.test.ts` 16 · `mahjong-yaku.test.ts` 33 · `mahjong.test.ts` 29),引擎全量 **329 通过**(13 文件);联机 E2E `e2e/mahjong-multiplayer.spec.ts`(4 端)✅。逐条清单见文末 [Q. 测试清单](#q-测试清单test-inventory)。 --- ## 本轮(v2)修复总览:P0 + P1 全部完成 | 编号 | 级别 | 修复内容 | 状态 | | --- | --- | --- | --- | | P-01 | P0 | 立直后强制**摸切**(宣言回合可打任意牌,之后只能打摸到的牌) | ✅ 单测 | | P-02 | P0 | **鸣牌响应超时**:新增 `claimDeadline` + `claimTimeout` move + UI 全局倒计时,掉线也不卡死 | ✅ 单测 + 🧪 冒烟 | | P-03 | P1 | 途中流局:四风连打 / 四家立直 / 三家和了 / 四杠散了 | ✅ 单测 | | P-04 | P1 | 流局满贯(弃牌全幺九且未被鸣 → 按满贯自摸,不收供托/本场) | ✅ 单测 | | P-05 | P1 | 和了终局/听牌终局(All Last 亲家一位且达返点 + 连庄 → 终局) | ✅ 单测 | | P-06 | P1 | 立直后暗杠**听牌不变**校验 | ✅ 单测 | | P-07 | P1 | 三麻抢北(对拔北开荣和窗口,按抢杠计) | ✅ 单测 | | P-08 | P1 | 里宝牌/杠宝 UI 揭示(和了后 `uraIndicators` 公开并在结算面板展示) | ✅ 单测 + UI | | P-09 | P1 | 食替「筋」规则核对(现物 + 筋,含 123/789 边界) | ✅ 已覆盖 | | P-10 | P1 | 振听边界:被鸣走的自弃牌仍计入舍张振听(`furitenKinds` 只增不减) | ✅ 单测 | > 另修正 `waitingKinds`:扣除已锁定在副露中的牌(某牌种自占 4 张时不再作为听牌)。 --- ## v3(P2)修复总览 | 编号 | 级别 | 修复内容 | 状态 | | --- | --- | --- | --- | | R-01 | P2 | 三麻:碰/明杠后**未打牌前不可拔北**(`justCalledBy`) | ✅ 单测 | | R-02 | P2 | 加杠被抢后撤销为碰时,**扣回第 4 张牌的赤宝牌计数** | ✅ 单测 | | R-05 | P2 | 终局**顺位马 + 头名赏**(四麻 +15/+5/-5/-15 且赏+20;三麻 +15/0/-15 且赏+15) | ✅ 单测 | | R-06 | P2 | **听牌 / 振听提示**(`playerView` 暴露 `myWaits`/`myFuriten`,UI 显示) | ✅ 单测 + UI | | D9/N8 | P2 | **立直棒可视化**(顶栏按供托数画棍)+ 自己立直提示 | ✅ UI | | R-07 | P1 | **联机 4 端 E2E**(建房→开局→隐藏信息→轮转打牌) | ✅ Playwright | **本轮有意保持不变(合理简化,非遗漏)**:R-03 开牌/宝牌物理位置、C6 自摸牌显示、E15 杠宝时机、F14 人和(雀魂不采用)、O5 掉线超时(客户端驱动已够用)。 **独立阶段(未做)**:R-04 观战 + AI 补位。 --- ## A. 牌具与牌组 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | A1 | P0 | 四麻牌组 | 34 种 × 4 = 136 张 | ✅ | | A2 | P0 | 三麻牌组 | 去 2m~8m,108 张 | ✅ | | A3 | P0 | 四麻赤宝牌 | 红 5m/5p/5s 各 1(3 枚) | ✅ | | A4 | P0 | 三麻赤宝牌 | 红 5p/5s 各 1(2 枚) | ✅ | | A5 | P0 | 牌种索引与赤牌归一 | `0m→5m`;`red` 单独保留 | ✅ | | A6 | P1 | 宝牌指示映射 | 数牌 9→1;风循环;三元循环 | ✅ | | A7 | P2 | 手牌排序 | m→p→s→z,各 1..9 | ✅ | ## B. 牌山 / 王牌 / 指示牌 / 岭上 / 里宝 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | B1 | P0 | 王牌 | 14 张不参与摸牌 | ✅ | | B2 | P0 | 开局表宝牌指示牌 | 开局翻 1 张 | 🧪 | | B3 | P0 | 杠宝牌 | 每次杠翻新指示牌(≤5) | 🟩 | | B4 | P0 | 岭上牌 | 4 张,杠/拔北后补摸 | 🟩 | | B5 | P1 | 里宝牌 | 立直和了按里指示加番;和了后 UI 揭示 | ✅ 计分 + UI | | B6 | P0 | 牌山摸尽 | 荒牌流局 | ✅ | | B7 | P2 | 指示牌/岭上物理位置 | 与真实砌墙一致 | ⚠️ 简化布局 | | B8 | P1 | 杠宝翻开时机 | 抢杠则不翻 | 🟩 | ## C. 配牌与摸打 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | C1 | P0 | 发牌 | 每人 13 张,原子完成 | ✅ | | C2 | P0 | 庄家先摸 | 起手 14 张 | ✅ | | C3 | P0 | 摸打循环 | 打牌 → 下家摸牌 | ✅ | | C4 | P0 | 出牌合法性 | 只能打自己手牌 | 🟩 | | C5 | P1 | 摸牌并入 | 摸到的牌进手牌 | ✅ | | C6 | P2 | 自摸牌提示 | 显示「摸到」 | 🧪(手牌行内亦有,UX 小事) | ## D. 立直 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | D1 | P0 | 立直条件 | 门清 + 听牌 + ≥1000 | 🟩 | | D2 | P0 | 立直供托 | 支付 1000 计供托 | 🟩 | | D3 | P0 | **立直后摸切** | 立直后只能打刚摸的牌 | ✅ | | D4 | P0 | 一发 | 立直后一巡内和了且无鸣牌 | 🟩 | | D5 | P1 | 双立直 | 第一巡立直(2 番) | 🟩 | | D6 | P1 | 立直后暗杠 | 仅在不改变听牌时可暗杠 | ✅ | | D7 | P1 | 四家立直流局 | → 途中流局 | ✅ | | D8 | P1 | 里宝牌 | 立直和了加算里宝 | ✅ | | D9 | P2 | 立直棒可视化 | 桌面立直棒 | ✅ 顶栏棍形显示 + 自己立直提示 | ## E. 鸣牌 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | E1 | P0 | 吃 | 仅下家(四麻) | ✅🧪 | | E2 | P0 | 碰 | 任意家 | 🟩 | | E3 | P0 | 大明杠 | 3 手牌 + 弃牌 | 🟩 | | E4 | P0 | 暗杠 | 手持 4 张 | 🟩 | | E5 | P0 | 加杠 | 已碰 + 第 4 张,含抢杠窗口 | 🟩 | | E6 | P0 | 三麻不可吃 | 无吃选项 | 🟩 | | E7 | P0 | 食替禁止 | 现物 + 筋 | ✅ | | E8 | P0 | 鸣牌优先级 | 荣 > 碰/杠 > 吃 | ✅ | | E9 | P0 | 一炮多响(头跳) | 最近者 | ✅ | | E10 | P1 | 三家和了 | → 流局 | ✅ | | E11 | P1 | 四杠散了 | → 流局 | ✅ | | E12 | P1 | 三麻拔北 | 亮北 +1 宝、岭上 | 🟩 | | E13 | P1 | 抢北 | 对拔北荣和 | ✅ | | E14 | P2 | 碰后不可立即拔北 | 拔北近似鸣牌 | ✅ | | E15 | P2 | 明杠/加杠的宝牌与岭上顺序 | 符合规则 | 🟩 | ## F. 和了判定 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | F1 | P0 | 自摸 | 三家付点 | ✅ | | F2 | P0 | 荣和 | 放铳者付 | 🟩 | | F3 | P0 | **无役不能和** | 番=0 不能和(宝牌不算役) | ✅ | | F4 | P0 | 宝牌不计入役 | 无役即使有宝牌也不能和 | ✅ | | F5 | P0 | 振听·舍张 | 含被鸣走的自弃牌 | ✅ | | F6 | P0 | 振听·同巡 | 本轮放过 → 本轮不能再荣和 | 🟩 | | F7 | P0 | 振听·立直后 | 永久振听 | 🟩 | | F8 | P1 | 一发和了 | +1 番 | 🟩 | | F9 | P0 | 岭上开花 | 杠/拔北后岭上自摸 | 🟩 | | F10 | P0 | 抢杠 | 抢加杠荣和 | 🟩 | | F11 | P0 | 海底摸月 | 牌山最后自摸 | 🟩 | | F12 | P0 | 河底捞鱼 | 牌山最后弃牌荣和 | 🟩 | | F13 | P0 | 天和 / 地和 | 役满 | 🟩 | | F14 | P2 | 人和 | 古役 | ❌ 有意不做 | | F15 | P1 | 振听边界(被鸣走牌) | 仍计入 | ✅ | ## G. 宝牌 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | G1 | P0 | 表宝牌 | 每张 +1 番 | ✅ | | G2 | P0 | 赤宝牌 | 按实际持有(含副露) | ✅ | | G3 | P1 | 里宝牌 | 立直和了 + 里指示 | ✅ 计分 + UI | | G4 | P0 | 杠宝牌 | 每杠翻新 | 🟩 | | G5 | P1 | 拔北宝牌 | 每张拔出北 +1 | 🟩 | | G6 | P0 | 宝牌不是役 | — | ✅ | ## H. 役种(按番数) > ✅ 有单测;🟩 已实现未单测;❌ 未实现。 | 番 | 役种 | 状态 | | --- | --- | --- | | 1 番 | 立直 / 一发 / 门前清自摸和 / 平和 / 断幺九(有食断)/ 一杯口 / 役牌(含连风)/ 岭上 / 抢杠 / 海底 / 河底 | ✅ 平和·断幺·一杯口·役牌·门前清自摸;🟩 立直·一发·岭上·抢杠·海底·河底 | | 2 番 | 双立直 / 三色同顺 / 一气通贯 / 混全带 / 七对子 / 对对和 / 三暗刻 / 三色同刻 / 三杠子 / 混老头 / 小三元 | ✅ 除双立直·三杠子为 🟩 | | 3 番 | 二杯口 / 纯全带 / 混一色 | ✅ | | 6 番 | 清一色 | ✅ | | 役满 | 国士 / 四暗刻 / 大三元 / 小四喜 / 大四喜(双) / 字一色 / 绿一色 / 清老头 / 九莲 / 纯正九莲(双) / 四杠子 / 天和 / 地和 / 国士十三面(双) / 四暗刻单骑(双) / 累计役满 | ✅ 国士·四暗刻·大三元·字一色·九莲·纯正·国士十三面·四暗刻单骑;🟩 其余 | | 未实现 | 人和 / 古役(有意不做)/ 抢北已补 | ❌ 仅人和·古役 | ## I. 符计算 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | I1 | P0 | 副底 | 20 符 | ✅ | | I2 | P0 | 门前清荣和 | +10 | ✅ | | I3 | P0 | 自摸 | +2 | 🟩 | | I4 | P0 | 雀头 | 三元/自风/场风 +2,连风 +4 | 🟩 | | I5 | P0 | 刻/杠符 | 分档(暗杠幺九 +32) | ✅ | | I6 | P0 | 听牌形 | 嵌张/单骑/边张 +2 | 🟩 | | I7 | P0 | 平和自摸 | 20 符 | ✅ | | I8 | P0 | 七对子 | 25 符 | 🟩 | | I9 | P0 | 最低符 | 不足 30 进位 | 🟩 | | I10 | P0 | 进位 | 到 10 位 | 🟩 | ## J. 点数计算 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | J1 | P0 | 基本点 | 符 × 2^(2+番) | ✅ | | J2 | P0 | 满贯判定 | 5 番 / 4番40符 / 3番70符 | ✅ | | J3 | P0 | 跳满/倍满/三倍满/役满 | 6/8/11/13 档 | ✅ | | J4 | P0 | 切上满贯 | 不采用 | ✅ | | J5 | P0 | 亲/子荣和 | ×6 / ×4 | ✅ | | J6 | P0 | 自摸分配 | 亲平摊;子庄2倍闲1倍 | ✅ | | J7 | P0 | 本场 | 300 / 200 | ✅ | | J8 | P0 | 供托 | 1000 归和了者 | 🟩 | | J9 | P0 | 三麻自摸损 | 少收一名闲家 | ✅ | | J10 | P0 | 取整 | 向上到 100 | ✅ | | J11 | P0 | 点数守恒 | 无供托零和 | ✅ | | J12 | P1 | 击飞 | < 0 终局(=0 继续) | 🟩 | ## K. 流局 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | K1 | P0 | 荒牌流局 | 牌山摸尽 | ✅ | | K2 | P0 | 听牌罚符 | 3000 / 2000 按听牌家数 | ✅ | | K3 | P0 | 连庄 | 亲听牌连庄 | ✅ | | K4 | P1 | 九种九牌 | 首巡 ≥9 种幺九字牌可宣言 | 🟩 | | K5 | P1 | 四风连打 | → 流局 | ✅ | | K6 | P1 | 四家立直 | → 流局 | ✅ | | K7 | P1 | 三家和了 | → 流局 | ✅ | | K8 | P2 | 四杠散了 | → 流局 | ✅ | | K9 | P1 | 流局满贯 | 弃牌全幺九未被鸣 → 满贯自摸 | ✅ | ## L. 连庄 / 进庄 / 终局 / 西入 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | L1 | P0 | 和了连庄/下庄 | 亲和了连庄 | 🟩 | | L2 | P0 | 听牌连庄 | — | ✅ | | L3 | P0 | 场次推进 | 东南半庄 4 局一场风 | 🟩 | | L4 | P1 | 和了终局/听牌终局 | All Last 亲一位+达返点+连庄 → 终局 | ✅ | | L5 | P1 | 西入 | 南 4 无人达返点 → 西入 | 🟩 | | L6 | P0 | 击飞终局 | — | 🟩 | | L7 | P2 | 顺位马 / 头名赏 | 段位点结算 | ✅ 终局计算 + 结算面板显示 | ## M. 三麻特有 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | M1 | P0 | 去牌 / 无吃 | — | ✅ | | M2 | P0 | 起点/返点 | 35000 / 40000 | 🟩 | | M3 | P0 | 自摸损 | — | ✅ | | M4 | P1 | 拔北 | — | 🟩 | | M5 | P1 | 拔北后岭上 | 算岭上开花 | 🟩 | | M6 | P1 | 北作面子=客风 | 非役 | 🟩 | | M7 | P1 | 无四风连打/四家立直 | 自动不适用 | 🟩 | | M8 | P2 | 抢北 | 对拔北荣和 | ✅ | ## N. UI / 交互 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | N1 | P0 | 牌桌渲染 | 手牌/牌河/副露/宝牌/剩余/点数/场况 | 🧪 | | N2 | P0 | 出牌 | 点击手牌、轮转 | 🧪 | | N3 | P0 | 鸣牌窗口 | 荣/碰/杠/吃/跳过 + 倒计时 | 🧪 | | N4 | P1 | 立直操作 | 宣言 + 选牌打出 | 🟩 | | N5 | P1 | 操作按钮 | 自摸/暗杠/加杠/拔北/九种九牌 | 🟩 | | N6 | P1 | 结算面板 | 役种/番符/点数/顺位/下一局 | 🟩 | | N7 | P2 | 里宝牌展示 | 和了时揭开 | ✅ | | N8 | P2 | 立直棒/自己立直提示 | — | ✅ 棍形供托 + 自己立直提示 | | N9 | P2 | 听牌/振听提示 | — | ✅ | | N10 | P1 | 鸣牌超时对“非本人”推进 | 掉线也能推进 | ✅🧪(任一客户端在线即可驱动) | ## O. 联机 / 隐藏信息 | 编号 | 级别 | 检查项 | 期望 | 状态 | | --- | --- | --- | --- | --- | | O1 | P0 | playerView 隐藏 | 他家手牌/牌山/里宝隐藏 | 🟩 | | O2 | P0 | 公开信息 | handCounts/wallCount/doraIndicators | 🧪 | | O3 | P1 | 本地换座位不重置 | updatePlayerID 原地切换 | 🧪 | | O4 | P1 | 联机 4 端对局 | SocketIO 正常同步 | ✅ E2E(`mahjong-multiplayer.spec.ts`) | | O5 | P2 | 掉线玩家鸣牌超时 | 服务端推进 | 🟩(客户端驱动;全部离线则仍会停) | ## P. 已修复与剩余风险 **已修复(P0/P1/P2 主要项)**: - P0/P1:P-01 摸切、P-02 鸣牌超时、P-03 途中流局×4、P-04 流局满贯、P-05 和了终局、P-06 立直后暗杠校验、P-07 抢北、P-08 里宝/杠宝展示、P-09 食替筋、P-10 振听边界。 - P2:R-01 碰后不可立即拔北、R-02 抢杠撤销红牌计数、R-05 顺位马/头名赏、R-06 听牌/振听提示、D9/N8 立直棒可视化、R-07 联机 4 端 E2E。 **仍存在(均为“有意简化”或“独立阶段”,非缺陷)**: | 编号 | 级别 | 项目 | 说明 | | --- | --- | --- | --- | | R-03 | P2 | 掷骰/开牌位置、宝牌物理位置 | 采用简化布局,不影响玩法 | | R-04 | — | 观战 + AI 补位 | 独立阶段(已确认 AI 后续再做) | | S-01 | P2 | 自摸牌在“摸到”与手牌行各显示一次 | 纯 UX,可后续去重 | | S-02 | P2 | 杠宝翻开时机为“杠成立即翻” | 与真实时序略有差异,无算分影响 | | S-03 | P2 | 人和(古役)不实现 | 雀魂不采用(有意) | | S-04 | P2 | 鸣牌超时由客户端驱动 | 任一客户端在线即可推进;全部离线则停 | --- ## 本轮浏览器冒烟实测(v2,均已通过、无 JS 异常) - 开局(修复后正常)→ 打牌 → 轮转 - 切换座位不重置 - 鸣牌窗口出现;**故意不响应,等待 >12s 后自动跳过并推进**(验证 P0-02 / N10) - 连续多回合打牌正常(牌河累加、宝牌指示显示、点数显示) - 注入 `window.onerror` 捕获:全程 `[]` ## 建议的后续优先项 1. **R-04 观战 + AI 补位**(唯一剩余的大阶段,已确认 AI 后续再做)。 2. 观战/补位完成后再补「观战者不可见手牌」的 E2E。 --- ## Q. 测试清单(Test Inventory) > 数据来源:`packages/engine` 实跑(2026-10-03)。命令:`pnpm --filter @tts-like/engine test`。 > 引擎全量 **329 / 13 文件全通过**;下表为麻将相关的 **78 条**逐组明细。 ### Q1. `mahjong-tiles.test.ts` — 16 条(牌具/牌组) | # | 分组 | 用例 | | --- | --- | --- | | 1-3 | 四麻牌组 | 136 张 id 唯一 · 每种牌种恰好 4 张 · 红 5m/5p/5s 各 1 | | 4-5 | 三麻牌组 | 108 张且不含 2m~8m · 红 5p/5s 各 1(无红 5m) | | 6-8 | 索引↔牌种 | 34 种索引 0..33 一一对应 · 赤牌归一到普通 5 · 幺九/字牌判定 | | 9-12 | 宝牌指示映射 | 数牌 9→1 循环 · 赤牌按普通 5 计算 · 风牌 東→南→西→北→東 · 三元牌 白→發→中→白 | | 13-15 | 排序与展示 | `sortTiles` 按 m→p→s→z 且各花色 1..9 · `tileLabel` 中文/数字 · 计数↔牌种互转 | | 16 | 洗牌 | 注入固定随机源可复现,且不改原数组 | ### Q2. `mahjong-yaku.test.ts` — 33 条(役种/符/点/听牌) | # | 分组 | 用例 | | --- | --- | --- | | 1-2 | 和牌型分解 | 标准型分解数量正确 · 七对子/国士判定 | | 3-15 | 普通役种(13) | 平和 · 平和+断幺九 · 一杯口 · 二杯口 · 役牌(三元)与副露 · 混一色/清一色 · 混全带/纯全带 · 无役→null · 三色同顺/一气通贯/三色同刻 · 对对和+三暗刻 · 混老头/小三元 · 立直/一发/门清自摸/平和 · 海底/河底/岭上/抢杠 旗标 | | 16 | 符细节 | 幺九暗杠 +32 符、门清荣和 70 符 | | 17-22 | 役满(6) | 国士无双 · 国士十三面(双倍) · 大三元 · 四暗刻/四暗刻单骑(双倍) · 字一色 · 九莲宝灯/纯正九莲(双倍) | | 23 | 宝牌计数 | 指示 3m→宝牌 4m;赤牌归一 | | 24-28 | 符与点数(5) | 点数基本表(子/亲×荣/自摸) · 满贯封顶且不采用切上满贯 · 役满/双倍役满 · 本场加算(+300/本场) · 三麻自摸损 | | 29-33 | 听牌/振听/食替 | 单骑听 · 两面听 · 不成和牌型→false · 食替(碰现物 / 吃现物+筋 / 嵌张) · 舍张振听 | ### Q3. `mahjong.test.ts` — 29 条(对局流程 / P0-P1-P2) | # | 分组 | 用例 | | --- | --- | --- | | 1-2 | 配牌与开局 | 四麻:庄 14/闲 13/牌山 69/赤初始化 · 三麻:108 张/每家 35000/无 2m~8m | | 3 | 打牌推进 | 无人鸣牌时推进下家并摸牌 | | 4-6 | 鸣牌窗口 | `buildClaims` 检出碰/杠/吃/荣 · 双响**头跳**取最近 · 荣和优先于碰 | | 7-10 | 和了计算 | 平和+门清自摸点数 · **无役不能和** · 赤宝牌按实际持有重算 · `applyWin` 点数守恒 | | 11-12 | 荒牌流局 | 听牌罚符 3000 与庄家轮转 · 庄家听牌则连庄 | | 13 | 整手模拟(冒烟) | 随机打至荒牌流局:不抛异常、点数守恒、可开下一局 | | 14 | P0-01 | 立直后不能打非摸到的牌,只能摸切 | | 15 | P0-02 | 鸣牌超时:未到点不生效;到点自动跳过并推进 | | 16-18 | P1-03 | 四家立直/四风连打 · 三家和了→流局 · 四杠散了判定 | | 19 | P1-04 | 流局满贯:弃牌全幺九未被鸣→满贯自摸,不收供托 | | 20 | P1-05 | All Last 亲家一位、达返点且连庄→终局 | | 21 | P1-06 | 立直后暗杠:改变听牌被拒 / 不变则允许 | | 22 | P1-07 | 三麻抢北:对拔北开启荣和窗口 | | 23 | P1-08 | 里宝牌:和了前隐藏,和了后公开 `uraIndicators` | | 24 | P1-10 | 被鸣走的自弃牌仍计入舍张振听 | | 25 | R-01 | 碰后 `justCalledBy` 期间拔北被拒,打牌后恢复 | | 26 | R-02 | 加杠被抢撤销为碰并扣回赤宝牌计数 | | 27-28 | R-05 | 四麻ウマ +15/+5/−5/−15 且头名赏 +20 · 三麻 +15/0/−15 且 +15 | | 29 | R-06 | `playerView` 暴露 `myWaits` / `myFuriten` | ### Q4. 联机 E2E(Playwright) | 用例 | 覆盖 | | --- | --- | | `e2e/mahjong-multiplayer.spec.ts` | 4 客户端注册/建房/加入/开局 · 各自仅见己方手牌 · 对手座位无真实牌泄漏 · 连续轮转打牌 · 牌河累积 | ### Q5. 未纳入自动化(人工/简化,非缺陷) | 项 | 说明 | | --- | --- | | 三麻自摸损全表 | 仅抽样(满贯)验证,未穷举 | | 浏览器冒烟(人工) | 开局/打牌/换座/鸣牌/超时自动跳过,见上节记录 | | R-03 / S-01~S-04 | 有意简化项,见 [P 节](#p-已修复与剩余风险) | | R-04 观战/AI | 未实现,无需测试 |