二七王:S-6 大局结算按 基础分/冲关分/傍王分 三项分解

问题:大局结算面板要分项显示,而 account 只有「累积得分 + 每局得分数组」。
傍王分尤其拆不出来——N = 冲关奖数 + 傍王王数,两个来源【求和之后】才代入
grade_aw = X×(2Ni−Nj−Nk),事后无法反推各自占比。

解法:在算钱时就拆。把 N 分成 N_冲关(只计庄家)与 N_傍王(勾选后庄闲都算),
分别代入同一公式各算一次。公式对 N 线性,故恒有
  grade_cg + grade_bw == grade_aw
这条恒等式正好当回归断言用。

服务端:
- class.paiju.js 抽出 award_pay(n) 复用同一公式,新增 grade_cg / grade_bw;
  desk.seatlist 追加三个累计位(基础/冲关/傍王)。
- class.desk.js seatlist 初始化为 5 元素;account 下发改为【对象数组】
  { score, grades, grade_jf_total, grade_cg_total, grade_bw_total }。
  原二元数组下标语义不清,且前端未开工,此时改代价最小(同 S-4 的判断)。

协议:aset.seatlist 增补 grade_cg / grade_bw;account 结构与恒等式
  grade_jf_total + grade_cg_total + grade_bw_total == score 写明;
  并记录这次结构变更的时间与理由。

测试(endgame 26 → 39 checks):
- 核心不变量:两分量之和 == grade_aw;两分量各自零和。
- 未勾傍王局:grade_bw 恒 0、grade_cg == grade_aw。
- 【新增一整局开傍王的端到端】:不开傍王时 grade_bw 恒 0,只验到平凡情形,
  必须有傍王局才算真验证了拆分。该局逐项复核两个分量的公式、naward 口径,
  并钉住「王数不全相等时 grade_bw 必有非零」防止又退化成平凡。
- 大局累计恒等式:基础+冲关+傍王 == 累积总分。

反向验证:把 _awbw 置零 → 4 条断言失败;把冲关分量误算到闲家头上 →
2 条断言失败。均已还原、全量 17 文件全绿。

另修四处测试桩:_rpc.js / test_paiju / test_rpc / test_success 里手工构造的
o_desk.seatlist 仍是 2 元素,未跟上 class.desk.js 的结构变更(脚本缺陷,
非业务缺陷)。

顺带解决小局结算「冲关分」标签的不严谨:改取 grade_cg 而非 grade_aw,
开傍王时不再把傍王贡献算进来。

遗留 T-31:参考图「基础分」与「总得分」两行数值相同且与右侧大字对不上
(30/30 vs +135),mock 不自洽。当前按 基础分=grade_jf_total、总分=score
提供。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 00:34:46 +08:00
co-authored by Claude Opus 5
parent 50e6fd3ca4
commit 76e82405e1
9 changed files with 150 additions and 46 deletions
+28 -8
View File
@@ -978,11 +978,26 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
];
//算奖并入结算(design §8.4):玩家i从另两家各收 X×Ni、各付 X×Nj,净得 X×(2Ni−Nj−Nk)
var _aw = [
_X * (2 * _nlist[0] - _nlist[1] - _nlist[2]),
_X * (2 * _nlist[1] - _nlist[0] - _nlist[2]),
_X * (2 * _nlist[2] - _nlist[0] - _nlist[1])
];
var award_pay = function(n){
return [
_X * (2 * n[0] - n[1] - n[2]),
_X * (2 * n[1] - n[0] - n[2]),
_X * (2 * n[2] - n[0] - n[1])
];
}
var _aw = award_pay(_nlist);
//冲关与傍王【分别】再各算一次,供大局结算分项展示(S-6)。
//必须在这里拆——N = 冲关 + 傍王 求和后才代入公式,事后无法从 grade_aw 反推各自占比。
//公式对 N 是线性的,故 _awcg[i] + _awbw[i] 恒等于 _aw[i](下方 _p 赋值处有断言性注释)。
var _ncg = [0, 0, 0]; //冲关分量:只计庄家(design §8.1)
var _nbw = [0, 0, 0]; //傍王分量:勾选时庄闲都算(design §8.3)
for (var q = 0; q < 3; q++){
if (q == o_paiju.banker){ _ncg[q] = _cglist[q].count; }
if (_bangwang){ _nbw[q] = _cglist[q].wang; }
}
var _awcg = award_pay(_ncg);
var _awbw = award_pay(_nbw);
//捡分子数:_win=1庄赢→庄+X×2/闲−X;_win=-1闲赢→庄−X×2/闲+X
var _jf = [0, 0, 0];
@@ -1003,12 +1018,17 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
_p.chongguan = _cglist[i].count; //常规算奖奖数(仅庄家计入 N)
_p.wang = _cglist[i].wang; //王数
_p.naward = _nlist[i]; //该家总奖数 N
_p.grade_aw = _aw[i]; //算奖得分 X×(2Ni−Nj−Nk)
_p.grade_jf = _jf[i]; //捡分子数得分
_p.grade_aw = _aw[i]; //算奖得分 X×(2Ni−Nj−Nk),= grade_cg + grade_bw
_p.grade_cg = _awcg[i]; //其中的冲关分量(design §8.1,不含傍王)
_p.grade_bw = _awbw[i]; //其中的傍王分量(design §8.3)
_p.grade_jf = _jf[i]; //捡分子数得分(基础分)
_p.grade = _p.grade_aw + _p.grade_jf; //本局总得分
//大局累积得分
//大局累积:总分 + 三项分量(基础/冲关/傍王),供大局结算面板分项展示
o_paiju.o_desk.seatlist[i][0] = o_paiju.o_desk.seatlist[i][0] + _p.grade;
_p.score = o_paiju.o_desk.seatlist[i][0];
o_paiju.o_desk.seatlist[i][2] = o_paiju.o_desk.seatlist[i][2] + _p.grade_jf;
o_paiju.o_desk.seatlist[i][3] = o_paiju.o_desk.seatlist[i][3] + _p.grade_cg;
o_paiju.o_desk.seatlist[i][4] = o_paiju.o_desk.seatlist[i][4] + _p.grade_bw;
//保存每局得分
o_paiju.o_desk.seatlist[i][1].push(_p.grade);
msg.data.aset.seatlist.push(_p);