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

374 lines
9.7 KiB
Markdown
Raw 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.
# 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` 不参与争夺,只表示当前窗口内放弃
- `PENG``GANG` 都是夺取弃牌控制权的动作
- `HU` 直接改变对局参与关系和结算路径,因此优先级最高
### 4.2 同优先级冲突
当多个玩家对同一张弃牌拥有同优先级动作时,`V1` 采用:
- 按出牌者之后的最近顺位优先
具体定义:
- 当前系统座位轮转顺序是 `seatNo` 递增后取模
- 因此从 `sourceSeatNo + 1` 开始,沿当前行牌方向逐个查找
- 先遇到的候选玩家优先获胜
示例:
- 4 人桌,出牌者为 `seat 0`
- `seat 1``seat 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. 参考来源与说明
以下来源用于确认“四川麻将 / 成都麻将血战到底”的高共识规则与差异点:
- [四川麻将 - 维基百科](https://zh.wikipedia.org/wiki/%E5%9B%9B%E5%B7%9D%E9%BA%BB%E5%B0%87)
- [成都麻将:血战到底 - 快懂百科](https://www.baike.com/wikiid/6198029954197195589)
- [四川麻将规则 - 同城游](https://www.tcy365.com/news/d30057.html)
- [成都麻将换三张规则 - 游戏茶苑](https://gametea.com/news/201910/9099.html)
说明:
- 上述来源之间对 `一炮多响``过水不胡` 等细节并不完全一致
- 因此本文中的 `V1` 规则属于“基于公开共识后的工程裁决”
- 若未来需要做更地道或更赛事化的模式,应再增加“规则模式配置层”