Files
huajishe-tts/docs/mahjong/02-verification-checklist.md
e2hang d02d718237 docs(mahjong): 依据实跑重核测试清单(v4)
- 头部测试概要改为准确值:麻将单测 78(tiles 16 / yaku 33 / game 29)、引擎 329、E2E ✅
- 新增「Q. 测试清单」:逐组列出 78 条用例 + 联机 E2E + 未纳入自动化项
- 修正过时项:O4 由「未做 4 端 E2E」→ ✅ E2E;移除已完成的后续优先项(仅剩 R-04 观战/AI)
2026-10-03 20:15:11 +08:00

363 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 立直麻将(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 | 未实现,无需测试 |