# 麻将 **Repository Path**: a1220986759/mahjong ## Basic Information - **Project Name**: 麻将 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-12 - **Last Updated**: 2026-10-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 麻将无双 · 乱世群英(网页版 MVP) 三国乱世,**麻将即战争**:每座城池的兵力就是你桌上的筹码。攻打相邻城池, 用一局四人麻将来决胜负——**赢了吃兵,输了掉兵,输光兵力就把城交出去**。 > 灵感来自塞班时代的老游戏《麻将无双之乱世群英》。 --- ## 快速开始 ```bash node tools/serve.mjs # 或 npm start(默认 5199) node tools/serve.mjs 5200 # 指定端口 # 打开 http://127.0.0.1:5199/ ``` > **端口被占用(EADDRINUSE)?** 说明已经有一个服务器在跑——直接打开原地址即可。 > 现在的 `serve.mjs` 会自动往后找可用端口(最多试 20 个),并打印实际使用的地址。 **零依赖**:源码就是浏览器原生的 ES Module(`web/js/**/*.js`),不需要 `npm install`、 不需要打包编译。Node 仅用于起静态服务器和跑测试。 ## 玩法 1. **选势力**:四方各据一角(西凉 / 河北 / 益州 / 江东),中原五城中立。 2. **地图回合**:轮到你可做两件事之一 - **攻打**相邻的非己方城 → 开一局四人麻将; - **派兵支援**相邻的己方城 → 把兵力前移,准备下一场仗。 3. **麻将战斗**:广东麻将 13 张(4 面子 + 1 将,136 张牌,无花牌)。 桌上四人 = 攻方(你)+ 守方 + 2 名佣兵。 4. **兵力结算**(核心规则) - 赌注 `S = min(参战各方兵力, 佣兵 20)`,四方等额下注; - 麻将 `deltas` 是番数增减(零和),按 **番数 × 赌注** 换算成兵力; - 自摸:三家各赔 1 倍,赢家收 3 倍;点炮:点炮者赔 3 倍、另两家各赔 1 倍,赢家收 5 倍; - 单局损兵有上限(60),**不会**把势力直接打到 0; - 输家欠债超过全部兵力 → **割城抵债**,城池归赢家,守军并入; - 攻打中立城获胜 → 守将(马腾 / 董卓 / 陶谦…)直接归顺。 5. **一统天下**:只剩一个势力时结束。 ## 番型(MVP) | 番型 | 条件 | 倍率 | |---|---|---| | 平胡 | 基本和牌 | ×1 | | 碰碰胡 | 4 个刻子/杠 | ×2 | | 混一色 | 一门数牌 + 字牌 | ×3 | | 清一色 | 纯一门数牌 | ×6 | | 七对 | 7 个对子(须门清) | ×4 | | 自摸 | 自己摸到和牌张 | ×2 | 倍率相乘,**封顶 8 番**(避免一局清盘)。 ## 代码结构 ``` web/ ├── index.html 入口(原生 ES Module) └── js/ ├── main.js 启动 ├── engine/ │ ├── types.js 牌与常量、可播种随机(mulberry32) │ ├── hand.js 和牌判定、向听数、听牌、番型 │ ├── rules.js 摸/打/吃/碰/杠/胡、番数结算 │ └── ai.js AI 打牌(向听优先 → 进张 → 孤张) ├── war/ │ └── war.js 3×3 城池图、相邻关系、调兵、赌注与兵力结算 └── ui/ ├── render.js Canvas 绘制(程序化牌面、地图、战报) ├── game.js 场景状态机与战斗编排 └── style.css tools/ 零依赖工具脚本 tests/ 测试(node:assert) docs/CONTRACT.md 模块接口契约与规则决定 ``` ## 验证 ```bash node tools/run-tests.mjs # 25 个用例:引擎 15 + 城池结算 10 node tools/smoke.mjs # 无头端到端:菜单→地图→攻城→麻将→战报→一统 node tools/sim.mjs 100 # 平衡模拟:和牌率、番数分布、地图推进 node tools/perf.mjs # 关键路径性能 ``` 测试与冒烟测试都用最小 DOM/Canvas 桩跑真实的 `GameController`, 所以不需要浏览器也能验证完整链路。 ## 已知取舍 - AI 是启发式(向听 + 进张 + 孤张),**会打但不无敌**;模拟中和牌率约 20–35%,其余流局。 - 佣兵只有固定 20 兵,不在地图上结算,作用是把赌注压到可控范围。 - 尚未实现:吃(chi)的 UI 按钮(引擎已支持)、存档、音效、PWA 离线缓存。