diff --git a/client/js/01_SubGame/codes/core/CardCodec.js b/client/js/01_SubGame/codes/core/CardCodec.js new file mode 100644 index 0000000..498b066 --- /dev/null +++ b/client/js/01_SubGame/codes/core/CardCodec.js @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////// +////////// EQW_CardCodec: 牌 id → 牌面资源帧号(纯逻辑)////////// +/////////////////////////////////////////////////////////////// +// 清单 §0.4:牌面资源统一 10 列 × 6 行 = 60 帧,行优先编号 +// 帧 1–13 黑桃 A–K / 14–26 红桃 / 27–39 梅花 / 40–52 方块 +// 帧 53 小王 / 54 大王 / 55–60 牌背 1–6(二七王用帧 55) +// 服务端牌 id 的花色段序是 方块→梅花→红心→黑桃(class.pai.js:16), +// 与美术帧的花色顺序【正好相反】,转换必须把花色段反过来数。 +// 【全前端只此一处实现】其余模块一律调用它,不得另写一份。 +var EQW_CardCodec = EQW_CardCodec || { + + //牌背帧号(二七王固定用牌背 1) + CARD_BACK_FRAME: 55, + + //牌 id → 牌面资源帧号。deck1 与 deck2 的同一张牌共用同一帧(牌面完全相同) + cardIdToFrame: function (cardId) { + var n = cardId % 54; // 去掉副数 + if (n === 52) { return 53; } // 小王 + if (n === 53) { return 54; } // 大王 + return (3 - Math.floor(n / 13)) * 13 + (n % 13) + 1; + } +}; diff --git a/client/tests/test_cardcodec.js b/client/tests/test_cardcodec.js new file mode 100644 index 0000000..a6447b7 --- /dev/null +++ b/client/tests/test_cardcodec.js @@ -0,0 +1,57 @@ +// cardId → 牌面帧号(清单 §0.4 唯一权威转换) +const { load } = require('./_load'); +const t = require('./_assert')(); + +load('client/js/01_SubGame/codes/core/CardCodec.js'); + +// ---- 清单 §0.4 的 10 条校验样例,逐条锁死 ---- +const cases = [ + [0, 40, '方块A'], + [4, 44, '方块5'], + [12, 52, '方块K'], + [13, 27, '梅花A'], + [26, 14, '红桃A'], + [39, 1, '黑桃A'], + [51, 13, '黑桃K'], + [52, 53, '小王'], + [53, 54, '大王'], + [106, 53, '小王(deck2)'] +]; +cases.forEach(c => t.eq('帧号 ' + c[2] + ' id=' + c[0], EQW_CardCodec.cardIdToFrame(c[0]), c[1])); + +// ---- 两副牌同一张牌共用同一帧 ---- +for (let id = 0; id < 54; id++) { + if (EQW_CardCodec.cardIdToFrame(id) !== EQW_CardCodec.cardIdToFrame(id + 54)) { + t.eq('deck1/deck2 同帧 id=' + id, false, true); + } +} +t.eq('deck1/deck2 全部同帧', true, true); + +// ---- 帧号值域:54 张牌只落在 1–54 ---- +let inRange = true; +for (let id = 0; id < 108; id++) { + const f = EQW_CardCodec.cardIdToFrame(id); + if (!(f >= 1 && f <= 54)) { inRange = false; } +} +t.eq('帧号值域 1-54', inRange, true); + +// ---- 单射:deck1 的 54 张牌映射出 54 个互不相同的帧 ---- +const seen = {}; +let dup = false; +for (let id = 0; id < 54; id++) { + const f = EQW_CardCodec.cardIdToFrame(id); + if (seen[f]) { dup = true; } + seen[f] = true; +} +t.eq('54 张牌帧号互不重复', dup, false); +t.eq('恰好覆盖 54 个帧', Object.keys(seen).length, 54); + +// ---- 二七王不使用 3、4 的帧(design §2 去掉 3 和 4)---- +// 方块3 id=2 → 帧42,方块4 id=3 → 帧43;资源仍按 60 帧通用排版出图,只是不引用 +t.eq('方块3 帧号', EQW_CardCodec.cardIdToFrame(2), 42); +t.eq('方块4 帧号', EQW_CardCodec.cardIdToFrame(3), 43); + +// ---- 牌背常量 ---- +t.eq('牌背帧', EQW_CardCodec.CARD_BACK_FRAME, 55); + +process.exit(t.done('cardcodec') ? 0 : 1);