From 4276d38267b1f2168c85e26a6b2cff0e79730195 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 12 Aug 2026 04:20:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=8C=E4=B8=83=E7=8E=8B=EF=BC=9A=E6=8A=A5?= =?UTF-8?q?=E6=97=A0=E4=B8=BB=E5=90=8E=E7=AB=8B=E5=8D=B3=E4=B8=BA=E5=85=A8?= =?UTF-8?q?=E4=BD=93=E4=B8=89=E4=BA=BA=E5=88=B7=E6=96=B0=E4=B8=BB=E7=89=8C?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit design §9:「一旦有玩家的主牌全部打空,系统就为全体三人显示另外 两家各自的主牌数量、以及这些主牌里有多少对子」。 原实现只在出牌者自己出牌时更新自己那一格 seatlist[seat][4],所以 A 打空主牌报无主的那一刻,B、C 的主牌数/对子数仍是初始 [-1,-1], 要等各自轮到出牌才补上,界面最多滞后两次出牌才完整。 改为:出牌后先判定出牌者主牌是否出空,一旦 have_baofu() 成立,就 按各家实际手牌为三个座位统一重算 [剩余主牌数, 剩余主对数] 及主花 色标志。重算幂等——主牌一旦出空不会再有,[4][0] 恒为 0。 test_rpc 的 mkChupai 原先只把 seatlist[1][4][0] 置 0 伪造报无主, 而不真的清空 seat1 的主牌;新逻辑按实际手牌重算会把这个假状态纠 正回去,导致 baozhu 断言失败。这是新实现更严格的正确表现,故改测 试造真状态(把 seat1 的主牌标为已出),不是放宽断言。 test_input 新增 6 项:报无主前三家均为 [-1,-1];打空瞬间三家统计 与主花色标志同时刷新到实际值。 Co-Authored-By: Claude Opus 5 (1M context) --- server/games/erqiwang/class.paiju.js | 38 ++++++++++++++---------- server/games/erqiwang/test/test_input.js | 20 +++++++++++++ server/games/erqiwang/test/test_rpc.js | 3 ++ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/server/games/erqiwang/class.paiju.js b/server/games/erqiwang/class.paiju.js index 7236a91..284b2ad 100644 --- a/server/games/erqiwang/class.paiju.js +++ b/server/games/erqiwang/class.paiju.js @@ -558,23 +558,29 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || { //进入出牌阶段 o_paiju.step = 5; - //是否报副处理 - if (o_paiju.seatlist[o_paiju.playproc.currseat][4][0] != 0){ - var _zhu = cls_youle_erqiwang_paiju.get_seat_zhucards(o_paiju, o_paiju.playproc.currseat); - if (_zhu.length == 0){ - o_paiju.seatlist[o_paiju.playproc.currseat][4][0] = 0; - o_paiju.seatlist[o_paiju.playproc.currseat][4][1] = 0; - } - if (o_paiju.method.have_baofu()){ - var _parilist = cls_youle_erqiwang_arith.get_pairlist(o_paiju.flower, _zhu); - o_paiju.seatlist[o_paiju.playproc.currseat][4][0] = _zhu.length; - o_paiju.seatlist[o_paiju.playproc.currseat][4][1] = _parilist.length; + //报无主处理(design §9) + //先看出牌者自己的主牌是否已出空(出空即"报无主"); + //一旦全场有人报无主,立即为【全体三人】刷新剩余主牌数/主对子数——design §9 要求 + //"一旦有玩家的主牌全部打空,系统就为全体三人显示另外两家各自的主牌数量与对子数", + //而不是等另外两家各自轮到出牌时才逐个补上。 + var _self = o_paiju.playproc.currseat; + if (cls_youle_erqiwang_paiju.get_seat_zhucards(o_paiju, _self).length == 0){ + o_paiju.seatlist[_self][4][0] = 0; + o_paiju.seatlist[_self][4][1] = 0; + } + if (o_paiju.method.have_baofu()){ + for (var _s = 0; _s < 3; _s++){ + var _zhu = cls_youle_erqiwang_paiju.get_seat_zhucards(o_paiju, _s); + var _zhupair = cls_youle_erqiwang_arith.get_pairlist(o_paiju.flower, _zhu); + o_paiju.seatlist[_s][4][0] = _zhu.length; + o_paiju.seatlist[_s][4][1] = _zhupair.length; - if (o_paiju.seatlist[o_paiju.playproc.currseat][4][0] == 0){ - o_paiju.seatlist[o_paiju.playproc.currseat][o_paiju.flower - 1][0] = 1; - o_paiju.seatlist[o_paiju.playproc.currseat][o_paiju.flower - 1][1] = 1; - } else if (o_paiju.seatlist[o_paiju.playproc.currseat][4][1] == 0){ - o_paiju.seatlist[o_paiju.playproc.currseat][o_paiju.flower - 1][1] = 1; + if (_zhu.length == 0){ + //主牌出空,等同于主花色也没有了、也没有主花色的对子 + o_paiju.seatlist[_s][o_paiju.flower - 1][0] = 1; + o_paiju.seatlist[_s][o_paiju.flower - 1][1] = 1; + } else if (_zhupair.length == 0){ + o_paiju.seatlist[_s][o_paiju.flower - 1][1] = 1; } } } diff --git a/server/games/erqiwang/test/test_input.js b/server/games/erqiwang/test/test_input.js index 1671652..c490edb 100644 --- a/server/games/erqiwang/test/test_input.js +++ b/server/games/erqiwang/test/test_input.js @@ -92,4 +92,24 @@ try { t.eq('出牌 反 非法入参不抛异常', threw, null); t.eq('出牌 反 非法入参不产生任何出牌', pj5.cards.filter(c => c.playround > 0).length, 0); + + +// ============ design §9:报无主后立即为全体三人刷新主牌统计 ============ +// 造 step5 牌局:seat0 手上只剩 1 张主牌(打掉即报无主),seat1/seat2 各持若干主牌 +const pj6 = newPaiju(5, 0, 0); +for (let i = 0; i < 108; i++) pj6.cards[i].dealowner = -1; // 先全部清空 +const give = (cid, seat) => { pj6.cards[cid].dealowner = seat + 1; pj6.cards[cid].playround = -1; }; +give(id(1, 1, 5), 0); // seat0:主♦5(唯一主牌) +give(id(1, 3, 9), 0); // seat0:副♥9(保证还有牌) +give(id(1, 1, 13), 1); give(id(2, 1, 13), 1); give(id(1, 1, 12), 1); // seat1:主♦K对 + 主♦Q +give(id(1, 1, 7), 2); // seat2:正7(固定主牌) +P.new_playround(pj6, 1, 0); +t.eq('报无主前 三家统计均为初始 [-1,-1]', pj6.seatlist.map(s => s[4]), [[-1, -1], [-1, -1], [-1, -1]]); +P.do_playcard(pj6, [id(1, 1, 5)]); // seat0 打出唯一主牌 → 报无主 +t.eq('报无主 seat0 主牌清空 [0,0]', pj6.seatlist[0][4], [0, 0]); +t.eq('报无主 立即刷新 seat1 [3张,1对]', pj6.seatlist[1][4], [3, 1]); +t.eq('报无主 立即刷新 seat2 [1张,0对]', pj6.seatlist[2][4], [1, 0]); +t.eq('报无主 seat0 主花色标志置1', pj6.seatlist[0][pj6.flower - 1], [1, 1]); +t.eq('报无主 seat2 无主对→无对标志置1', pj6.seatlist[2][pj6.flower - 1][1], 1); + process.exit(t.done('input') ? 0 : 1); diff --git a/server/games/erqiwang/test/test_rpc.js b/server/games/erqiwang/test/test_rpc.js index 0f3cf49..0db7345 100644 --- a/server/games/erqiwang/test/test_rpc.js +++ b/server/games/erqiwang/test/test_rpc.js @@ -46,6 +46,9 @@ function mkChupai(roomtype) { const lead = id(1, 3, 9); // 副9(flower3) 作单张首出 pj.cards[lead].dealowner = 1; // 归庄家 pj.cards[lead].playround = -1; + // seat1 报无主:必须让它【真的】打空主牌。do_playcard 会按各家实际手牌重算三家的主牌统计 + // (design §9:一旦有人报无主,立即为全体三人刷新),只置标志位会被重算纠正回去 + for (const c of P.get_seat_zhucards(pj, 1)) pj.cards[c].playround = 1; pj.seatlist[1][4][0] = 0; // seat1 报无主 → have_baofu()=true const c = setup(roomtype, pj); mod.chupai(pack(0, { cards: [lead] }));