二七王:拖拉机极大连续段扫描与牌编码区间常量收敛进 shared
前后端此前各写了一遍「分对子 → is_continuous 扫极大连续段 → ≥2 对算拖拉机」: 服务端 class.arith.js decompose_trump 与前端 core/CardMark.js。规则内容(什么算连续、 几对起算拖拉机)散在两处,正是 shared/ 要消除的重复。 - shared/cards.js 新增 group_tractor_runs(mainflower, pairlist):返回极大连续段数组, 孤立对子作为长度 1 的段返回,拼接后恰好还原入参;阈值导出为 TRACTOR_MIN_PAIRS。 - shared/cards.js 导出牌编码区间边界具名常量(CODE_ZHU_MIN / CODE_ZHENG2_* / CODE_FU2_* / CODE_ZHENG7_* / CODE_FU7_* / CODE_XIAOWANG / CODE_DAWANG / CODE_A_IN_ZHU),并在 id_to_code / is_continuous / trump_rank 内部改用它们。 - decompose_trump 改调共享扫描,对外行为完全不变(分量类型、顺序、cards 归属不变)。 - CardMark 删掉本地扫描改调共享版本,区间判定与标记值改引用常量,去掉 1000/3000/ 4000/8000/9000 裸字面量。 - 前端副本经 sync_shared.cmd 同步;服务端单测 624→645 checks 全绿,前端 8 个测试全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,35 @@ const crossFlower = [id(1, 2, 9), id(2, 2, 9), id(1, 3, 10), id(2, 3, 10)];
|
||||
const m4 = EQW_CardMark.marksOfHand(crossFlower, MF);
|
||||
t.eq('跨花色不成拖', crossFlower.map(c => m4[c] || null), [null, null, null, null]);
|
||||
|
||||
// ---- 三连对:整段 6 张全标 tractor ----
|
||||
const tractor3 = [id(1, 2, 9), id(2, 2, 9), id(1, 2, 10), id(2, 2, 10), id(1, 2, 11), id(2, 2, 11)];
|
||||
const m3a = EQW_CardMark.marksOfHand(tractor3, MF);
|
||||
t.eq('三连对全标 tractor', tractor3.map(c => m3a[c]), ['tractor', 'tractor', 'tractor', 'tractor', 'tractor', 'tractor']);
|
||||
|
||||
// ---- 极大连续段:连续的 10/J 成拖,同花色不相连的 8 对不成拖(段与段互不粘连)----
|
||||
const runAndLone = [id(1, 2, 10), id(2, 2, 10), id(1, 2, 11), id(2, 2, 11), id(1, 2, 8), id(2, 2, 8)];
|
||||
const m3b = EQW_CardMark.marksOfHand(runAndLone, MF);
|
||||
t.eq('连续段内标 tractor', [m3b[id(1, 2, 10)], m3b[id(1, 2, 11)]], ['tractor', 'tractor']);
|
||||
t.eq('段外孤立对子不标', m3b[id(1, 2, 8)] || null, null);
|
||||
|
||||
// ---- 与服务端同源:标记扫描走 shared 的 group_tractor_runs(前后端唯一实现)----
|
||||
t.eq('shared 导出极大连续段扫描', typeof youle_erqiwang_shared_cards.group_tractor_runs, 'function');
|
||||
t.eq('shared 导出拖拉机起算对数', youle_erqiwang_shared_cards.TRACTOR_MIN_PAIRS, 2);
|
||||
|
||||
// ---- 区间边界取自 shared 具名常量(CardMark 内不再有裸字面量)----
|
||||
t.eq('shared 导出主牌下界', youle_erqiwang_shared_cards.CODE_ZHU_MIN, 1000);
|
||||
t.eq('正2 落在 CODE_ZHENG2 区间',
|
||||
youle_erqiwang_shared_cards.id_to_code(MF, id(1, MF, 2)) > youle_erqiwang_shared_cards.CODE_ZHENG2_MIN &&
|
||||
youle_erqiwang_shared_cards.id_to_code(MF, id(1, MF, 2)) < youle_erqiwang_shared_cards.CODE_ZHENG2_MAX, true);
|
||||
t.eq('正7 落在 CODE_ZHENG7 区间',
|
||||
youle_erqiwang_shared_cards.id_to_code(MF, id(1, MF, 7)) > youle_erqiwang_shared_cards.CODE_ZHENG7_MIN &&
|
||||
youle_erqiwang_shared_cards.id_to_code(MF, id(1, MF, 7)) < youle_erqiwang_shared_cards.CODE_ZHENG7_MAX, true);
|
||||
|
||||
// ---- 标记值取自 MARK_* 常量,不在别处重写字面量 ----
|
||||
t.eq('MARK_TRACTOR 常量', EQW_CardMark.MARK_TRACTOR, 'tractor');
|
||||
t.eq('MARK_ZHENG 常量', EQW_CardMark.MARK_ZHENG, 'zheng');
|
||||
t.eq('MARK_ZHU 常量', EQW_CardMark.MARK_ZHU, 'zhu');
|
||||
|
||||
// ---- 优先级:属于拖拉机的正2,标 tractor 而非 zheng ----
|
||||
// 主牌序里 正2 与 副2 相连(is_continuous: 正2、负2)
|
||||
const zhengInTractor = [id(1, MF, 2), id(2, MF, 2), id(1, 2, 2), id(2, 2, 2)];
|
||||
|
||||
Reference in New Issue
Block a user