- 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 通过
3.3 KiB
3.3 KiB
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.ioGame:阶段机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])。
遇到的问题
- 赤宝牌表达:牌型判定用索引(0..33),索引会丢赤牌信息。→ 赤 5 用
'0m'/'0p'/'0s',判定时normalizeKind归一到5m/5p/5s;赤牌数单独按Tile.red+Meld.redCount统计。 - 隐藏信息与剩余牌数:
playerView把wall置空后 UI 无法显示“剩余张数”。→ 额外注入公开字段wallCount、doraIndicators、handCounts。 - boardgame.io 单线程下的鸣牌并发:真实麻将是并发申请+优先级比较。→ 用“响应窗口 + 全部响应后按 荣>碰/杠>吃 结算”建模,UI 端 8 秒倒计时自动跳过来避免卡死。
- 立直支付时机:先宣言后打牌,若在宣言与打牌之间自摸会漏付供托。→ 把 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 造成状态错乱)。