二七王:修复跟牌判定依赖客户端入参顺序(可翻转本轮胜负与结算)
can_followcard 尾段计算 cardvalue/noflower/nopair 时用的是入参原始数组 followcards(客户端提交顺序),而 get_pairlist/get_tuolaji_list 都按降序 相邻取对。端到端实测:闲家用主拖拉机毙牌且为末轮,降序提交时闲家赢下本轮 (捡分 40、扣底 ×4),把同一手牌打乱成 [51,50,105,104] 后对子漏判、 cardvalue 归 0,变成庄家赢、闲家 0 分大光、不扣底——同一手合法牌仅靠数组 顺序就能翻转胜负、捡分归属与最终结算,同源问题还能抹掉 noflower 缺门标志 污染 §9 下发给全场的牌况表。 改为在 min_ary_deduct 削减 _followcards 之前另存完整排序快照 _sortfollow, 尾段 8 处全部改用它(_followcards 会被削减、不可复用)。 顺带给 get_disbandRoom 加空守卫:平台在 makewar 后立刻置 battlestate=1, 而首局是延迟 1 秒创建的,这段窗口内解散会在 curr_paiju() 的 undefined 上 解引用抛异常、打断平台解散链路;现返回 null 走平台既有的「不带 deskfree」分支。 补 8 条回归(入参顺序无关性 5 条 + 端到端 1 条 + 解散空守卫 2 条), 已用「回退修复 → 用例转红」反验有效性;全套单测 401 项全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -104,4 +104,36 @@ t.eq('混 拖·2副散+补2主 不压', beat(f([N9(1), N8(1), zK(1), zQ(1), zJ(1
|
||||
// 首家副拖拉机:手中1对该副花色(数量仍不足) + 主牌 → 有对也压不过(混合非纯主拖)
|
||||
t.eq('混 拖·副对(不足)+补2主 不压', beat(f([N9(1), N9(2), zK(1), zQ(1), zJ(1)], [N9(1), N9(2), zK(1), zQ(1)], 4, 2, 302)), false);
|
||||
|
||||
// ===================== 入参顺序无关性(服务端不得依赖客户端提交的数组顺序)=====================
|
||||
// 回归:can_followcard 尾段曾用入参原始顺序的 followcards 算 cardvalue/noflower/nopair,
|
||||
// 而 get_pairlist/get_tuolaji_list 按降序相邻取对——客户端只要打乱数组顺序,
|
||||
// 就能把本该压过的主拖拉机算成牌面 0(改写本轮胜者/捡分/扣底),或抹掉缺门标志污染 §9 牌况表。
|
||||
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
||||
|
||||
// 主拖拉机毙牌:有序 vs 乱序,结果必须完全一致且都判为「压过」
|
||||
const HT = [zK(1), zK(2), zQ(1), zQ(2), oth(9)];
|
||||
const ht1 = f(HT, [zK(1), zK(2), zQ(1), zQ(2)], 4, 2, 302); // 降序
|
||||
const ht2 = f(HT, [zK(1), zQ(1), zK(2), zQ(2)], 4, 2, 302); // 乱序(对子被拆开摆放)
|
||||
t.eq('序无关 主拖毙牌·有序压过', beat(ht1), true);
|
||||
t.eq('序无关 主拖毙牌·乱序同样压过', beat(ht2), true);
|
||||
t.eq('序无关 主拖毙牌·两种顺序结果全等', same(ht1, ht2), true);
|
||||
|
||||
// 主对子毙牌
|
||||
const HP = [zK(1), zK(2), oth(9)];
|
||||
t.eq('序无关 主对毙牌·两种顺序结果全等',
|
||||
same(f(HP, [zK(1), zK(2)], 2, 2, 201), f(HP, [zK(2), zK(1)], 2, 2, 201)), true);
|
||||
|
||||
// 同花色拖拉机跟牌(非毙牌)的牌面值也不得随顺序变
|
||||
const HS = [J(1), J(2), T(1), T(2), N8(1)];
|
||||
t.eq('序无关 同花色跟拖·两种顺序结果全等',
|
||||
same(f(HS, [J(1), J(2), T(1), T(2)], 4, 2, 302), f(HS, [J(1), T(1), J(2), T(2)], 4, 2, 302)), true);
|
||||
|
||||
// 混合出牌:3 张该副花色 + 1 主牌。把副牌摆在首尾也必须记为「已缺该花色」
|
||||
const HM = [K(1), Q(1), J(1), zK(1)];
|
||||
const hm1 = f(HM, [zK(1), K(1), Q(1), J(1)], 4, 2, 302); // 降序:主牌在首
|
||||
const hm2 = f(HM, [K(1), zK(1), Q(1), J(1)], 4, 2, 302); // 乱序:首尾都是副牌
|
||||
t.eq('序无关 混合出牌·有序记缺门', hm1.noflower, true);
|
||||
t.eq('序无关 混合出牌·乱序同样记缺门', hm2.noflower, true);
|
||||
t.eq('序无关 混合出牌·两种顺序结果全等', same(hm1, hm2), true);
|
||||
|
||||
process.exit(t.done('follow') ? 0 : 1);
|
||||
|
||||
Reference in New Issue
Block a user