Files
xzmaster/docs/RESPONSE_RESOLUTION_RULES.md
hujun 48da7d4990 feat: 实现响应候选模型与私有动作消息结构化
新增响应候选领域模型和结构化私有动作消息,支持响应窗口和候选动作下发。主要变更包括:

- 新增 ResponseActionOption、ResponseActionSeatCandidate 和 ResponseActionWindow 模型
- 扩展 PrivateActionMessage 支持响应候选上下文
- 实现 ResponseActionWindowBuilder 构建弃牌响应候选
- 拆分 GameMessagePublisher 支持回合动作和响应动作消息
- 更新前端原型页展示结构化候选动作
- 新增响应优先级规则文档 RESPONSE_RESOLUTION_RULES.md
2026-03-20 13:04:59 +08:00

9.7 KiB
Raw Blame History

XueZhanMaster 响应优先级规则澄清

本文档用于澄清四川麻将血战到底在本项目中的响应窗口、优先级与裁决方式。
它不等于“所有地区、所有平台唯一正确规则”,而是:

  1. 先吸收公开规则中的高共识部分
  2. 再明确本项目 V1 的工程实现边界
  3. 给后续真实裁决代码提供单一依据

当前状态快照日期:2026-03-20


1. 文档结论先看

1.1 本项目 V1 采用的核心结论

  • 只支持 碰 / 杠 / 胡 / 过,不支持
  • 响应窗口首先只围绕“弃牌后响应”建立
  • 优先级顺序采用:
    • HU > GANG > PENG > PASS
  • AI 与真人使用同一套优先级规则
  • 同优先级冲突时,按出牌者之后的最近顺位优先
  • PASS 仅表示放弃当前窗口,不等于永久放弃后续所有同类机会
  • 过水不胡 作为后续增强规则,不在当前 V1 强制启用
  • 一炮多响 在项目 V1 中暂不实现,采用“单窗口单胜出动作”的工程裁决

1.2 为什么这样定

  • 这样能和当前后端结构最自然衔接
  • 可以先把响应窗口停顿与恢复流程做稳
  • 避免在 HU 判定、多人同时胡牌、结算分摊都未稳定时,提前引入高复杂度冲突逻辑

这符合:

  • KISS:先做单窗口单胜出
  • YAGNI:当前不抢做一炮多响和完整过手胡体系
  • SOLID:先把规则澄清文档与裁决器边界固定
  • DRY:所有动作冲突统一走一套优先级裁决

2. 公开规则共识与本项目采用范围

2.1 高共识部分

结合公开资料,以下规则共识较高:

  • 四川麻将 / 成都麻将常见规则中:
    • 只有 万 / 筒 / 条
    • 可碰、可杠,不可吃
    • 血战到底是一家胡后牌局不立即结束,其他未胡家继续
  • 四川麻将公开资料中常见“点炮”“杠分”“查叫”“花猪”等扩展规则
  • 多个公开资料都把血战到底视为成都规则或四川规则的典型变体

2.2 规则不完全统一的部分

公开资料中存在差异或版本不完全一致的地方:

  • 是否支持 一炮多响
  • 是否严格执行 过水不胡
  • 过水不胡 的解除时机
  • 抢杠胡、补杠、绕杠与响应时机的细节
  • 比赛规则、地方线下习惯和手游平台的实现差异

因此本项目必须明确“工程采用规则”,不能把互相矛盾的外部说法直接混进代码。


3. 本项目 V1 规则边界

3.1 当前先实现哪些响应窗口

V1 只实现:

  • 某玩家打出一张牌后
  • 其他仍在牌局中的玩家基于这张弃牌触发响应窗口

V1 暂不实现:

  • 抢杠胡窗口
  • 补杠后二次响应窗口
  • 最后一张牌必须胡的特殊强制窗口
  • 多轮连续嵌套响应窗口

3.2 当前先支持哪些候选动作

当前候选结构已经准备支持:

  • PENG
  • GANG
  • PASS

HU 的动作入口和事件枚举虽然已预留,但真正候选生成依赖胡牌判定完成后再接入。

因此要区分两个状态:

  1. 接口和模型层:HU 已被保留
  2. 当前实际候选生成层:以 PENG / GANG / PASS 为主

4. 优先级规则

4.1 基础优先级

本项目 V1 的响应优先级顺序固定为:

  1. HU
  2. GANG
  3. PENG
  4. PASS

解释:

  • PASS 不参与争夺,只表示当前窗口内放弃
  • PENGGANG 都是夺取弃牌控制权的动作
  • HU 直接改变对局参与关系和结算路径,因此优先级最高

4.2 同优先级冲突

当多个玩家对同一张弃牌拥有同优先级动作时,V1 采用:

  • 按出牌者之后的最近顺位优先

具体定义:

  • 当前系统座位轮转顺序是 seatNo 递增后取模
  • 因此从 sourceSeatNo + 1 开始,沿当前行牌方向逐个查找
  • 先遇到的候选玩家优先获胜

示例:

  • 4 人桌,出牌者为 seat 0
  • seat 1seat 3 同时都能 PENG
  • seat 1 获胜

4.3 为什么不在 V1 支持一炮多响

这是一个项目级工程取舍,不是宣称外部规则世界只有这一种。

原因:

  • 一炮多响会直接放大以下复杂度:
    • 多赢家结算
    • 胡牌先后次序
    • 胡后谁退出牌局、谁继续
    • 多人同时胡后下一个行动座位怎么定
  • 当前项目还未完成:
    • 胡牌判定
    • 基础结算
    • 胡后继续行牌完整链路

所以 V1 先采用:

  • 单窗口单胜出动作

后续若要升级到一炮多响,应作为 V2 明确需求,不应在当前实现里偷偷混入。


5. PASS 与过手规则

5.1 PASS 在本项目中的定义

PASS 只表示:

  • 当前响应窗口内
  • 当前玩家放弃对当前触发牌的响应

它不表示:

  • 永久放弃此类动作
  • 放弃后续整局碰、杠、胡能力

5.2 当前窗口内的限制

在同一个响应窗口内:

  • 玩家一旦提交 PASS
  • 不能再次回到同一个窗口重新声明 PENG / GANG / HU

这是当前必须实现的最小一致性规则。

5.3 过水不胡 的项目处理

公开资料中可见类似“过水不胡 / 同巡振听 / 过手胡”的描述,但不同平台和地方规则细节并不完全统一。

因此本项目采取分阶段策略:

V1

  • 不实现完整 过水不胡
  • 只保证“同一响应窗口内PASS 后不能反悔”

V2

  • 评估是否加入:
    • 玩家错过可胡后,直到自己下一次摸牌或动牌前不能再胡
    • 是否仅限制同张牌
    • 是否限制同一路听牌
    • 是否允许加番后破除限制

6. 响应窗口生命周期

6.1 打开条件

当一名玩家完成弃牌后:

  1. 系统生成 TILE_DISCARDED 公共事件
  2. 系统用弃牌和当前牌桌状态构建响应候选
  3. 若存在候选,则创建 ResponseActionWindow
  4. 发出 RESPONSE_WINDOW_OPENED 公共事件
  5. 向有资格响应的玩家分别下发私有动作消息

6.2 关闭条件

响应窗口在以下任一条件满足时关闭:

  • 所有候选玩家都已响应
  • 响应超时
  • 裁决器已确定唯一胜出动作

关闭后应发出:

  • RESPONSE_WINDOW_CLOSED

并带上至少以下信息:

  • 来源座位
  • 最终裁决动作类型

6.3 关闭后的流转

若有人胜出

  • 执行胜出动作
  • 广播对应公共事件:
    • PENG_DECLARED
    • GANG_DECLARED
    • HU_DECLARED
    • PASS_DECLARED 一般不作为最终胜出动作事件使用

若所有人都放弃

  • 广播窗口关闭事件
  • 继续原始出牌后的下家摸牌流程

7. 公共消息与私有消息边界

7.1 公共消息应该包含什么

公共事件只应表达“桌面上发生了什么”,例如:

  • 某张牌被打出
  • 响应窗口已打开
  • 响应窗口已关闭
  • 某玩家碰 / 杠 / 胡

公共事件不应广播:

  • 每个玩家分别可做哪些动作
  • 某玩家私下收到的教学建议

7.2 私有消息应该包含什么

私有动作消息应表达“你现在能做什么”,例如:

  • 作用域:当前回合动作 / 响应动作
  • 来源牌与来源座位
  • 当前候选动作列表
  • 当前窗口 ID

这也是当前后端已升级为结构化 PrivateActionMessage 的原因。


8. 对代码实现的直接指导

8.1 裁决器建议输入

后续真正实现裁决器时,建议输入至少包括:

  • ResponseActionWindow
  • 各候选玩家的最终响应
  • 当前出牌座位
  • 当前行牌顺序

8.2 裁决器建议输出

建议输出至少包括:

  • 是否有人胜出
  • 胜出玩家
  • 胜出动作
  • 窗口内已放弃玩家
  • 是否继续原出牌后流转

8.3 当前推荐实现顺序

  1. 先把 ResponseActionWindow 真正接入弃牌后主流程
  2. 再实现窗口停顿与私有候选下发
  3. 再实现优先级裁决器
  4. 最后再接入 HU 判定与结算

不要反过来做,否则会出现:

  • 胡牌判定先写了,但没有窗口停顿
  • 前端已经能显示候选,但后端还无法裁决
  • 公共事件和私有动作消息互相打架

9. 与当前代码进度的对应关系

当前已经完成:

  • 新动作统一入口
  • 新动作基础校验
  • 新动作事件模型
  • 响应候选模型
  • 结构化私有动作消息
  • H5 原型页候选消息展示占位

当前尚未完成:

  • 真正的响应窗口停顿
  • 基于窗口的多人响应收集
  • 优先级裁决器
  • HU 候选生成与胡牌判定

因此本文件的直接用途是:

  • 让下一步裁决实现有明确规则依据
  • 降低“每轮新对话都重新讨论优先级”的沟通成本

10. 本项目 V1 的最终裁决口径

为了避免歧义,本项目 V1 最终采用如下口径:

  1. 血战到底按成都麻将大框架实现
  2. 不可吃,只处理 碰 / 杠 / 胡 / 过
  3. 当前第一阶段只围绕“弃牌后响应”建窗口
  4. 优先级固定为 HU > GANG > PENG > PASS
  5. 同优先级按出牌者之后最近顺位优先
  6. PASS 仅放弃当前窗口
  7. 当前不实现完整 过水不胡
  8. 当前不实现 一炮多响

如果后续要改这些口径,必须先更新本文件,再改代码。


11. 参考来源与说明

以下来源用于确认“四川麻将 / 成都麻将血战到底”的高共识规则与差异点:

说明:

  • 上述来源之间对 一炮多响过水不胡 等细节并不完全一致
  • 因此本文中的 V1 规则属于“基于公开共识后的工程裁决”
  • 若未来需要做更地道或更赛事化的模式,应再增加“规则模式配置层”