- engine/tiles: 34 种牌、四麻 136/三麻 108(去 2m~8m)、赤 5(3/2 枚)、宝牌指示映射、排序与计数
- engine/yaku: 和牌分解(标准/七对/国士)+ 全役种(含双倍役满、累计役满)+ 符计算 + 番符→点数(满贯封顶、不采用切上满贯、三麻自摸损)+ 听牌/振听/食替
- engine/game: boardgame.io Game(阶段机 + 摸打/立直/鸣牌/和了/流局 moves + 鸣牌窗口“荣>碰/杠>吃/头跳” + playerView 隐藏 + 连庄/进庄/击飞/西入/半庄终局)
- ui: 新增 MahjongBoard(立式麻将桌:手牌/牌河/副露/宝牌/剩余张数/点数/鸣牌倒计时)
- 注册: server 两数组 + App.tsx GAMES/GAME_ORDER/GameKey/本地+联机 View(maxSeats=4, seatChoices=[3,4])
- docs: docs/mahjong/{00-rules,01-implementation-plan}.md + dev-log 15;CODEBUDDY.md 游戏清单更新
- 测试: mahjong-tiles/yaku/game 共 59 条;engine 全量 310 通过;web tsc+vite build、server tsc 通过
35 lines
3.3 KiB
Markdown
35 lines
3.3 KiB
Markdown
# 15 · 立直麻将(Mahjong)游戏
|
||
|
||
> **做什么**(用户要求)→ **遇到什么问题** → **怎么解决**
|
||
|
||
## 做什么
|
||
|
||
在 tts-like 中加入**日本立直麻将**,规则采用**雀魂标准**,覆盖**四麻 + 三麻**、**半庄战**、**纯真人**(AI 后续)。
|
||
规则文档先行:`docs/mahjong/00-rules.md`(玩法依据 + 选型)、`docs/mahjong/01-implementation-plan.md`(工程拆分)。
|
||
UI 参照桥牌 `BridgeBoard.tsx` 的思路二次设计为立式麻将桌。
|
||
|
||
## 实现结构
|
||
|
||
- `packages/engine/src/games/mahjong-tiles.ts` — 牌具:34 种牌、四麻 136/三麻 108 去 **2m~8m**、赤 5(四麻 3 / 三麻 2)、宝牌指示映射、排序与计数。测试 `mahjong-tiles.test.ts`。
|
||
- `packages/engine/src/games/mahjong-yaku.ts` — 和牌分解(标准型/七对/国士)、**全役种**(含双倍役满、累计役满)、符计算、点数(含满贯封顶、**不采用切上满贯**、亲/子/自摸/荣和、本场、三麻自摸损)、听牌/振听/食替辅助。测试 `mahjong-yaku.test.ts`。
|
||
- `packages/engine/src/games/mahjong.ts` — boardgame.io `Game`:阶段机 `waiting→playing→roundEnd→gameEnd`,moves(`startGame/declareRiichi/discard/tsumo/respond/ankan/kakan/nuki/kyushu9/nextRound/setName`),鸣牌窗口(荣>碰/杠>吃、**头跳**),`playerView` 剥离手牌/牌山/里宝。测试 `mahjong.test.ts`。
|
||
- `apps/web/src/MahjongBoard.tsx` — 麻将桌 UI(手牌/牌河/副露/宝牌指示/剩余牌数/点数/操作按钮 + 鸣牌响应倒计时)。
|
||
- 注册:`packages/server/src/index.ts` 两数组 + `apps/web/src/App.tsx`(`GAMES`/`GAME_ORDER`/`GameKey`/本地+联机 View,`maxSeats=4`、`seatChoices=[3,4]`)。
|
||
|
||
## 遇到的问题
|
||
|
||
1. **赤宝牌表达**:牌型判定用索引(0..33),索引会丢赤牌信息。→ 赤 5 用 `'0m'/'0p'/'0s'`,判定时 `normalizeKind` 归一到 `5m/5p/5s`;赤牌数单独按 `Tile.red` + `Meld.redCount` 统计。
|
||
2. **隐藏信息与剩余牌数**:`playerView` 把 `wall` 置空后 UI 无法显示“剩余张数”。→ 额外注入公开字段 `wallCount`、`doraIndicators`、`handCounts`。
|
||
3. **boardgame.io 单线程下的鸣牌并发**:真实麻将是并发申请+优先级比较。→ 用“响应窗口 + 全部响应后按 荣>碰/杠>吃 结算”建模,UI 端 8 秒倒计时自动跳过来避免卡死。
|
||
4. **立直支付时机**:先宣言后打牌,若在宣言与打牌之间自摸会漏付供托。→ 把 1000 点支付与 `riichi=true` 提前到 `declareRiichi`,`discard` 只负责进入一发。
|
||
|
||
## 结果
|
||
|
||
- `pnpm --filter @tts-like/engine test`:**310 通过**(新增麻将 59 条)。
|
||
- `apps/web` 的 `tsc --noEmit && vite build` 通过;server 类型检查通过。
|
||
- 已知**待补**(`mahjong.ts` 内有 TODO):四风连打/四家立直/三家和了/四杠散了等途中流局、流局满贯、立直后暗杠的听牌不变校验、和了终局/听牌终局的精确 All Last 判定、精确一发计时。九种九牌、荒牌流局听牌罚符、连庄/进庄、击飞、西入已实现。
|
||
|
||
## 与 §14 对接要点的落地
|
||
|
||
规则文档 §14 列的三处注册与 `playerView` 约束均已按约定实现;发牌为 `freshRoundState` 内**原子完成**(避免多客户端抢发同一 move 造成状态错乱)。
|