二七王:手牌标记精灵扩到与手牌一一对应(36 个),并钉死精灵总数

清单 §5.2 表格写的是「牌型分组标记 ×8」,但 §1.6 明确规定三种标记互斥、【每张牌】
至多一个,core/CardMark.js 也是按每张牌返回标记的。一手 28 张牌通常带 13 个以上标记、
36 张埋牌手更多,8 个远远不够。§1.6 是行为规格、比表格措辞更权威,故按 §1.6 裁决:
HAND_MARK_1..36 与 HAND_CARD_1..36 一一对应。

- ID 另起 2100–2135 整段空号:1236 往后接不下 36 个连号(1250 起已是底牌/埋牌区),
  换空号段比给别的 View 重新编号更安全;仍落在子游戏段 1001–2999,无重复。
- 守卫补「手牌与标记 1..36 一一对应且同群组」检查。
- 精灵总数由「> 200」改为钉死 387(test_constants / test_spriteindex 两处同一个数),
  布局节点数同理已钉死——松下界删掉整个 View 都还能通过。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 22:25:19 +08:00
co-authored by Claude Opus 5
parent 92edb6a3f5
commit ee65871694
3 changed files with 66 additions and 12 deletions
@@ -7,7 +7,7 @@
// 连号精灵逐条写全,不用循环生成——便于人逐张对照编辑器核对。
var EQW_Sprites = EQW_Sprites || {};
//自己手牌区:36 张手牌 + 8 个牌型分组标记,同属群组 210(清单 §5.2,Layer 102)
//自己手牌区:36 张手牌 + 36 个手牌标记(每张牌一个,见下方裁决说明),同属群组 210(清单 §5.2,Layer 102)
EQW_Sprites.HandView = {
Layer: EQW_Layers.HAND, //102
@@ -52,15 +52,50 @@ EQW_Sprites.HandView = {
HAND_CARD_35: 1234,
HAND_CARD_36: 1235,
//—— 8 个手牌牌型分组标记【T-8】,资源 EQW_Images.MARK_CARD_GROUP,帧1=拖(拖拉机) 帧2=橙五角星(正2/正7) 帧3=蓝五角星(其他主牌)——
HAND_MARK_1: 1236,
HAND_MARK_2: 1237,
HAND_MARK_3: 1238,
HAND_MARK_4: 1239,
HAND_MARK_5: 1240,
HAND_MARK_6: 1241,
HAND_MARK_7: 1242,
HAND_MARK_8: 1243
//—— 36 个手牌标记【T-8】,与 HAND_CARD_1..36 一一对应(HAND_MARK_i 属于 HAND_CARD_i)——
//资源 EQW_Images.MARK_CARD_GROUP,帧1=拖(拖拉机) 帧2=橙五角星(正2/正7) 帧3=蓝五角星(其他主牌)。
//【裁决:按「每张牌」而非「每组」】清单 §5.2 的表格写的是「牌型分组标记 ×8」,但 §1.6 明确
//规定三种标记互斥、【每张牌】至多一个,core/CardMark.js 也是按每张牌返回标记的。
//一手 28 张牌通常带 13 个以上标记、36 张埋牌手更多,8 个远远不够——§1.6 是行为规格,
//比 §5.2 表格的措辞更权威,故按 §1.6 扩到与手牌一一对应。
//ID 另起 2100 段:1236 往后接不下 36 个连号(1250 起已是底牌/埋牌区),
//换整段空号 2100–2135 比给别的 View 重新编号更安全。
HAND_MARK_1: 2100,
HAND_MARK_2: 2101,
HAND_MARK_3: 2102,
HAND_MARK_4: 2103,
HAND_MARK_5: 2104,
HAND_MARK_6: 2105,
HAND_MARK_7: 2106,
HAND_MARK_8: 2107,
HAND_MARK_9: 2108,
HAND_MARK_10: 2109,
HAND_MARK_11: 2110,
HAND_MARK_12: 2111,
HAND_MARK_13: 2112,
HAND_MARK_14: 2113,
HAND_MARK_15: 2114,
HAND_MARK_16: 2115,
HAND_MARK_17: 2116,
HAND_MARK_18: 2117,
HAND_MARK_19: 2118,
HAND_MARK_20: 2119,
HAND_MARK_21: 2120,
HAND_MARK_22: 2121,
HAND_MARK_23: 2122,
HAND_MARK_24: 2123,
HAND_MARK_25: 2124,
HAND_MARK_26: 2125,
HAND_MARK_27: 2126,
HAND_MARK_28: 2127,
HAND_MARK_29: 2128,
HAND_MARK_30: 2129,
HAND_MARK_31: 2130,
HAND_MARK_32: 2131,
HAND_MARK_33: 2132,
HAND_MARK_34: 2133,
HAND_MARK_35: 2134,
HAND_MARK_36: 2135
}
};
+19 -1
View File
@@ -41,11 +41,29 @@ t.eq('声音资源均 >= 101', soundVals.every(v => v >= 101), true); // T-20
// ---- 精灵 ID 1001–2999(段内 3000 已被平台占用,清单 §0.3)----
const index = EQW_SpriteIndex.build(EQW_Sprites);
const spriteVals = Object.keys(index).map(k => index[k]);
t.eq('精灵数量 > 200', spriteVals.length > 200, true);
// 钉住精确数量:松下界(如 >200)删掉整个 View 都还能通过。
// 增删精灵时连同本数字一起改——有意的顺手更新,不是有意的就红给你看
t.eq('精灵总数', spriteVals.length, 387);
const spriteOk = spriteVals.every(v => v >= 1001 && v <= 2999);
if (!spriteOk) { console.log('越界精灵: ' + JSON.stringify(spriteVals.filter(v => v < 1001 || v > 2999))); }
t.eq('精灵落在 1001-2999', spriteOk, true);
// ---- 手牌标记与手牌一一对应(清单 §1.6:三种标记互斥、【每张牌】至多一个)----
// core/CardMark.js 也是按每张牌返回标记的:一手 28 张常带 13 个以上标记、36 张埋牌手更多,
// 标记精灵必须与手牌等量,否则渲染时必然有牌的标记画不出来
const groupMap = EQW_SpriteIndex.buildGroupMap(EQW_Sprites);
const handPairing = [];
for (let i = 1; i <= 36; i++) {
if (!index.hasOwnProperty('HAND_CARD_' + i)) { handPairing.push('缺 HAND_CARD_' + i); }
if (!index.hasOwnProperty('HAND_MARK_' + i)) { handPairing.push('缺 HAND_MARK_' + i); }
else if (groupMap['HAND_MARK_' + i] !== groupMap['HAND_CARD_' + i]) {
handPairing.push('HAND_MARK_' + i + ' 与手牌不同群组');
}
}
if (handPairing.length) { console.log('手牌标记配对问题:\n ' + handPairing.join('\n ')); }
t.eq('手牌标记与手牌 1..36 一一对应', handPairing, []);
t.eq('手牌标记恰好 36 个(无第 37 个)', index.hasOwnProperty('HAND_MARK_37'), false);
// ---- 各类 ID 全局不重复 ----
function dupsOf(vals) {
const seen = {}, dups = [];
+2 -1
View File
@@ -82,6 +82,7 @@ let realOk = true;
let realIndex = {};
try { realIndex = EQW_SpriteIndex.build(EQW_Sprites); } catch (e) { realOk = false; console.log('建索引失败: ' + e.message); }
t.eq('真实精灵常量无重复键', realOk, true);
t.eq('真实精灵数量 > 200', Object.keys(realIndex).length > 200, true);
// 钉住精确数量(与 test_constants.js 同一个数):松下界删掉整个 View 都还能通过
t.eq('真实精灵数量', Object.keys(realIndex).length, 387);
process.exit(t.done('spriteindex') ? 0 : 1);