Files
erqiwang_youle/client/js/01_SubGame/codes/shared/cards.js
T
joywayerandClaude Opus 5 d287ce5c8c 二七王:新增根目录 shared 同步脚本与前端只读副本
同步是跨端动作(源在 server、目标在 client),脚本放仓库根目录。
只提供服务端→前端一个方向;前端副本只读,手改会被覆盖。
CLAUDE.md 常用命令一节同步收录。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:44:00 +08:00

251 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///////////////////////////////////////////////////////////////
////// youle_erqiwang_shared_cards: 前后端共享牌值算法 //////////
///////////////////////////////////////////////////////////////
// 【权威源】本文件是前后端共享算法的唯一可修改处。
// 前端副本 client/js/01_SubGame/codes/shared/cards.js 由仓库根目录的
// sync_shared.cmd 单向同步生成,为只读;任何改动都必须落在本文件,
// 改完跑一次 sync_shared.cmd,否则 client/tests/test_shared_sync.js 会红。
//
// 内容:牌值编码与牌型分组的纯函数,不依赖对局状态、不依赖平台 API。
// 牌编码区间约定(id_to_code 的产物,各处判定据此):
// 9554 大王 / 9553 小王 / 8000–9000 正7 / 7000–8000 副7
// 3000–4000 正2 / 2000–3000 副2 / 1000–2000 主花色普通牌 / 100–500 副牌普通牌
// ⇒ 主牌 ⟺ code > 1000
var youle_erqiwang_shared_cards = youle_erqiwang_shared_cards || {
//牌id转花色
id_to_flower: function(cardid){
if (cardid == 52 || cardid == 106){
//小王
return 5;
}
if (cardid == 53 || cardid == 107){
//大王
return 5;
}
return parseInt((cardid % 54) / 13) + 1;
},
//牌id转牌面数值
id_to_number: function(cardid){
if (cardid == 52 || cardid == 106){
//小王
return 53;
}
if (cardid == 53 || cardid == 107){
//大王
return 54;
}
return (cardid % 54) % 13 + 1;
},
//牌id转牌编码
id_to_code: function(mainflower, cardid){
if (cardid == 52 || cardid == 106){
//小王
return 9553;
}
if (cardid == 53 || cardid == 107){
//大王
return 9554;
}
var flower = youle_erqiwang_shared_cards.id_to_flower(cardid);
var number = youle_erqiwang_shared_cards.id_to_number(cardid);
var code = flower * 100 + number;
//特殊处理
switch (number)
{
case 1:
code = code + 13;
break;
case 2:
code = code + 2000;
break;
case 7:
code = code + 7000;
break;
}
//主牌花色处理
if (flower == mainflower){
code = code + 1000;
}
return code;
},
//从大到小排序(冒泡排序)
order_cards: function(mainflower, aryCardIDs){
if (aryCardIDs){
for (var i = 0; i < aryCardIDs.length; i++) {
for (var j = i + 1; j < aryCardIDs.length; j++) {
var i_code = youle_erqiwang_shared_cards.id_to_code(mainflower, aryCardIDs[i]);
var j_code = youle_erqiwang_shared_cards.id_to_code(mainflower, aryCardIDs[j]);
if (i_code < j_code) {
var tmp = aryCardIDs[j];
aryCardIDs[j] = aryCardIDs[i];
aryCardIDs[i] = tmp;
}
}
}
}
return aryCardIDs;
},
//判断两个牌是否是连续的
is_continuous: function(bigcode, smallcode){
//是小王
var is_xiaowang = function(_code){
if (_code == 9553){
return true;
}
return false;
}
//是正7
var is_zheng7 = function(_code){
if (_code > 8000 && _code < 9000){
return true;
}
return false;
}
//是负7
var is_fu7 = function(_code){
if (_code > 7000 && _code < 8000){
return true;
}
return false;
}
//是正2
var is_zheng2 = function(_code){
if (_code > 3000 && _code < 4000){
return true;
}
return false;
}
//是负2
var is_fu2 = function(_code){
if (_code > 2000 && _code < 3000){
return true;
}
return false;
}
//是主A
var is_zhuA = function(_code){
if (_code > 1000 && _code < 2000 && _code % 100 == 14){
return true;
}
return false;
}
//是8
var is_8 = function(_code){
if (_code % 100 == 8){
return true;
}
return false;
}
//是6
var is_6 = function(_code){
if (_code % 100 == 6){
return true;
}
return false;
}
//普通的连牌
if (bigcode - smallcode == 1){
return true;
}
//小王、正7
if (is_xiaowang(bigcode) && is_zheng7(smallcode)){
return true;
}
//正7、负7
if (is_zheng7(bigcode) && is_fu7(smallcode)){
return true;
}
//负7、正2
if (is_fu7(bigcode) && is_zheng2(smallcode)){
return true;
}
//正2、负2
if (is_zheng2(bigcode) && is_fu2(smallcode)){
return true;
}
//负2、主A
if (is_fu2(bigcode) && is_zhuA(smallcode)){
return true;
}
//8、6(design §5.3:7 不与 6/8 相连,6 与 8 相连)
//必须是同一花色的 8 与 6:牌编码同花色相差 2(主花色 1408-1406=2、副牌 308-306=2),
//跨花色则相差 100 的倍数。只判 %100 会把「♥8 + ♣6」误判为连对,
//进而在 get_chongguan 扫描整手牌时让副牌的 6 对错误接续主 8、多算奖(design §8.1 连对链)
if (is_8(bigcode) && is_6(smallcode) && (bigcode - smallcode == 2)){
return true;
}
return false;
},
//获取对子列表,cards为同一花色的排过序的牌列表
get_pairlist: function(mainflower, flowercards){
var pairlist = [];
var i = 0;
while (i < flowercards.length - 1){
//牌编码,两张牌两张牌一取
var code_i = youle_erqiwang_shared_cards.id_to_code(mainflower, flowercards[i]);
var code_j = youle_erqiwang_shared_cards.id_to_code(mainflower, flowercards[i + 1]);
if (code_i == code_j){
pairlist.push([flowercards[i], flowercards[i + 1]]);
i = i + 2;
} else {
i++;
}
}
return pairlist;
},
//获取拖拉机列表,pairlist为同一花色的排过序的对子列表,cardtype为拖拉机牌型
get_tuolaji_list: function(mainflower, pairlist, cardtype){
var tuolaji = [];
var count = cardtype - 300; //拖拉机的对子数量
var i = 0;
for (var i = 0; i < pairlist.length - count + 1; i++){
//每次按拖拉机的对子数量取N对
var tmplist = pairlist.slice(i, i + count);
//判断是否是cardtype类型的拖拉机
var is_tlj = true;
for (var j = 0; j < tmplist.length - 1; j++) {
var code_j1 = youle_erqiwang_shared_cards.id_to_code(mainflower, tmplist[j][0]);
var code_j2 = youle_erqiwang_shared_cards.id_to_code(mainflower, tmplist[j+1][0]);
if (!youle_erqiwang_shared_cards.is_continuous(code_j1, code_j2)){
is_tlj = false;
break;
}
}
if (is_tlj){
var tlj = [];
for (var k = 0; k < tmplist.length; k++){
tlj = tlj.concat(tmplist[k]);
}
tuolaji.push(tlj);
}
}
return tuolaji;
},
//主牌归一化大小(副7 同级取 7000、副2 同级取 2000,其余用牌编码),仅用于甩牌分量比大小
trump_rank: function(mainflower, cardid){
var code = youle_erqiwang_shared_cards.id_to_code(mainflower, cardid);
if (code > 7000 && code < 8000){ //副7
return 7000;
}
if (code > 2000 && code < 3000){ //副2
return 2000;
}
return code;
},
}
//Node 导出;友乐/浏览器无 module 时跳过(dev-guide 01 §1)
if (typeof module !== "undefined"){
module.exports = youle_erqiwang_shared_cards;
}