二七王测试:完成 P0 用例(正常跟牌/结算集成/叫分坐庄/扣底触发)

- test_follow.js(新):§5.1/5.2 正常跟牌/毙牌/垫牌 17 例——单张/对子/拖拉机的
  必出、缺门毙牌数量对应(副单→主单/副对→主对/副N连→主N连)、垫牌、有对/拖却出散张被拒
- test_callgrade.js(新):§4.2 叫分坐庄 do_callgrade 6 例(叫5立即/两家不叫/后叫更低)
- test_paiju.js:§7/§8 结算集成扩充(大光/过庄/升级/爬坡/傍王+算奖参与/对照)、
  §6.3 扣底触发 get_bottom_account(主对×2/两连对×4/副牌不扣/庄赢不扣)
- 02-测试计划.md/README:P0 全部标记完成

全部单测 123 项断言全绿(node server/games/erqiwang/test/run.js)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 01:03:01 +08:00
co-authored by Claude Opus 4.8
parent 5a5165a319
commit 0049754988
5 changed files with 145 additions and 30 deletions
@@ -0,0 +1,28 @@
// §4.2 叫分坐庄 do_callgrade(纯函数,operate on 最小 o_paiju)。期望取自 design §4.2
require('./_shim');
const P = require('../class.paiju.js');
const t = require('./_assert')();
const mkCall = fs => ({ callproc: [{ seat: fs, call: null }], banker: -1, call: -1, step: 1 });
// 依次叫分序列(calls 里每个值 = 当前轮到者的叫分,0=不叫)
function seq(firstseat, calls) {
const p = mkCall(firstseat);
for (const c of calls) P.do_callgrade(p, c);
return p;
}
const bcs = p => [p.banker, p.call, p.step];
// 叫5立即上庄
t.eq('叫5立即上庄', bcs(seq(0, [5])), [0, 5, 2]);
// 暂定庄叫65,另两家都不叫 → 暂定庄(0)上庄
t.eq('0叫65 两家不叫→0上庄', bcs(seq(0, [65, 0, 0])), [0, 65, 2]);
// 0叫65、1叫更低60、2不叫、0不叫 → 60 最低者(1)上庄
t.eq('0叫65 1叫60 余不叫→1上庄', bcs(seq(0, [65, 60, 0, 0])), [1, 60, 2]);
// 首家叫5路径:0叫5 → 0直接上庄(其余无需叫)
t.eq('首家叫5直接坐庄', bcs(seq(0, [5])), [0, 5, 2]);
// 递减到5:0叫65,1叫60,2叫5 → 2上庄(叫5立即)
t.eq('2叫5立即上庄', bcs(seq(0, [65, 60, 5])), [2, 5, 2]);
// 不同首家:1起叫,1叫50,2不叫,0不叫 → 1上庄
t.eq('首家1叫50 余不叫→1上庄', bcs(seq(1, [50, 0, 0])), [1, 50, 2]);
process.exit(t.done('callgrade') ? 0 : 1);