'use strict'; //// 为什么选择 Lodash ? //// Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。 //// Lodash 的模块化方法 非常适用于: //// 遍历 array、object 和 string //// 对值进行操作和检测 //// 创建符合功能的函数 var _ = require('lodash'); var quick = require('quick-pomelo'); var logger = quick.logger.getLogger('fhmj', __filename); // 所有牌 const CARDS = [ 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条 // 51, // 中 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条 // 51, // 中 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条 // 51, // 中 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条 // 51, // 中 ]; // 块类型 const STYLE = { NULL: 0, // 无效 CHI: 1, // 吃牌 SUN: 2, // 顺序 PENG: 3, // 碰子 KE: 4, // 刻子 GANG: 5, // 杠子 ANGANG: 6, // 暗杠 ZMGANG: 7, // 自摸明杠 BU: 8, // 补子 ANBU: 9, // 暗补 ZMBU: 10, // 自摸明补 // LIANGBD:9, // TL++两张百搭和一张普通牌组成一个块 // SANBD:10, // TL++三张百搭和一张普通牌组成一个块 }; // 椅子数 const CHAIR_COUNT = 4; const CARDS_COUNT = 13; // 构造方法 var Logic = function (type,gameKindTL,playerAllCount,other) { // 类型 this.type = type; this.other = other;//////TL++2人3人的游戏规则 this.jiangmaCount = 2;////奖码张数(抓鸟张数) this.kexuanList = [0,0,0,0]; if(this.other & 1){ this.kexuanList[0] = 1;//勾选了中途大四喜 } if(this.other & 2){ this.kexuanList[1] = 1;//勾选了中途六六顺 } if(this.other & 4){ this.kexuanList[2] = 1;//勾选了门清 } if(this.other & 256){ this.kexuanList[3] = 1;//勾选了小胡只能自摸 } this.hzCount = 0;/////红中个数 this.fengDingType = 0;/////封顶类型1:不封顶;2:封顶56分;3:封顶112分; if(this.other & 8){ this.fengDingType = 1; } else if(this.other & 16){ this.fengDingType = 2; } else if(this.other & 32){ this.fengDingType = 3; } this.ZNJSType = 0;/////中鸟结算类型1:中鸟相加;2:中鸟相乘; if(this.other & 64){ this.ZNJSType = 1; } else if(this.other & 128){ this.ZNJSType = 2; } this.gameKindTL = 1;//1:传统;2:割索;3:疯狂 if(this.other & 512){ this.gameKindTL = 2; } // else if(gameKindTL == 3){ // this.gameKindTL = 3;//疯狂 // this.hzCount = 4;/////红中个数 疯狂模式默认为4张红中 // } this.isZNZM = false;/////是否只能自摸,拉杠情况可以胡 // console.warn("封顶类型1:不封顶;2:封顶56分;3:封顶112分 "+this.fengDingType) // console.warn("中鸟结算类型1:中鸟相加;2:中鸟相乘 "+this.ZNJSType) // console.warn("logic可选列表 111 "+this.kexuanList) // 七对 // this.has7d = true;/////TL++因为奉化麻将当中本身就可以胡7对 // 全牌 var cards = _.clone(CARDS); // 添加红中红中 // if (this.hzCount > 0){ // for (let i = 0; i < this.hzCount; ++i) { // cards[cards.length] = 51; // } // } this.castCount = 0; this.disCount = 0; this.lastCount = cards.length;//////设置剩余牌数为了测试海底捞月 this.cardsPool = cards; this.cardsyl = _.clone(cards); console.warn(" this.cardsyl "+this.cardsyl+" lastCount "+this.lastCount); //////以下变量全是TL++ this.playerAllCount = playerAllCount || 4;////游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局 this.setCardFilerIndex = 0 this.baiDaCard = 0;/////TL++,拿到百搭牌 // this.baiDaList = [0,0,0];/////TL++,拿到百搭牌数组 // this.sbyBDList = []//////得到某人手中的百搭牌数组 this.chuPaiCountTL = 0//////TL++,记录出牌的个数,为了判断天胡和地胡 this.moPaiCountTL = 0//////TL++,记录出牌的个数,为了判断天胡和地胡 this.lastMoPaiChairID = 0//////TL++,最后一个摸牌玩家的id this.addThisIsHu = 0//////TL++,胡牌判断时加上这张能不能胡 this.isSeleCatcedCard = false//////判断能否胡牌的那张牌是自己抓的还是别人打出来的 this.currChairIDTL = 0/////当前判断胡的chairID,用于得到当前玩家的胡牌情况 this.isGGMG = [false,false,false,false];//////TL++,是否刚刚直杠(明杠)用于判断是否是直杠杠开 this.isGGAG = [false,false,false,false];//////TL++,是否刚刚暗杠用于判断是否暗杠杠开 this.isGGFXG = [false,false,false,false];//////TL++,是否刚刚风险杠用于判断是否风险杠杠开 this.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡 this.isGuoHuList = [[false,-1],[false,-1],[false,-1],[false,-1],]/////TL++,各个玩家在本轮是否点击了过胡和点击过牌时的台数 this.setCardFileName = '';/////设置手牌的文件名 this.cardGroupIndex = 0;////要设置的牌型种类 this.isZHYZ = false;/////是不是最后1张 this.isMZWF = [0,1,2,3];/////是不是满足位风 /////TL++每个人满足的的起手胡胡牌类型 this.everyQSHType = [ [],[],[],[] ] this.canSelects = [//各个起手胡玩家可以选择的牌型 [],[],[],[] ]; /////TL++每个人满足的的起手胡胡牌类型操作过的牌 this.everyQSHCZGList = [ [],[],[],[] ] /////TL++每个人满足的的起手胡胡牌类型操作过的牌 this.everyQSHCZGList2 = [ [],[],[],[] ] this.qshuTypeTL = [ /////分别表示起手胡牌型和台数 ["四喜",2,], ///// 0 起完牌后,玩家手上已有四张一样的牌; ["板板胡",2,], ///// 1 起完牌后,玩家手上没有一张2、5、8牌; ["缺一色",2,], ///// 2 起完牌后,玩家手上筒、索、万任缺一门; ["六六顺",2,], ///// 3 起完牌后,玩家手上已有2个刻子(刻子:三个一样的牌); ["中途四喜",2,], ///// 4 玩家在牌局过程中,手中有四张相同的牌; ["中途六六顺",2,], ///// 5 起完牌后,玩家手上已有2个刻子(刻子:三个一样的牌); // ["节节高",2,], ///// 4 起完牌后,起完牌后,玩家手上有3连对且同花色;(例如2个3万,2个4万,2个5万); // ["三同",2,], ///// 5 起完牌后,玩家手上有3对点数相同的牌;(例如2个3万,2个3筒,2个3条) // ["单将一枝花",2,], ///// 6 起完牌后,玩家手上只有一张将牌(2、5、8),且这只将牌为“5”; // ["单五一枝花",2,], ///// 7 起完牌后,玩家手上只有一张将牌(2、5、8),且这只将牌为“5”; ] this.everyXiaoHuList = [ [],[],[],[] ];//每个玩家的起手胡牌型用于算分 /////TL++每个人满足的的大胡胡牌类型 this.everyDAHType = [ [],[],[],[] ] this.dahuTypeTL = [ /////分别表示大胡牌型和台数 // ["天胡",6,], ///// 0 单指庄家,庄家起牌后,即已经胡牌。(需要2、5、8做将) // ["地胡",6,], ///// 1 指闲家,当庄家打出第一张牌时,给闲家点炮。(需要2、5、8做将); ["七小对",7,], ///// 0 胡牌时,手上任意七对将牌(无需2、5、8做将); ["豪华七小对",7,],///// 1 手上任意七对牌,且其中有4张一样的牌(不能杠,算作2对); ["双豪华七小对",7,],///// 2 手上任意七对牌,且其中有2种4张一样的牌(不能杠,算作2对); ["三豪华七小对",7,],///// 13手上任意七对牌,且其中有3种4张一样的牌(不能杠,算作2对); ["将将胡",7,], ///// 4 玩家手上每一张牌都为2、5、8; ["全求人",7,], ///// 5 玩家通过吃、碰、杠而使得最后手中只剩下一颗牌,当摸或其他玩家打出这张牌时,即可胡牌; ["门清",7,], ///// 6 玩家没有吃、碰、杠等操作,胡牌时手上有14张牌,自己摸到的算门清别人打的不算门清; ["清一色",7,], ///// 7 玩家手中的牌全部由同一种花色(万、筒、条)组成; ["碰碰胡",7,], ///// 8 碰碰胡:玩家所有的牌均为刻子或将牌,乱将(无需2、5、8做将),可碰,可杠,可自摸; ["杠开(杠炮)",7,], ///// 9 自己杠上开花(需要2、5、8做将) ["抢杠胡",7,], ///// 10 (需要2、5、8做将); ["海底胡",7,], ///// 11 最后一张牌为海底牌。玩家选择要海底牌且通过这张海底牌胡牌,则为海底捞月,(是否需要2、5、8将根据当前牌型决定) // ["杠上炮",7,], ///// 10 单指庄家,庄家起牌后,即已经胡牌。(需要2、5、8做将) // ["海底炮",7,], ///// 11 单指庄家,庄家起牌后,即已经胡牌。(需要2、5、8做将) ] // console.warn("ppppppppppp 长度 "+cards.length+" cards "+cards); }; Logic.setHCfileNameList =[/////全部设置牌型的文件名 "setHandCard_tianhu", ] // 导出常量 Logic.CARDS = CARDS; Logic.STYLE = STYLE; Logic.CHAIR_COUNT = CHAIR_COUNT; Logic.CARDS_COUNT = CARDS_COUNT; // 导出类 module.exports = Logic; // 原型对象 var proto = Logic.prototype; /////TL++为了得到百搭牌数组用于判断是否需要补花和手牌中百搭牌个数 // proto.setBDList = function () { // this.baiDaList = [this.baiDaCard,this.baiDaCard,this.baiDaCard]/////TL++,拿到百搭牌 // }; ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡 proto.chuPaiTL = function () { // console.warn("111c天胡判断不正确",this.chuPaiCountTL); this.chuPaiCountTL += 1//////这个其实并不是真实的出牌个数,因为这个方法的调用在判断吃碰杠胡之前调用的 } ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡 proto.moPaiTL = function () { // console.warn("111c天胡判断不正确",this.chuPaiCountTL); this.moPaiCountTL += 1//////TL++,记录出牌的个数,为了判断天胡和地胡 += 1 } ///////TL++重置默认数据,在每局游戏开始的洗牌函数中调用 proto.resetDataOnGameStart = function () { for (let i = 0; i < this.everyQSHType.length; ++i) { this.everyQSHType[i] = [] } for (let i = 0; i < this.everyQSHCZGList.length; ++i) { this.everyQSHCZGList[i] = [] } for (let i = 0; i < this.everyQSHCZGList2.length; ++i) { this.everyQSHCZGList2[i] = [] } for (let i = 0; i < this.everyXiaoHuList.length; ++i) { this.everyXiaoHuList[i] = [] } for (let i = 0; i < this.everyDAHType.length; ++i) { this.everyDAHType[i] = [] } this.chuPaiCountTL = 0//////TL++出牌个数 this.moPaiCountTL = 0//////TL++,记录摸牌的个数,为了判断天胡和地胡 this.lastMoPaiChairID = 0//////TL++,最后一个摸牌玩家的id this.addThisIsHu = 0//////TL++,胡牌判断时加上这张能不能胡 this.isSeleCatcedCard = false//////判断能否胡牌的那张牌是自己抓的还是别人打出来的 this.currChairIDTL = 0/////当前判断胡的chairID,用于得到当前玩家的花牌情况 this.isGGMG = [false,false,false,false];;//////TL++,是否刚刚直杠(明杠)用于判断是否是直杠杠开 this.isGGAG = [false,false,false,false];//////TL++,是否刚暗杠用于判断是否暗杠杠开 this.isGGFXG = [false,false,false,false];//////TL++,是否刚刚风险杠用于判断是否风险杠杠开 this.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡 this.isGuoHuList = [[false,-1],[false,-1],[false,-1],[false,-1],]/////TL++,各个玩家在本轮是否点击了过胡和点击过牌时的台数 this.isZHYZ = false;/////是不是最后1张 } // 重新洗牌 proto.shuffle = function () { this.castCount = 0; this.disCount = 0; this.cardsPool = _.clone(this.cardsyl); this.lastCount = this.cardsPool.length; this.cardsPool = _.shuffle(this.cardsPool);////随机打乱一个数组 this.cardsPool = _.shuffle(this.cardsPool);////洗第二次牌 // this.cardsPool = _.shuffle(this.cardsPool);////洗第三次牌 }; // 填充数组 proto.fillDeep = function (array, o, isMore) { for (let i = 0; i < array.length; ++i) { if (!isMore) { array[i] = _.clone(o); } else { array[i] = _.cloneDeep(o);/////深度拷贝,就是重新分配内存空间,浅拷贝则是两个变量共用一个内存对象 } } return array; }; //////TL++ 深复制一个object类型的数据 proto.deepCloneTL = function (obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(let key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&& typeof obj[key] ==="object"){ objClone[key] = this.deepCloneTL(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; }; // 获取类型 proto.getType = function (card) { return Math.floor(card / 10); }; // 获取牌值 proto.getValue = function (card) { return card % 10; }; // 手牌排序 proto.sort = function (handCards) { return _.sortBy(handCards);///降序排序 }; // 删除手牌 /////TL++参数isBuHua表示是否因为补花而造成的删除牌 proto.remove = function (handCards, cards) { if (typeof (cards) == 'number') { if (cards == handCards[handCards.length - 1]) { return (handCards.pop(), true); } else { let pos = handCards.indexOf(cards); if (pos == -1) return false; return (handCards.splice(pos, 1), true); } } var length = cards.length; if (length > 1 && cards[0] == cards[length - 1]) { if (cards[0] == handCards[handCards.length - 1]) { handCards.pop(); length -= 1; } let pos = handCards.indexOf(cards[0]); if (pos == -1) return false; handCards.splice(pos, length); } else { for (let i = 0; i < length; ++i) { let pos = handCards.indexOf(cards[i]); if (pos == -1) return false; handCards.splice(pos, 1); } } return true; }; // 调整手牌 proto.adjust = function (handCards) { var length = handCards.length; if (length < 2) return false; if (handCards[length - 1] < handCards[length - 2]) { let moCard = handCards.pop(); let pos = _.findIndex(handCards, (i) => (i >= moCard)); if (pos == -1) handCards.push(moCard); else handCards.splice(pos, 0, moCard); } return true; }; // 投骰子 proto.dice = function () { return _.random(1, 6); }; // 剩余牌数 proto.leaveCount = function () { return this.lastCount; }; //////TL++,人工设置测试牌型 proto.setTestSendCardsTL = function () { this.setCardFileName = ''; let fileName = "setHandCard_tianhu" if(!fileName) return;/////文件名字不存在 // console.warn("设置手牌的文件名",fileName); this.setCardFileName = fileName delete require.cache[require.resolve('./setcard/' + fileName)]; var SetHandCardTL = require('./setcard/' + fileName); if(!SetHandCardTL) return; //////TL++,设置手牌的文件 this.setHandCardTL = new SetHandCardTL(); ////console.error("洗牌之后的牌",this.cardsPool); let ccc = this.setHandCardTL.getSCFP(this.cardGroupIndex) if(ccc){//////已经设置的手牌发完了就随机发牌 this.cardsPool = ccc/////设置手牌的地方 设置牌 this.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型 // SetHandCardTL.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型 // if(SetHandCardTL.cardGroupIndex == 1) SetHandCardTL.cardGroupIndex = 0 } else{ this.setCardFilerIndex += 1; this.cardGroupIndex = 0; // SetHandCardTL.cardGroupIndex = 0; if(Logic.setCardFilerIndex < Logic.setHCfileNameList.length) this.setTestSendCardsTL() } } // 初始手牌 proto.handCards = function (chBanker,_PJHF,_over,recordid,_ctime) { this.resetDataOnGameStart()//////TL++ this.shuffle(); // if(this.hzCount == 8) { // this.cardsPool = [21,51,33,33,15,26,24,29,26,35,14,29,17,11,19,14,13,38,29,35,23,51,17,51,27,19,33,28,22,21,17,51,21,13,38,34,39,39,38,34,26,14,36,33,37,39,19,27,17,37,12,24,28,31,32,22,11,23,12,15,25,29,34,36,16,36,18,12,21,11,32,13,11,22,19,38,24,15,35,32,16,27,39,37,31,18,51,28,16,51,25,27,32,16,51,14,31,18,51,35,15,26,23,28,22,34,12,36,31,25,23,37,13,25,18,24] // this.setTestSendCardsTL()///////设置手牌的地方,设置发牌 不需要设置的时候注释掉这个方法就可以了 // this.lastCount = this.cardsPool.length;//////设置剩余牌数设置剩余牌数,测试完这句要删掉 // } let dqjs = _over + 1; _PJHF.writexpJson(this.deepCloneTL(this.cardsPool),dqjs,recordid,_ctime); //// 下面这个是随机发牌但是起手发lzgs张癞子的逻辑 // let lzgs = 6//癞子个数 // let djg = 0; // for (let i = 0; i < this.cardsPool.length; i++) { // if(this.cardsPool[i] == 51){ // let xx = this.cardsPool[djg] // this.cardsPool[djg] = 51; // this.cardsPool[i] = xx; // djg++ // if(djg >= lzgs){ // break // } // } // } /////TL++设置百搭牌数组 // this.setBDList() var result = []; var castCount = 0; for (let i = 0; i < this.playerAllCount; ++i) { let cardCount = CARDS_COUNT; if (i == chBanker) cardCount += 1; let cards = this.cardsPool.slice(castCount, castCount + cardCount); castCount += cardCount; result.push({ cards: this.sort(cards) }); } this.castCount += castCount this.lastCount -= castCount; // this.lastCount -= this.disCountTL;////因为翻出来的百搭牌不能被摸走 // console.error("发的手牌",result); return result; }; // 是否无牌 proto.isNoCards = function () { return this.lastCount <= 0; }; // 摸牌函数 proto.moCard = function (isgang) { // console.error("摸排摸排--------isgang ",isgang,this.disCountTL,this.lastCount); var card = 0; if(isgang){ let card1 = 0; if (this.lastCount > 1) { card1 = this.cardsPool[this.castCount++]; this.lastCount -= 1; } let card2 = 0; if (this.lastCount > 0) { card2 = this.cardsPool[this.castCount++]; this.lastCount -= 1; } return { card1: card1,card2: card2 }; } else{ if (this.lastCount > 0) { card = this.cardsPool[this.castCount++]; this.lastCount -= 1; } } return { card: card }; }; // 是否将牌 proto.isJang = function (lcard, rcard) { return lcard == rcard; }; ////判断吃碰补之后是否只剩下百搭牌了,因为如果吃碰补之后只剩下百搭牌,而百搭牌又不允许打出会造成玩家无牌可出的局面 proto.isCanCPB = function (handCards,opeate,type) { return true;//非疯狂没有红中不存在这个问题 } // 可否碰牌 proto.isPeng = function (handCards, card) { if(Array.isArray(handCards)){ for (let i = 0; i < handCards.length - 1; ++i) { if (handCards[i] == card && handCards[i + 1] == card) { return true; } } } return false; }; // 碰牌 TL++参数chirID为了判断圈风和位风 proto.peng = function (chirID,handCards, card) { if (this.isPeng(handCards, card)) { return { style: STYLE.PENG, cards: [card, card, card], disc: [card] }; } }; // 吃牌,1-@**左吃, 2-*@*中吃, 3-@**右吃 proto.chi = function (handCards, card, type) { var chis = this.chiAnalyze(handCards, card, type); if (chis[0]) { let res = { style: STYLE.CHI, type: type, disc: [card] }; if (type == 1) { res.cards = [card, card + 1, card + 2]; if (this.getValue(card) < 7) { res.disc.push(card + 3); } } else if (type == 2) { res.cards = [card - 1, card, card + 1]; } else { res.cards = [card - 2, card - 1, card]; if (this.getValue(card) > 3) { res.disc.push(card - 3); } } return res; } }; // 杠牌,1-普通杠, 2-暗杠, 3-自摸明杠 TL++参数chirID为了判断圈风和位风 proto.gang = function (chirID,handCards, card, type) { // 结果 var res = null; // 明杠 if (type == 1) { let gang = this.gangAnalyze(handCards, card); if (gang) { res = { style: STYLE.GANG, cards: [card, card, card] }; } } // 暗杠 else if (type == 2) { let anGang = this.anGangAnalyze(handCards, card); if (anGang[0]) { res = { style: STYLE.ANGANG, cards: [card, card, card] }; } } return res; }; // 自摸明杠,1-普通杠, 2-暗杠, 3-自摸明杠 TL++参数chirID为了判断圈风和位风 proto.zmGang = function (chirID,handCards, huCards, card) { var zmGang = this.zmGangAnalyze(handCards, huCards, card); if (zmGang[0]) { return { style: STYLE.ZMGANG, cards: [card, card, card] }; } }; // 补牌,1-普通补, 2-暗补, 3-自摸明补 TL++参数chirID为了判断圈风和位风 proto.bu = function (chirID,handCards, card, type) { // 结果 var res = null; // 明补 if (type == 1) { let bu = this.buAnalyze(handCards, card); if (bu) { res = { style: STYLE.BU, cards: [card, card, card] }; } } // 暗补 else if (type == 2) { let anBu = this.anBuAnalyze(handCards, card); if (anBu[0]) { res = { style: STYLE.ANBU, cards: [card, card, card] }; } } return res; }; // 自摸明补,1-普通补, 2-暗补, 3-自摸明补 TL++参数chirID为了判断圈风和位风 proto.zmBu = function (chirID,handCards, huCards, card) { var zmBu = this.zmBuAnalyze(handCards, huCards, card); if (zmBu[0]) { return { style: STYLE.ZMBU, cards: [card, card, card] }; } }; // 吃牌分析,1-@**左吃, 2-*@*中吃, 3-@**右吃, type可以不传 proto.chiAnalyze = function (handCards, card, type) { // 结果集合 var result = []; // 排除风字 if(!Array.isArray(handCards)) { return result; } if (handCards.length < 2 || card > 40) return result; // 查找句子 var length = handCards.length; for (let i = 0; i < length; ++i) { // 牌面值 let value = this.getValue(card); // @**左吃,吃类型(可以不指定) if (!type || type == 1) { if (value < 8 && i < length - 1) { if (handCards[i] == card + 1 && handCards[i + 1] == card + 2) { result.push({ type: 1, card: card }); } } } // *@*中吃,吃类型(可以不指定) if (!type || type == 2) { if (value > 1 && value < 9 && i < length - 1) { if (handCards[i] == card - 1 && handCards[i + 1] != card - 1) { for (let j = i + 1; j < i + 5 && j < length; ++j) { if (handCards[j] == card + 1) { result.push({ type: 2, card: card }); break; } } } } } // **@右吃,吃类型(可以不指定) if (!type || type == 3) { if (value > 2 && i < length - 1) { if (handCards[i] == card - 2 && handCards[i + 1] == card - 1) { result.push({ type: 3, card: card }); } } } } return result; }; // 普通杠分析,1-普通杠, 2-暗杠, 3-自摸明杠 proto.gangAnalyze = function (handCards, card) { // 结果对象 var result = null; var length = handCards.length; if (length < 3) return result; // 查找同牌 for (let i = 0; i < length - 2; ++i) { if (handCards[i] == card && handCards[i + 1] == card && handCards[i + 2] == card) { result = { type: 1, card: card }; break; } } return result; }; // 暗杠分析,1-普通杠, 2-暗杠, 3-自摸明杠, card可以不传 proto.anGangAnalyze = function (handCards, card) { // 结果对象 var result = []; var length = handCards.length; if (length < 4) return result; // 查找同牌 var moCard = handCards[length - 1]; for (let i = 0; i < length - 3; ++i) { // 指定杠牌,可以不指定 if (card && handCards[i] != card) continue; // 判定是否刻子 if (handCards[i] == handCards[i + 1] && handCards[i] == handCards[i + 2]) { // 手上有杠牌 if (handCards[i] == handCards[i + 3]) { result.push({ type: 2, card: handCards[i] }); } // 刚摸到杠牌 else if (handCards[i] == moCard) { result.push({ type: 2, card: moCard }); } } } return result; }; // 自摸杠分析,1-普通杠, 2-暗杠, 3-自摸明杠, card可以不传 proto.zmGangAnalyze = function (handCards, huCards, card) { // 返回结果 var result = []; // 遍历句子 for (let i = 0; i < huCards.length; ++i) { if (huCards[i].style != STYLE.PENG) { continue; } let _card = huCards[i].cards[0]; if (card && _card != card) continue; let pos = handCards.indexOf(_card); if (pos != -1) { result.push({ type: 3, card: _card }); if (card) break; } } return result; }; // 普通补分析,1-普通补, 2-暗补, 3-自摸明补 proto.buAnalyze = function (handCards, card) { // 结果对象 var result = null; var length = handCards.length; if (length < 3) return result; // 查找同牌 for (let i = 0; i < length - 2; ++i) { if (handCards[i] == card && handCards[i + 1] == card && handCards[i + 2] == card) { result = { type: 1, card: card }; break; } } return result; }; // 暗补分析,1-普通补, 2-暗补, 3-自摸明补, card可以不传 proto.anBuAnalyze = function (handCards, card) { // 结果对象 var result = []; var length = handCards.length; if (length < 4) return result; // 查找同牌 var moCard = handCards[length - 1]; for (let i = 0; i < length - 3; ++i) { // 指定补牌,可以不指定 if (card && handCards[i] != card) continue; // 判定是否刻子 if (handCards[i] == handCards[i + 1] && handCards[i] == handCards[i + 2]) { // 手上有补牌 if (handCards[i] == handCards[i + 3]) { result.push({ type: 2, card: handCards[i] }); } // 刚摸到补牌 else if (handCards[i] == moCard) { result.push({ type: 2, card: moCard }); } } } return result; }; // 自摸补分析,1-普通补, 2-暗补, 3-自摸明补, card可以不传 proto.zmBuAnalyze = function (handCards, huCards, card) { // 返回结果 var result = []; // 遍历句子 for (let i = 0; i < huCards.length; ++i) { if (huCards[i].style != STYLE.PENG) { continue; } let _card = huCards[i].cards[0]; if (card && _card != card) continue; let pos = handCards.indexOf(_card); if (pos != -1) { result.push({ type: 3, card: _card }); if (card) break; } } return result; }; // 分析牌型 proto.parseBlock = function (card1, card2, card3) { // 刻子 if (card1 && card1 == card2 && card1 == card3) { return { style: STYLE.KE, cards: [card1, card2, card3] }; } // 顺子(排除风字) var cards = this.sort([card1, card2, card3]); if (cards[2] < 40) { if (cards[2] == cards[1] + 1 && cards[1] == cards[0] + 1) { return { style: STYLE.SUN, cards: cards }; } } }; // 得到等待数据更新类型,因为在杠后2张牌时就可能会出现2个玩家可碰或可杠或可补, // 而出现这种情况时规则是操作优先级高的玩家优先操作若相同操作时谁距离杠的玩家距离最近的玩家操作优先级高 // 如ABCD4个玩家A杠后两张牌为101和102,此时B可碰101C可碰102D可胡时,若B点碰后C点碰最后D点过之后 // 按照之前的逻辑就会出现B碰102(本应B碰101,由于等待碰等待数据里记录this.pengCard记录的是102),但是 // 实际B不能碰102就会判碰102失败导致卡住的bug proto.getDDGXType = function (type,chairId, ddcwj,gangch, ccount,masks) { let res = 0;//0:不更新等待操作数据,1:需将之前等待操作玩家的mask置0,2:需将等待数据设置回本次修改之前的 if(gangch == -1) return res;//不是杠后不会出现多个人等待同一个操作直接返回 if(ddcwj == -1) return res;//此操作目前没有等待的玩家 let czym = 0;//操作掩码 if(type == 1) czym = 5;//判断碰 else if(type == 2) czym = 9;//判断杠 else if(type == 3) czym = 33;//判断补 if(czym == 0) return res;//参数错误直接返回 let zjjl = 0; if((gangch + 1) % ccount == chairId) zjjl = 1; else if((gangch + 2) % ccount == chairId) zjjl = 2; else if((gangch + 3) % ccount == chairId) zjjl = 3; let qtjl = 0; if((gangch + 1) % ccount == ddcwj) qtjl = 1; else if((gangch + 2) % ccount == ddcwj) qtjl = 2; else if((gangch + 3) % ccount == ddcwj) qtjl = 3; if(zjjl > qtjl){ if(masks[ddcwj] == czym){ res = 2; return res } else{ return 0;//正常不应该走到这里来,能进这里都是有错误的 } } res = 1; return res }; // TL++,得到手牌中百搭牌的个数 proto.getBDCount = function (cards) { ////TL++,整个for循环判断手牌中的百搭牌个数 let baiDaCount = 0 for (let i = 0; i < cards.length; ++i) { if(cards[i] == this.baiDaCard) baiDaCount = baiDaCount + 1 } return baiDaCount } // TL++,得到手牌中百搭牌的shuzu数组 // proto.getBDListZZ = function (cards) { // this.sbyBDList = []//////重置某人手牌中的百搭牌数组 // ////TL++,整个for循环判断手牌中的百搭牌个数 // let baiDaCount = 0 // let baiDali = [] // for (let i = 0; i < cards.length; ++i) { // if(cards[i] == this.baiDaCard){ // baiDali[baiDaCount] = cards[i] // baiDaCount = baiDaCount + 1 // } // } // return baiDali // } // TL++,得到手牌中百搭牌的index数组 // proto.getBDIndexList = function (cards) { // ////TL++,整个for循环判断手牌中的百搭牌个数 // let baiDali = [] // for (let i = 0; i < cards.length; ++i) { // let cardTL = cards[i]; // if(this.baiDaList[0] && cardTL == this.baiDaList[0]) baiDali[baiDali.length] = i; // else if(this.baiDaList[1] && cardTL == this.baiDaList[1]) baiDali[baiDali.length] = i; // else if(this.baiDaList[2] && cardTL == this.baiDaList[2]) baiDali[baiDali.length] = i; // } // return baiDali // } // // TL++,得到手牌中百搭牌的index,用于删除手牌中的百搭牌 // proto.getBDIndex = function (cards) { // ////TL++,整个for循环判断手牌中的百搭牌个数 // let baiDali = [] // for (let i = 0; i < cards.length; ++i) { // let cardTL = cards[i]; // if(this.sbyBDList[0] && cardTL == this.sbyBDList[0]) baiDali[baiDali.length] = i; // if(this.sbyBDList[1] && cardTL == this.sbyBDList[1]) baiDali[baiDali.length] = i; // if(this.sbyBDList[2] && cardTL == this.sbyBDList[2]) baiDali[baiDali.length] = i; // } // return baiDali // } // TL++,得到默认手牌中百搭牌当的数组 cards: 手牌去除百搭之后的牌 proto.getBDMakeList = function (cards,isNeedAllZi) { if(cards.length == 0){ ////手上就剩百搭牌的时候 需要把所有牌都当一遍 let reslist = [ 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条 ] return reslist; } ////TL++,整个for循环按照手牌情况确定百搭牌当的范围 let makeList = this.deepCloneTL(cards) for (let i = 0; i < cards.length; ++i) { let cardTL = cards[i]; let type = this.getType(cardTL); let vale = this.getValue(cardTL); if(type < 4){ if(vale == 1){ let makeValue = cardTL + 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL + 2; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; } else if(vale == 9){ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL - 2; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; } else if(vale == 2){ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL + 1; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; let makeValue3 = cardTL + 2; if(makeList.indexOf(makeValue3) == -1) makeList[makeList.length] = makeValue3; } else if(vale == 8){ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL - 2; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; let makeValue3 = cardTL + 1; if(makeList.indexOf(makeValue3) == -1) makeList[makeList.length] = makeValue3; } else if(vale > 2 && vale < 8){ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL + 1; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; let makeValue3 = cardTL - 2; if(makeList.indexOf(makeValue3) == -1) makeList[makeList.length] = makeValue3; let makeValue4 = cardTL + 2; if(makeList.indexOf(makeValue4) == -1) makeList[makeList.length] = makeValue4; } } } // let makeList2 = makeList.concat([41,42,43,44,51,52,53])/////给当的数组拼接字牌 // var xx = [1,1,2,3,4,1,2] // var xx22 = _.uniq(xx) // console.warn("数组去重",xx,xx22);///[ 1, 1, 2, 3, 4, 1, 2 ] [ 1, 2, 3, 4 ] // xx[1] = 6 // console.warn("22数组去重",xx,xx22);////[ 1, 6, 2, 3, 4, 1, 2 ] [ 1, 2, 3, 4 ] return _.uniq(makeList); } // 提取成句 card:手上的所有牌删除2张用来做将的牌之后剩下的牌 整理是否为刻子或者顺子 proto._dumpFixed = function (cards, huCards) { // if(this.currChairIDTL == 0){ // console.error("sscc提取成句没有百搭cards",cards); // console.error("sscc提取成ju没有百搭huCards",huCards); // } for (let i = 0; i < cards.length - 2; ++i) { let card = cards[i]; if (card <= 0) continue; if (card == cards[i + 1] && card == cards[i + 2]) { huCards.push({ style: STYLE.KE, cards: [card, card, card] }); cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0; i += 2; continue; } if (card > 40 || this.getValue(card) > 7) continue; let second = -1, third = -1; for (let j = i + 1; j < cards.length; ++j) { if (cards[j] == card + 1) second = j; if (cards[j] == card + 2) third = j; if (cards[j] > card + 2) break; if (second != -1 && third != -1) break; } if (second != -1 && third != -1) { huCards.push({ style: STYLE.SUN, cards: [card, cards[second], cards[third]] }); cards[i] = 0; cards[second] = 0; cards[third] = 0; } } }; proto._dumpFixedc = function (cards,huCards,baidaCount) { let spkzgs = 4 - huCards.length;//手牌可组个数 let spkzzh = [];//手牌可组组合(1为刻2为顺) if(spkzgs == 1) spkzzh = [[1],[2]]; else if(spkzgs == 2) spkzzh = [[1,1],[1,2],[2,2],[2,1]]; else if(spkzgs == 3) spkzzh = [[1,1,1],[1,2,1],[1,1,2],[1,2,2],[2,2,2],[2,1,2],[2,2,1],[2,1,1]]; else if(spkzgs == 4){ spkzzh = [[1,1,1,1],[1,2,1,1],[1,1,2,1],[1,1,1,2], [1,2,2,1],[1,1,2,2],[1,2,1,2],[1,2,2,2], [2,2,2,2],[2,1,2,2],[2,2,1,2],[2,2,2,1], [2,1,1,2],[2,2,1,1],[2,1,2,1],[2,1,1,1] ] } //找到目标牌 var getMBCard = (cscards) => { for (let i = 0; i < cscards.length; ++i) { let card = cscards[i]; if (card <= 0) continue; else return card; } return -100; }; // let mbpailist = [12,15,15,15,16,17,18,25,26,27] // let islog = true; // if(mbpailist.length == cards.length){ // for (let i = 0; i < cards.length; ++i) { // if(mbpailist[i] != cards[i]) islog = false; // } // } // else{ // islog = false; // } // let mbpailist2 = [15,15,16,17,18,25,26,27,28,28,28] // if(islog) console.warn("_dumpFixedc 提取成句 baidaCount "+baidaCount+" cards "+cards+ " indexof "+mbpailist2.indexOf(15)); // console.warn("所有的判断组合 长度 "+spkzzh.length+" spkzzh "+JSON.stringify(spkzzh) ) let dqdpd = [0,0]//当前的判断 for (let x = 0; x < spkzzh.length; ++x) { let copyCards = this.deepCloneTL(cards) let bdCount = baidaCount; let huCards22 = []; // console.warn("当前的判断组合 "+dqdpd+" spkzzh[x] "+spkzzh[x]+" x "+x); // if(islog && x == 5) console.warn("当前的判断组合 "+dqdpd+" spkzzh[x] "+spkzzh[x]+" x "+x); for (let y = 0; y < spkzzh[x].length; ++y) { let ckORcs = spkzzh[x][y]//成刻或成顺(1为刻2为顺) // if(islog && x == 5) console.warn("当前的判断 "+dqdpd+" ckORcs "+ckORcs); if(ckORcs == 1){ let mbCard = getMBCard(copyCards);//目标card(mbCard这次应该成刻) if(mbCard > 0){ let index1 = copyCards.indexOf(mbCard); if(index1 != -1) copyCards[index1] = 0; else console.error("这里不正常,都没有目标牌"); let cj = [mbCard];//成句 let index2 = copyCards.indexOf(mbCard); if(index2 != -1){ cj[cj.length] = mbCard; copyCards[index2] = 0; } else { if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } let index3 = copyCards.indexOf(mbCard); if(index3 != -1){ cj[cj.length] = mbCard; copyCards[index3] = 0; } else { if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } if(cj.length == 3){ huCards22.push({ style: STYLE.KE, cards: cj }); } else{ //mbCard不能成刻,说明spkzzh[x]这种组合是不行的,剩下的就不用判断了 // console.warn("mbCard不能成刻,说明spkzzh[x]这种组合是不行的,剩下的就不用判断了"); break; } } else{ //手牌全部都判断过了 if(bdCount >= 3){ huCards22.push({ style: STYLE.KE, cards: [51, 51, 51] }); bdCount -= 3; } //因为手里最多8张百搭,最多可以有6张百搭做成2个百搭刻,所以需要两次if if(bdCount >= 3){ huCards22.push({ style: STYLE.KE, cards: [51, 51, 51] }); bdCount -= 3; } break; } } else if(ckORcs == 2){ let mbCard = getMBCard(copyCards);//目标card(mbCard这次应该成刻) // if(islog && x == 5) console.warn("mbCard "+mbCard+" copyCards "+copyCards); if (mbCard < 40){ if(mbCard > 0){ let index1 = copyCards.indexOf(mbCard); if(index1 != -1) copyCards[index1] = 0; else console.error("这里不正常,都没有目标牌"); let cj = [mbCard];//成句 if(this.getValue(mbCard) <= 7){ let index2 = copyCards.indexOf(mbCard+1); if(index2 != -1){ cj[cj.length] = copyCards[index2]; copyCards[index2] = 0; } else { if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } let index3 = copyCards.indexOf(mbCard+2); if(index3 != -1){ cj[cj.length] = copyCards[index3]; copyCards[index3] = 0; } else { if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } } else if(this.getValue(mbCard) == 8){ let index2 = copyCards.indexOf(mbCard+1); if(index2 != -1){ cj[cj.length] = copyCards[index2]; copyCards[index2] = 0; } else { if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } if(bdCount > 0){ cj[cj.length] = 51; bdCount -= 1; } } else if(this.getValue(mbCard) == 9){ if(bdCount > 1){ cj[cj.length] = 51; cj[cj.length] = 51; bdCount -= 2; } } if(cj.length == 3){ huCards22.push({ style: STYLE.SUN, cards: cj }); } else{ //mbCard不能成顺,说明spkzzh[x]这种组合是不行的,剩下的就不用判断了 break; } } else{ //手牌全部都判断过了 if(bdCount >= 3){ huCards22.push({ style: STYLE.SUN, cards: [51, 51, 51] }); bdCount -= 3; } //因为手里最多8张百搭,最多可以有6张百搭做成2个百搭刻,所以需要两次if if(bdCount >= 3){ huCards22.push({ style: STYLE.SUN, cards: [51, 51, 51] }); bdCount -= 3; } break; } } } // if(y < spkzzh[x].length-1) dqdpd=[x,y+1]; // else dqdpd=[x+1,0]; } // if(islog && x == 5) console.warn("提取成句 组合 "+" spkzzh[x] "+spkzzh[x]+" huCards22 "+JSON.stringify(huCards22) ); if(huCards22.length + huCards.length == 4){ //已经可以胡牌了,其他的组合就不需要判断了 for (var i = 0; i < huCards22.length; i++) { huCards.push(huCards22[i]); } break; } } }; //////TL++,判断一手张牌是否为百搭牌 proto.judgeACardISBD = function (card) { return card == this.baiDaCard; } // 胡牌分析 chairID(TL++这个参数) 手牌 加上这张判断能不能胡 手上的吃碰杠牌 是否自己摸上来的 proto.huAnalyze = function (chairID,handCards, card, huCards, isTouch) { // console.error("sscc777胡牌分析card",card); // console.error("sscc777胡牌分析handCards",handCards); // console.error("sscc777胡牌分析huCards",huCards); // console.error("sscc777胡牌分析isTouch",isTouch); this.addThisIsHu = card//////TL++,胡牌判断时加上这张能不能胡 this.isSeleCatcedCard = isTouch//////判断能否胡牌的那张牌是自己抓的还是别人打出来的 this.currChairIDTL = chairID/////当前判断胡的chairID,用于得到当前玩家的花牌情况 this.dangAfterBDListTL = [];/////7月18日+的 // console.warn("胡牌分析 isGuoHuList ",this.isGuoHuList," chairID ",chairID," isTouch ",isTouch); // let baiDaCount22 = 0 // let bdIndexlist = [] if (!isTouch){ handCards = handCards.concat(card);/////不是自己抓的就把这张牌拼接进手牌中 } handCards = this.sort(handCards); let huCards2 = this.deepCloneTL(huCards) // console.warn("判断13不搭手上百搭牌个数出错了?????",baiDaCount22,this.sbyBDList,bdIndexlist) var huRes = { card: card, jiang: 0, huCards: [] }; // 重设将牌 var resetHuRes = (jiang) => { huRes.jiang = jiang; huRes.huCards = []; for (let huCard of huCards) huRes.huCards.push(huCard); }; // 手牌不全 var length = handCards.length; if (length % 3 != 2) return; let result = null if(this.isSevenDouble(handCards)){ // console.warn("是个7对子了"); resetHuRes(-1); result = huRes; } if(this.isJiangJiangHu(handCards,huCards2)){ // console.warn("是个将将胡了"); resetHuRes(-1); result = huRes; } // let hucardTL = huCards//////TL++,保存碰杠牌的初始值,因为这个参数会在下面的代码中被修改掉 // console.warn("下面是计算普通胡法 "+handCards); // 确定将牌 for (let i = 0; i < length - 1; ++i) { if (!this.isJang(handCards[i], handCards[i + 1])) continue; resetHuRes(handCards[i]);////设置将牌 let bcjp = handCards[i]; let cards = handCards.slice(0, i);////手牌数组的前i个元素 cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌 this._dumpFixed(cards, huRes.huCards); i += 1;/////TL++,为了减少运算 if(huRes.huCards.length >= 4){ if(this.isNeedEWBZJ(handCards,huCards2,huRes,isTouch)){ let jiangValue = this.getValue(bcjp); if(jiangValue == 2 || jiangValue == 5 || jiangValue == 8){ result = this.deepCloneTL(huRes); // console.error("xxxxxxx需要258做将 bcjp "+bcjp+" "+handCards) } break } else{ // console.error("不需要258做将 bcjp "+bcjp+" "+handCards) result = this.deepCloneTL(huRes); // console.error("不需要258做将 result "+JSON.stringify(result)) } } } if(result){ let copyCards = this.deepCloneTL(handCards); // console.error("胡牌分析 判断可胡 大胡牌型111 ",chairID,copyCards); // console.error("胡牌分析 判断可胡 大胡牌型huCards2 ",JSON.stringify(huCards2)); // console.error("胡牌分析 判断可胡 大胡牌型huRes ",JSON.stringify(huRes)); // console.error("胡牌分析 判断可胡 大胡牌型result ",JSON.stringify(result)); this.getCardTypeTL(chairID,copyCards,huCards2,result,isTouch); // console.error("胡牌分析 可胡 大胡牌型 "+chairID+" "+this.everyDAHType[chairID]); if(!isTouch){ // console.warn("不是此人摸牌 ",chairID,isTouch); let pxgs = 0; for (let x = 0; x < this.everyDAHType[chairID].length; ++x) { if(this.everyDAHType[chairID][x] == 1) pxgs++; } // console.error("胡牌分析 可胡 是否过胡 "+this.isGuoHuList[chairID][0]+" 过胡牌型个数 "+this.isGuoHuList[chairID][1]+" 当前牌型个数 "+pxgs); if(this.isGuoHuList[chairID][0] && this.isGuoHuList[chairID][1] >= pxgs){ // console.warn("此人点过胡了 ",chairID," isTouch ",(!isTouch)); return false; } } } if(!isTouch && this.kexuanList[3] == 1){ // console.error("胡牌分析 不是自己摸牌 勾选了小胡只能自摸 "+chairID+" "+this.everyDAHType[chairID]); if(this.everyDAHType[chairID].indexOf(1) == -1){ // console.error("胡牌分析 不是自己摸牌 勾选了小胡只能自摸 没有大胡牌型 "+chairID+" "+this.everyDAHType[chairID]); return false; } } return result; }; // // TL++胡牌提示 chairID(TL++这个参数) 手牌 手上的吃碰杠牌 这个是胡牌提示里不统计台数 proto.hutip = function (chairID,_handCards, _huCards,_allhuCards,outCards) { // return { // renyi:0,//////是否可胡任意牌,0表示不满足1表示满足 // kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据 // };////服务端运算量太大放到前端去计算了 this.yscs = 0 // console.warn("hutip777胡牌提示handCards ",chairID,_handCards,_huCards,this.yscs); // console.error("sscc777胡牌提示huCards",_huCards); let hutipRes = []; let handCards1 = _.clone(_handCards); // if(chairID == 1) console.warn("sscc777胡牌提示handCards1 ",chairID,_handCards); let huCards = _.clone(_huCards); let allhuCards = _.clone(_allhuCards);////用统计胡牌提示的剩余牌 // let baiDaCount22 = this.getBDCount(_handCards); let dangPaiList = this.getYGLDPList(handCards1); // console.warn("hutip777胡牌提示 dangPaiList ",dangPaiList.length,dangPaiList); // if(baiDaCount22 < this.hzCount && this.hzCount > 0 && _handCards.indexOf(this.baiDaCard) == -1 && this.baiDaCard < 60){ // dangPaiList[dangPaiList.length] = this.baiDaCard; // } // if(chairID == 1) console.warn("hutip777胡牌提示 dangPaiList ",dangPaiList.length,dangPaiList); let kdcdp = 0;////可打出的牌 就是打出这个牌之后可以胡 let dczhkhdp = [];////打出kdcdp之后可以胡的牌 let yjpdgdsp = 0;////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了 // let yjpdgdzh = [];////已经判断过的组合 把28换成26 和 把26换成28 的结果是一样的所以可以剔除以减少运算 if(Array.isArray(handCards1)){ for (var i = 0; i < handCards1.length; i++) { if(this.judgeACardISBD(handCards1[i])) continue; kdcdp = handCards1[i];////可打出的牌 dczhkhdp = []; if(handCards1[i] == yjpdgdsp) continue;////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了 yjpdgdsp = handCards1[i];////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了 var huResTL = []; for (let huCard of huCards) huResTL.push(huCard); let copyhandCards = this.deepCloneTL(_handCards) // for (let x = 0; x < copyhandCards.length; ++x) { // if(this.judgeACardISBD(copyhandCards[x])){ // copyhandCards[x] = 0;////剔除手里的百搭去判断抛搭 // } // } copyhandCards[i] = 0;///剔除手里的百搭和打出那张之后剩下的手牌去判断抛搭 let copyhandCardsqbd = _.compact(_.clone(copyhandCards)); copyhandCardsqbd = this.sort(copyhandCardsqbd); // let ispd = this.hutipJudgePAODA(baiDaCount22,copyhandCardsqbd,dangPaiList,huResTL.length,kdcdp);////打出kdcdp之后是否抛搭 //上面是旧的算法,下面是新的算法 // let ispd = false; // if(copyhandCardsqbd.length == 0){ // ispd = true;//手上全是百搭肯定抛搭了 // } // else{ // if(baiDaCount22 > 0){ // ispd = this.hutipJudgePAODA2(baiDaCount22-1,copyhandCardsqbd,huResTL,kdcdp);////打出kdcdp之后是否抛搭 // } // } // // console.warn("打出kdcdp之后是否抛搭 ",kdcdp,ispd,this.yscs); // if(ispd){ // ////打出kdcdp之后可以抛搭了 // let data = { // "canTing": kdcdp,////表示打出这张牌之后可以听牌 // "youjin": 1,////打出这张牌之后是不是游金(抛搭)这个在象山麻将里面没有用 // "tpxq": dczhkhdp // } // hutipRes[hutipRes.length] = data; // } // else{ ////打出kdcdp之后不能抛搭 for (var k = 0; k < dangPaiList.length; k++) { this.yscs++; let handCards = _.clone(handCards1); // console.error("222sscc777胡牌提示huCards",i,handCards[i] , dangPaiList[k],handCards); handCards[i] = dangPaiList[k]; handCards = this.sort(handCards); // 手牌不全 var length = handCards.length; if (length % 3 != 2) return; // console.warn("pandau 0ceccewcde -------开始调用 hutip33"); let huRes22 = this.hutip33(chairID,handCards, dangPaiList[k], huCards,false); if (huRes22) { // console.warn("胡牌提示 打出 "+kdcdp+" 如果摸到 "+dangPaiList[k]+" 可以胡"); ////打出kdcdp如果摸到dangPaiList[k]可以胡 let syzs = this.getACardSYZS(dangPaiList[k],_handCards,allhuCards,outCards); // console.warn("111????????????????????????????????",dangPaiList[k],syzs); dczhkhdp[dczhkhdp.length] = [dangPaiList[k],-1,syzs];////[可胡的牌,剩余张数] } } // console.warn("222????????????????????????????????",dczhkhdp.length); if(dczhkhdp.length > 0){ ////至此表示打出handCards[i]之后可以听牌 let data = { "canTing": kdcdp,////表示打出这张牌之后可以听牌 "youjin": 0,////打出这张牌之后是不是游金(抛搭)这个在象山麻将里面没有用 "tpxq": dczhkhdp } hutipRes[hutipRes.length] = data; } } } // } // console.warn("333????????????????????????????????",hutipRes); // console.warn("222sscc777胡牌提示handCards ",chairID,_handCards,_huCards,this.yscs); let kehuData3 = { renyi:0,//////是否可胡任意牌,0表示不满足1表示满足 kehuData:hutipRes/////对象数组,分别表示打哪张可胡哪几张数据 }; return kehuData3; // return hutipRes; }; ////TL++得到一张牌的剩余张数 用于胡牌提示提示该张的剩余张数 proto.getACardSYZS = function (card,_handCards,allhuCards,outCards) { // console.warn("000得到一张牌的剩余张数 手牌张数",card,_handCards); // console.warn("000得到一张牌的剩余张数 手牌张数",JSON.stringify(allhuCards)); // console.warn("000得到一张牌的剩余张数 手牌张数",JSON.stringify(outCards)); ////下面这段是适合胡牌提示里用的剩余牌数统计 let yjcxdzs = 0;////该牌已经出现的张数 for (var i = 0; i < _handCards.length; i++) { if(card == _handCards[i]) yjcxdzs++;////该牌已经出现在自己手牌里的张数 } // console.warn("111得到一张牌的剩余张数 手牌张数",yjcxdzs,_handCards); for (var i = 0; i < allhuCards.length; i++) { if(allhuCards[i].length == 0) continue;////该玩家没有碰杠牌 // console.warn("222得到一张牌的剩余张数 碰杠杠牌",card,yjcxdzs,i,JSON.stringify(_.clone(allhuCards[i]))); for (var k = 0; k < allhuCards[i].length; k++) { let pgp = allhuCards[i][k].cards; if(!pgp) continue; if(allhuCards[i][k].style >= 5 && allhuCards[i][k].style <= 10 ){ if(allhuCards[i][k].cards[0] == card){ yjcxdzs+=4;//明杠暗杠自摸杠明补暗补自摸补 } } else{ // console.warn("得到一张牌的剩余张数 "+pgp+" card "+card); for (var j = 0; j < pgp.length; j++) { if(card == pgp[j]) yjcxdzs++;////该牌已经出现在自己手牌里的张数 } } } } for (var i = 0; i < outCards.length; i++) { if(outCards[i].length == 0) continue;////该玩家没有碰杠牌 // console.warn("2得到一张牌的剩余张数 打出去的牌",card,yjcxdzs,i,JSON.stringify(_.clone(outCards[i]))); for (var k = 0; k < outCards[i].length; k++) { if(card == outCards[i][k]) yjcxdzs++;////该牌已经出现在所有打出去牌里的张数; } } let zs = 4 if(card == 51) zs = this.hzCount; // if(this.judgeACardISBD(card)) zs = 3; let syzs = zs - yjcxdzs;////剩余张数 = 总张数 - 已经出现的张数 // console.warn("333得到一张牌的剩余张数",card,syzs); return syzs; }; // //////TL++,胡牌提示判断抛搭 // proto.hutipJudgePAODA2 = function (_baidacount,_hd,_huCards,_addThisIsHu) { // // console.warn("胡牌提示判断抛搭 _baidacount "+_baidacount+" _hd.length "+_hd.length +" _hd "+_hd); // let cards2 = this.deepCloneTL(_hd); // let huRes3 = { card: 0, jiang: 0, huCards: [] }; // huRes3.huCards = []; // for (let huCard of _huCards) huRes3.huCards.push(huCard); // this._dumpFixedc(cards2, huRes3.huCards,_baidacount); // // console.warn("胡牌提示 判断判断抛搭 length "+huRes3.huCards.length+" huRes3.huCards "+ JSON.stringify(huRes3.huCards)); // if (huRes3.huCards.length >= 4){ // // console.warn("胡牌提示 判断判断抛搭 可以抛搭222 length "+huRes3.huCards.length+" huRes3.huCards "+ JSON.stringify(huRes3.huCards)); // return true; // } // // console.warn("不能抛搭"); // return false; // } // 胡牌分析(胡牌提示里调用) chairID(TL++这个参数) 手牌 加上这张判断能不能胡 手上的吃碰杠牌 是否自己摸上来的 proto.hutip33 = function (chairID,handCards, card, huCards, isTouch) { // console.error("sscc777胡牌分析card",card); // console.error("sscc777胡牌提示分析handCards",handCards); // console.error("sscc777胡牌分析huCards",huCards); // console.error("sscc777胡牌分析isTouch",isTouch); // let tempres = {}///本函数的返回值 // this.addThisIsHu = card//////TL++,胡牌判断时加上这张能不能胡 // this.isSeleCatcedCard = isTouch//////判断能否胡牌的那张牌是自己抓的还是别人打出来的 // this.currChairIDTL = chairID/////当前判断胡的chairID,用于得到当前玩家的花牌情况 // this.dangAfterBDListTL = [];/////7月18日+的 // let baiDaCount22 = 0 // let bdIndexlist = [] // handCards = this.sort(handCards); // baiDaCount22 = this.getBDCount(handCards) // this.sbyBDList = this.getBDListZZ(handCards) // bdIndexlist = this.getBDIndexList(handCards) // console.warn("判断13不搭手上百搭牌个数出错了?????",baiDaCount22,this.sbyBDList,bdIndexlist) // 手牌不全 // var length = handCards.length; // // console.warn("胡牌提示 length "+length+" baiDaCount22 "+baiDaCount22); // if (length % 3 != 2) return; let huCards2 = this.deepCloneTL(huCards) var huRes = { card: card, jiang: 0, huCards: [] }; // 重设将牌 var resetHuRes = (jiang) => { huRes.jiang = jiang; huRes.huCards = []; for (let huCard of huCards) huRes.huCards.push(huCard); }; if(this.isSevenDouble(handCards)){ // console.warn("胡牌提示 是个7对子了"); return true; } if(this.isJiangJiangHu(handCards,huCards2)){ // console.warn("胡牌提示 是个将将胡了"); return true; } // let hucardTL = huCards//////TL++,保存碰杠牌的初始值,因为这个参数会在下面的代码中被修改掉 // 确定将牌 for (let i = 0; i < handCards.length - 1; ++i) { if (!this.isJang(handCards[i], handCards[i + 1])) continue; resetHuRes(handCards[i]);////设置将牌 let bcjp = handCards[i]; ///////本次的将牌 7月18日+的 let cards = handCards.slice(0, i);////手牌数组的前i个元素 cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌 this._dumpFixed(cards, huRes.huCards); i += 1;/////TL++,为了减少运算 // let tempres22 = this.outHures(huRes,handCards,hucardTL); if(huRes.huCards.length >= 4){ if(this.isNeedEWBZJ(handCards,huCards2,huRes,true)){ let jiangValue = this.getValue(bcjp); if(jiangValue == 2 || jiangValue == 5 || jiangValue == 8){ return true; } } else{ return true; } } } return false; }; // TL++,得到和手牌有关联的牌的数组,用于判断是否听牌 cards: 13张手牌 proto.getYGLDPList = function (_cards) { let cards = this.deepCloneTL(_cards) cards = this.sort(cards); let cannotList = []; ////TL++,整个for循环按照手牌情况确定百搭牌当的范围 let makeList = this.deepCloneTL(cards) for (let i = 0; i < cards.length; ++i) { let cardTL = cards[i]; let type = this.getType(cardTL); let vale = this.getValue(cardTL); if(cardTL == cards[i+1] && cardTL == cards[i+2] && cardTL == cards[i+3]){ i += 3; cannotList[cannotList.length] = cardTL; } if(type < 4){ if(vale == 1){ let makeValue = cardTL + 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; } else if(vale == 9){ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; } else{ let makeValue = cardTL - 1; if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue; let makeValue2 = cardTL + 1; if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2; } } } // console.warn("22数组去重",xx,xx22);////[ 1, 6, 2, 3, 4, 1, 2 ] [ 1, 2, 3, 4 ] //return _.uniq(makeList); makeList = _.uniq(makeList); this.remove(makeList,cannotList); return makeList; } //判断是否可以杠,14张手牌去掉可以暗杠的4张牌(或者13张牌去掉可以明杠的3张牌)之后可以听牌则可以杠否则不能杠 proto.isCanGang = function (cards,_huCards,gangtype,gangcard) { // console.error("判断是否可以杠 cards "+cards,_huCards,gangtype,gangcard); let huCards = []; for (let huCard of _huCards) huCards.push(huCard); let handCards = this.deepCloneTL(cards); handCards = this.sort(handCards); let needDelList = []; //1-普通杠, 2-暗杠, 3-自摸明杠 if(gangtype == 1){ needDelList[needDelList.length] = [gangcard,gangcard,gangcard] huCards.push({ style: STYLE.GANG, cards: [gangcard,gangcard,gangcard] }); } else if(gangtype == 2){ if(gangcard != 0){ needDelList[needDelList.length] = [gangcard,gangcard,gangcard,gangcard]; huCards.push({ style: STYLE.ANGANG, cards: [gangcard,gangcard,gangcard] }); } else{ for (let i = 0; i < handCards.length - 3; ++i) { let card = handCards[i]; // 判定是否刻子 if (card == handCards[i + 1] && card == handCards[i + 2] && card == handCards[i + 3]) { needDelList[needDelList.length] = [card,card,card,card]; huCards.push({ style: STYLE.ANGANG, cards: [card,card,card] }); i+=3 } } } } else if(gangtype == 3){ needDelList[needDelList.length] = [gangcard]; } // console.error("判断是否可以杠 needDelList "+needDelList.length,needDelList); for (let i = 0; i < needDelList.length; ++i) { let handCards2 = this.deepCloneTL(handCards); this.remove(handCards2,needDelList[i]); // console.error("判断是否可以杠 handCards2 "+handCards2+" needDelList[i] "+needDelList[i]); if(this.checkTing(handCards2,huCards)){ // console.error("判断是否可以杠 可以杠"); return true; } } return false; } //检查是否可以听牌 proto.checkTing = function (_cards,huCards) { // console.error("检查是否可以听牌 length "+_cards.length+" cards "+_cards); // console.error("检查是否可以听牌111 length "+huCards.length+" huCards "+JSON.stringify(huCards) ); if (_cards.length % 3 != 1) return; let handCards = this.deepCloneTL(_cards) let dangPaiList = this.getYGLDPList(handCards); let huCards2 = this.deepCloneTL(huCards) var huRes = { card: 0, jiang: 0, huCards: [] }; // 重设将牌 var resetHuRes = (jiang) => { huRes.jiang = jiang; huRes.huCards = []; for (let huCard of huCards) huRes.huCards.push(huCard); }; for (let n = 0; n < dangPaiList.length; ++n) { let cards22 = this.deepCloneTL(handCards)/////百搭牌当完之后的手牌数组 cards22[cards22.length] = dangPaiList[n]; cards22 = this.sort(cards22); if(this.isJiangJiangHu(handCards,huCards2)){ // console.error("是个将将胡了"); return true; } if(this.isSevenDouble(cards22)){ return true; } // 确定将牌 for (let i = 0; i < cards22.length - 1; ++i) { if (!this.isJang(cards22[i], cards22[i + 1])) continue; resetHuRes(cards22[i]);////设置将牌 let bcjp = cards22[i]; ///////本次的将牌 7月18日+的 // this.judgePAODA(1,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里 let cards = cards22.slice(0, i);////手牌数组的前i个元素 cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌 this._dumpFixed(cards, huRes.huCards); if(huRes.huCards.length >= 4){ // if(handCards.length == 1) return true; if(this.isNeedEWBZJ(cards22,huCards2,huRes,true)){ let jiangValue = this.getValue(bcjp); // return (jiangValue == 2 || jiangValue == 5 || jiangValue == 8); if((jiangValue == 2 || jiangValue == 5 || jiangValue == 8)){ // console.error("检查是否可以听牌 可以听牌111"); return true; } } else{ // console.error("检查是否可以听牌 可以听牌222"); return true; } } i += 1;/////TL++,为了减少运算 } } // console.warn("检查是否可以听牌 不能听牌"); return false; } //是否需要二五八做将 proto.isNeedEWBZJ = function (handCards,huCards,hures,isTouch) { // console.error("是否需要二五八做将 isTouch "+isTouch +" handCards " +handCards+" huCards "+JSON.stringify(huCards)+" hures "+JSON.stringify(hures)); let shoupai = handCards/////手牌 let PGPai = huCards/////手上的碰杠牌 let chengju = hures/////整理好之后成句的牌(包括碰杠牌) for (var i = 5; i < this.dahuTypeTL.length; i++) { if( i == 5 && this.isQQR(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将1"); return false; } // else if( i == 6 && isTouch && this.isMQ(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将2"); // return false; // } else if( i == 7 && this.isQYS(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将3"); return false; } else if( i == 8 && this.isPengPengHu(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将4"); return false; } // else if( i == 9 && this.isGangKai(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将5"); // return false; // } // else if( i == 10 && this.isQiangGang(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将6"); // return false; // } // else if( i == 11 && this.isHDLY(shoupai,PGPai,chengju)){ // console.warn("不需要2,5,8做将7"); // return false; // } } // console.error("是否需要二五八做将 需要 "); return true; } // 是否可以出牌,别人有权限的时候不能出牌需要等待 proto.getIsCanOut = function (masks) { let isCanOut = true; for (let x = 0; x < masks.length; ++x) { if(masks[x] > 0){ isCanOut = false; break; } } return isCanOut; }; //删除起手胡牌型的操作权限 proto.getNewMask = function (oldMask) { let list = [1,2,4,8,16,32]; let isCanOperateList = []; for (let i = 0; i < list.length; ++i) { // if(oldMask < list[i]) break; if(oldMask & list[i]) isCanOperateList[isCanOperateList.length] = 1; else isCanOperateList[isCanOperateList.length] = 0; } let newMask = 0; for (let i = 0; i < isCanOperateList.length; ++i) { if(isCanOperateList[i] == 1){ newMask |= list[i] } } return newMask; } ////得到list1里面是否包含list2 proto.getISBH = function (_list1,list2) { //因为运算过程中会改变_list1的值所以需要备份数据 let list1 = this.deepCloneTL(_list1); for (let i = 0; i < list2.length; ++i) { let pos = list1.indexOf(list2[i]); if (pos == -1){ return false; } list1.splice(pos, 1); } return true } ////得到list1[[],[],[]]里面是否包含list2 proto.getISBH2 = function (_list1,list2) { // console.warn("得到list1[[],[],[]]里面是否包含list2 "+JSON.stringify(_list1)+" list2 "+list2); for (let i = 0; i < _list1.length; ++i) { if(_list1[i].length == list2.length){ for (let x = 0; x < _list1[i].length; ++x) { if(_list1[i][x] == list2[x]){ // console.warn("包含了 第i个 "+i); return true; } } } } // console.warn("不包含"); return false } //// 得到是否是起手 proto.getIsQS = function () { let isqs = this.castCount == (this.playerAllCount*CARDS_COUNT+1);//是否起手 if(isqs){ if(this.chuPaiCountTL == 0) return true; } return false; } // 起手胡牌分析 chairID(TL++这个参数) 手牌 加上这张判断能不能胡 手上的吃碰杠牌 是否自己摸上来的 proto.qshuAnalyze = function (chairID,handCards) { this.everyQSHType[chairID] = []; this.canSelects[chairID] = []; let isqs = this.getIsQS(); let shoupai = this.deepCloneTL(handCards); // this.remove(shoupai,this.everyQSHCZGList[chairID]); shoupai = this.sort(shoupai); for (let i = 0; i < this.qshuTypeTL.length; ++i) { this.everyQSHType[chairID][i] = 0; if( i == 0 && isqs && this.isSiXi(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } else if( i == 1 && isqs && this.isBanBanHu(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } else if( i == 2 && isqs && this.isQueYiSe(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } else if( i == 3 && isqs && this.isLiuLiuShun(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } else if( i == 4 && (!isqs) && this.isSiXi(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } else if( i == 5 && (!isqs) && this.isLiuLiuShun(chairID,shoupai,isqs)){ this.everyQSHType[chairID][i] = 1; } // else if( i == 4 && this.isJieJieGao(shoupai)){ // this.everyQSHType[chairID][i] = 1; // } // else if( i == 5 && this.everyQSHType[chairID][2] == 0 && this.isSanTong(shoupai)){ // //是缺一色的情况下不可能是三同 // this.everyQSHType[chairID][i] = 1; // } // else if( i == 6 && this.everyQSHType[chairID][1] == 0 && this.isDanJiang(shoupai)){ // //是板板胡的话不可能是单将一枝花 // this.everyQSHType[chairID][i] = 1; // } // else if( i == 7 && this.everyQSHType[chairID][1] == 0 && this.everyQSHType[chairID][6] == 0 && this.isDanWu(shoupai)){ // //是板板胡的话不可能是单五一枝花 // //只有一张五的情况下都满足单将一枝花和单五一枝花,这种情况算单将一枝花单五一枝花不成立 // this.everyQSHType[chairID][i] = 1; // } } } //起手的六六顺消耗过的牌起手四喜不能再次使用,中途的六六顺消耗过的牌中途四喜不能再次使用, //起手的六六顺消耗过的牌中途四喜可以再次使用,(四喜和六六顺同理) // 是否四喜 proto.isSiXi = function (chairID,handCards,isqs) { // console.error("是否四喜===111 chairID "+chairID+" everyQSHCZGList "+JSON.stringify(this.everyQSHCZGList[chairID])); // console.error("是否四喜===222 chairID "+chairID+" everyQSHCZGList2 "+JSON.stringify(this.everyQSHCZGList2[chairID])); // console.error("是否四喜===333 chairID "+chairID+" handCards "+JSON.stringify(handCards)); if(!isqs && this.kexuanList[0] != 1) return false;//没有勾选中途大四喜 let canSelects = []; var dcount = 0; for (let i = 0; i < handCards.length-3; ++i) { let card = handCards[i]; if (card == handCards[i+1] && card == handCards[i+2] && card == handCards[i+3]) { if(!this.getISBH(this.everyQSHCZGList[chairID],[card,card,card])){ dcount += 1; i+=3; canSelects.push([card,card,card,card]) } else{ // console.error("是否四喜===222 chairID isqs " + isqs) //添加这个else是为了满足下面这个规则,如果消耗过的牌不能再次使用就不要这个else了 //起手的六六顺消耗过的牌起手四喜不能再次使用,中途的六六顺消耗过的牌中途四喜不能再次使用, //起手的六六顺消耗过的牌中途四喜可以再次使用,(四喜和六六顺同理) if(!isqs && !this.getISBH2(this.everyQSHCZGList2[chairID],[card,card,card,card])){ dcount += 1; i+=3; canSelects.push([card,card,card,card]) } } } } if(dcount >= 1){ let type = 0; if(!isqs) type = 4; let obj = { type:type, cards:canSelects } this.canSelects[chairID].push(obj) return true; } return false; }; // 是否板板胡 proto.isBanBanHu = function (chairID,handCards,isqs) { if(this.everyXiaoHuList[chairID].indexOf(1) != -1) return false; for (let i = 0; i < handCards.length; ++i) { let card = this.getValue(handCards[i]); if (card == 2 || card == 5 || card == 8) { return false; } } let obj = { type:1, cards:[] } this.canSelects[chairID].push(obj); return true; }; // 是否缺一色 proto.isQueYiSe = function (chairID,handCards,isqs) { // console.warn("是否缺一色 chairID "+chairID+" handCards "+handCards + " isqs "+isqs); let huaSeCount = [0,0,0,0]; for (let i = 0; i < handCards.length; ++i) { let card = handCards[i]; if(this.getType(card) == 1 ) huaSeCount[0] = 1; if(this.getType(card) == 2 ) huaSeCount[1] = 1; if(this.getType(card) == 3 ) huaSeCount[2] = 1; } let huase = 0; for (let n = 0; n < huaSeCount.length; ++n) { if(huaSeCount[n] == 1) huase += 1; } if(huase <= 2){ let ismz = false; let yjhgdqyscs = 0;//已经胡过的缺一色次数 for (let i = 0; i < this.everyXiaoHuList[chairID].length; ++i) { if(this.everyXiaoHuList[chairID][i] == 2) yjhgdqyscs++ } if(huase == 2){ if(yjhgdqyscs == 0) ismz = true; } else if(huase == 1){ //手上只有一种花色可以胡缺一色两次 if(yjhgdqyscs < 2) ismz = true; } // console.warn("缺一色==== "+ismz+" yjhgdqyscs "+yjhgdqyscs + " huase "+huase); if(ismz){ let obj = { type:2, cards:[] } this.canSelects[chairID].push(obj); return true; } } return false; }; // 是否六六顺 proto.isLiuLiuShun = function (chairID,handCards,isqs) { if(!isqs && this.kexuanList[1] != 1) return false;//没有勾选中途大四喜 var keList = []; for (let i = 0; i < handCards.length-2; ++i) { let card = handCards[i]; if (card == handCards[i+1] && card == handCards[i+2]) { keList.push([card,card,card]) i+=2; } } if(keList.length >= 2){ let cards = []; for (let i = 0; i < keList.length; ++i) { for (let j = i+1; j < keList.length; ++j) { if(!this.getISBH(this.everyQSHCZGList[chairID],keList[i]) && !this.getISBH(this.everyQSHCZGList[chairID],keList[j])){ let cc = keList[i].concat(keList[j]); cards.push(cc); } } } if(cards.length > 0){ let type = 3; if(!isqs) type = 5; let obj = { type:type, cards:cards } this.canSelects[chairID].push(obj); return true } return false; } return false; }; // 是否节节高 // proto.isJieJieGao = function (handCards) { // var duiziList = []; // for (let i = 0; i < handCards.length-1; ++i) { // let card = handCards[i]; // if (card == handCards[i+1]) { // if(duiziList.indexOf(card) == -1){ // duiziList[duiziList.length] = card; // } // i+=1; // } // } // for (let i = 0; i < duiziList.length; ++i) { // let value = this.getValue(duiziList[i]) // if(value < 8 && duiziList[i]+1 == duiziList[i+ 1] && duiziList[i]+2 == duiziList[i+ 2]){ // return true // } // } // return false; // }; // // 是否三同 // proto.isSanTong = function (handCards) { // var duiziList = []; // for (let i = 0; i < handCards.length-1; ++i) { // let card = handCards[i]; // if (card == handCards[i+1]) { // if(duiziList.indexOf(card) == -1){ // duiziList[duiziList.length] = card; // } // i+=1; // } // } // for (let i = 0; i < duiziList.length; ++i) { // let card = handCards[i]; // let type = this.getType(duiziList[i]) // if(type < 2){ // if(duiziList.indexOf(card + 10) != -1 && duiziList.indexOf(card + 20) != -1){ // return true; // } // } // else { // return false; // } // } // return false; // }; // // 是否单将一枝花 // proto.isDanJiang = function (handCards) { // let count = 0; // for (let i = 0; i < handCards.length; ++i) { // let value = this.getValue(handCards[i]) // if (value == 2 || value == 5 || value == 8) { // count++; // if(count >= 2) return false; // } // } // return true; // }; // // 是否单五一枝花 // proto.isDanWu = function (handCards) { // let count1 = 0; // let count2 = 0; // let count3 = 0; // for (let i = 0; i < handCards.length; ++i) { // let value = this.getValue(handCards[i]) // if (value == 2) count1++; // if (value == 5) count2++; // if (value == 8) count3++; // } // if(count1 == 1 || count2 == 1 || count3 == 1) return true; // }; //得到除7对和将将胡之外的大胡牌型,大胡牌型可以乱将 proto.getCardTypeTL = function (chairID,handCards, huCards,hures,isTouch) { let shoupai = handCards/////手牌 let PGPai = huCards/////手上的碰杠牌 let chengju = hures/////整理好之后成句的牌(包括碰杠牌) for (var i = 0; i < this.dahuTypeTL.length; i++) { this.everyDAHType[chairID][i] = 0; if( i == 0 && this.isSevenDouble(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } if( i == 1 && this.everyDAHType[chairID][0] == 1 && this.isHHSevenDouble(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } if( i == 2 && this.everyDAHType[chairID][0] == 1 && this.isSHHSevenDouble(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } if( i == 3 && this.everyDAHType[chairID][0] == 1 && this.isSSHHSevenDouble(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } if( i == 4 && this.isJiangJiangHu(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } if( i == 5 && this.isQQR(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 6 && isTouch && this.isMQ(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 7 && this.isQYS(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 8 && this.isPengPengHu(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 9 && this.isGangKai(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 10 && this.isQiangGang(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } else if( i == 11 && this.isHDLY(shoupai,PGPai,chengju)){ this.everyDAHType[chairID][i] = 1; } } } // 是否七对 proto.isSevenDouble = function (handCards,PGPai,chengju) { if (handCards.length <= CARDS_COUNT) return false; var dcount = 0; var counts = {}; for (let i = 0; i < handCards.length; ++i) { let card = handCards[i]; counts[card] = (counts[card] || 0) + 1; if (counts[card] >= 2) { dcount += 1; counts[card] = 0; } } // console.warn("是否是7对 ",dcount,handCards); return (dcount >= 7); }; // 是否豪华七对 proto.isHHSevenDouble = function (handCards,PGPai,chengju) { if (handCards.length <= CARDS_COUNT) return false; var dcount = 0; for (let i = 0; i < handCards.length-3; ++i) { let card = handCards[i]; if (card == handCards[i+1] && card == handCards[i+2] && card == handCards[i+3]) { dcount += 1; i+=3; } } // console.warn("是否是豪华七对 "+dcount); return (dcount >= 1); }; // 是否双豪华七对 proto.isSHHSevenDouble = function (handCards,PGPai,chengju) { if (handCards.length <= CARDS_COUNT) return false; var dcount = 0; for (let i = 0; i < handCards.length-3; ++i) { let card = handCards[i]; if (card == handCards[i+1] && card == handCards[i+2] && card == handCards[i+3]) { dcount += 1; i+=3; } } return (dcount >= 2); }; // 是否三豪华七对 proto.isSSHHSevenDouble = function (handCards,PGPai,chengju) { if (handCards.length <= CARDS_COUNT) return false; var dcount = 0; for (let i = 0; i < handCards.length-3; ++i) { let card = handCards[i]; if (card == handCards[i+1] && card == handCards[i+2] && card == handCards[i+3]) { dcount += 1; i+=3; } } return (dcount >= 3); }; // 是否将将胡 proto.isJiangJiangHu = function (handCards,PGPai,chengju) { for (let i = 0; i < handCards.length; ++i) { let value = this.getValue(handCards[i]); if (value == 2 || value == 5 || value == 8) continue; else return false; } ////上面是统计手牌2,5,8,下面是统计碰杠牌的2,5,8 if(PGPai && PGPai.length > 0){ for (let i = 0; i < PGPai.length; ++i) { if(!PGPai[i]) continue; let pgcardlist = PGPai[i].cards; if(!pgcardlist) continue; for (let j = 0; j < pgcardlist.length; ++j) { let card2 = pgcardlist[j]; let value = this.getValue(card2); if (value == 2 || value == 5 || value == 8) continue; else return false; } } } return true; } //是否 "全求人", proto.isQQR = function (shoupai,PGPai,chengju) { // console.warn("判断全求人 shoupai "+shoupai); return shoupai.length == 2 && shoupai[0] == shoupai[1]; } //是否 "门清", proto.isMQ = function (shoupai,PGPai,chengju) { if(this.kexuanList[2] != 1) return false; return shoupai.length == (CARDS_COUNT+1) && PGPai.length == 0 } //是否 "清一色", proto.isQYS = function (shoupai,PGPai,chengju) { let huaSe= 0; for (let n = 0; n < shoupai.length; ++n) { let card = shoupai[n]; if(huaSe == 0){ huaSe = this.getType(card); } else{ if(this.getType(card) != huaSe){ return false; } } } ////上面是统计手牌花色种类,下面是统计碰杠牌的花色 if(PGPai && PGPai.length > 0){ for (let i = 0; i < PGPai.length; ++i) { if(!PGPai[i]) continue; let pgcardlist = PGPai[i].cards; if(!pgcardlist) continue; let card2 = pgcardlist[0]; if(this.getType(card2) != huaSe){ return false; } } } return true; }; // 是否碰碰胡 proto.isPengPengHu = function (shoupai,PGPai,chengju) { // console.warn("是否碰碰胡000 shoupai "+shoupai+" PGPai "+JSON.stringify(PGPai)); // console.warn("是否碰碰胡111 chengju "+JSON.stringify(chengju)); let cjlist = chengju.huCards if(!cjlist) return false;/////七对的话没有chengju,所以直接返回false // console.warn("是否碰碰胡222 "+JSON.stringify(chengju)); let keOrGangCount = 0; for (let i = 0; i < cjlist.length; ++i) { if(cjlist[i].style >= 3 && cjlist[i].style <= 10) keOrGangCount += 1; } // return keOrGangCount == 4 && chengju.jiang > 0; if(keOrGangCount == 4 && chengju.jiang > 0) return true; let huCards2 = this.deepCloneTL(PGPai) // console.warn("判断13不搭手上百搭牌个数出错了?????",baiDaCount22,this.sbyBDList,bdIndexlist) var huRes = { card: 0, jiang: 0, huCards: [] }; // 重设将牌 var resetHuRes = (jiang) => { huRes.jiang = jiang; huRes.huCards = []; for (let huCard of huCards2) huRes.huCards.push(huCard); }; for (let i = 0; i < shoupai.length - 1; ++i) { let handCards = this.deepCloneTL(shoupai) if (!this.isJang(handCards[i], handCards[i + 1])) continue; // console.warn("判断13不搭手上百搭牌个数出错了?????000 ",JSON.stringify(huRes)) resetHuRes(handCards[i]);////设置将牌 // console.warn("判断13不搭手上百搭牌个数出错了?????111 ",JSON.stringify(huRes)) let bcjp = handCards[i]; let cards = handCards.slice(0, i);////手牌数组的前i个元素 cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌 this._dumpFixed(cards, huRes.huCards); // console.warn("判断13不搭手上百搭牌个数出错了?????222 ",JSON.stringify(huRes)) i += 1;/////TL++,为了减少运算 if(huRes.huCards.length == 4){ let keOrGangCount = 0; for (let j = 0; j < huRes.huCards.length; ++j) { if(huRes.huCards[j].style >= 3 && huRes.huCards[j].style <= 10) keOrGangCount += 1; } // console.warn("是否碰碰胡333 "+JSON.stringify(huRes)+" keOrGangCount "+keOrGangCount); if(keOrGangCount == 4 && huRes.jiang > 0) return true; } } return false; }; //是否杠开 proto.isGangKai = function (shoupai,PGPai,chengju) { // console.warn("是否杠开 ",this.currChairIDTL,JSON.stringify(this.isGGMG),JSON.stringify(this.isGGAG),JSON.stringify(this.isGGFXG)); // if(this.isSeleCatcedCard){ // if(this.isGGMG[this.currChairIDTL] || this.isGGAG[this.currChairIDTL] || this.isGGFXG[this.currChairIDTL]){ // return true;/////普通杠开 // } // } ////上面是判断刚开的方法,下面是可以杠开和杠炮都判断,因为杠开和杠炮不能同时存在 for (var i = 0; i < this.isGGMG.length; i++) { if(this.isGGMG[i]) return true; } for (var i = 0; i < this.isGGAG.length; i++) { if(this.isGGAG[i]) return true; } for (var i = 0; i < this.isGGFXG.length; i++) { if(this.isGGFXG[i]) return true; } return false; } //是否抢杠胡 proto.isQiangGang = function (shoupai,PGPai,chengju) { return this.isLaGang } //是否海底捞月 proto.isHDLY = function (shoupai,PGPai,chengju) { // console.error("是否海底捞月 "+" this.isZHYZ "+this.isZHYZ+" this.lastCount "+this.lastCount); return (this.isZHYZ && this.lastCount == 0) } // 获得奖码列表和计算奖码分数函数 proto.getJiangmaInfo = function () { // console.warn("获得奖码列表函数 奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中 "+this.jiangmaType) let jiangmaList = [] let jmzs = this.jiangmaCount;//奖码张数 let castC1 = this.castCount;//已经消耗的 let lastC1 = this.lastCount; for (var i = 0; i < jmzs; i++) { let card = 0; if (lastC1 > 0) { card = this.cardsPool[castC1++]; lastC1 -= 1; } if(card > 0) jiangmaList[i] = card; else break; } let startNum1 = 0;/////骰子1的点数 let startNum2 = 0;/////骰子2的点数 if(jiangmaList.length < jmzs){ //抓鸟牌时牌堆剩余牌张数不足的时候通过掷骰子来凑数 startNum1 = this.dice();/////骰子1的点数 startNum2 = this.dice();/////骰子2的点数 } // console.warn("获得奖码列表函数 奖码列表 ",jiangmaList," 长度 ",jiangmaList.length," addThisIsHu ",this.addThisIsHu) //下面是计算奖码分数 let mafen = 0; return { jiangmaList:jiangmaList,mafen:mafen,startNum1:startNum1,startNum2:startNum2} }; //得到本局的各个玩家的中鸟个数 proto.getBJGWJZBGS = function (chairId,jiangmaList,diceNum1,diceNum2,lead,yjList) { // console.warn("每个玩家中鸟个数 chairId " , chairId,jiangmaList,diceNum1,diceNum2,lead,JSON.stringify(yjList)); let tzdsfbqk = [0,0,0,0];//点数分布情况 if(jiangmaList.length == 0){ let dices = diceNum1; if(dices == 1 || dices == 5) tzdsfbqk[0]++; else if(dices == 2 || dices == 6) tzdsfbqk[1]++; else if(dices == 3) tzdsfbqk[2]++; else if(dices == 4) tzdsfbqk[3]++; let dices2 = diceNum2; if(dices2 == 1 || dices2 == 5) tzdsfbqk[0]++; else if(dices2 == 2 || dices2 == 6) tzdsfbqk[1]++; else if(dices2 == 3) tzdsfbqk[2]++; else if(dices2 == 4) tzdsfbqk[3]++; } else if(jiangmaList.length == 1){ let dices = diceNum1+diceNum2; if(dices == 5 || dices == 9) tzdsfbqk[0]++; else if(dices == 2 || dices == 6 || dices == 10) tzdsfbqk[1]++; else if(dices == 3 || dices == 7 || dices == 11) tzdsfbqk[2]++; else if(dices == 4 || dices == 8 || dices == 12) tzdsfbqk[3]++; let cardValue = this.getValue(jiangmaList[0]) if(cardValue == 1 || cardValue == 5 || cardValue == 9) tzdsfbqk[0]++; else if(cardValue == 2 || cardValue == 6) tzdsfbqk[1]++; else if(cardValue == 3 || cardValue == 7) tzdsfbqk[2]++; else if(cardValue == 4 || cardValue == 8) tzdsfbqk[3]++; } else if(jiangmaList.length == 2){ for (var i = 0; i < jiangmaList.length; i++) { let cardValue = this.getValue(jiangmaList[i]) if(cardValue == 1 || cardValue == 5 || cardValue == 9) tzdsfbqk[0]++; else if(cardValue == 2 || cardValue == 6) tzdsfbqk[1]++; else if(cardValue == 3 || cardValue == 7) tzdsfbqk[2]++; else if(cardValue == 4 || cardValue == 8) tzdsfbqk[3]++; } } // let result = []; // if(this.playerAllCount == 2) result = [0,0]; // else if(this.playerAllCount == 3) result = [0,0,0]; // else if(this.playerAllCount == 4) result = [0,0,0,0]; // let cell = this.qshuTypeTL[qshType][1] || 0; // console.warn("每个玩家中鸟个数000==== tzdsfbqk " + tzdsfbqk); let everyZNGS = [0,0,0,0];//每个玩家中鸟个数 if(this.playerAllCount == 2){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[1],tzdsfbqk[0],tzdsfbqk[2],tzdsfbqk[3]]; } else if(this.playerAllCount == 3){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[2],tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[3]]; else if(chairId == 2) everyZNGS = [tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[0],tzdsfbqk[3]]; } else if(this.playerAllCount == 4){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[3],tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2]]; else if(chairId == 2) everyZNGS = [tzdsfbqk[2],tzdsfbqk[3],tzdsfbqk[0],tzdsfbqk[1]]; else if(chairId == 3) everyZNGS = [tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3],tzdsfbqk[0]]; } // console.warn("每个玩家中鸟个数111==== everyZNGS " + everyZNGS); if(lead != -1){ for (var i = 0; i < everyZNGS.length; i++) { if(chairId == lead){ //自己是抓鸟者又是点炮者,说明自己是一炮多响了 //一炮多响的时候,不是赢家也不是点炮者不中鸟 if (yjList.indexOf(i) == -1 && i != lead) everyZNGS[i] = 0; } else{ //正常的点炮,不是点炮者也不是赢家就不中鸟了 if(i != chairId && i != lead) everyZNGS[i] = 0; } } } // console.warn("每个玩家中鸟个数222==== everyZNGS " + everyZNGS); return everyZNGS; } //得到起手胡牌型的总分 proto.getQSHFen = function (chairID) { // console.error("得到起手胡牌型的总分 "+chairID+" "+this.everyXiaoHuList[chairID]+" cd "+this.everyXiaoHuList[chairID].length); let count = 0; for (var i = 0; i < this.everyXiaoHuList[chairID].length; i++) { let zl = this.everyXiaoHuList[chairID][i]; count+=this.qshuTypeTL[zl][1]; } return count; }; //得到本次起手/中途胡牌型的各个玩家的输赢 proto.getBCQSHSY = function (chairId,qshType,diceNum1,diceNum2) { let result = []; if(this.playerAllCount == 2) result = [0,0]; else if(this.playerAllCount == 3) result = [0,0,0]; else if(this.playerAllCount == 4) result = [0,0,0,0]; let cell = this.qshuTypeTL[qshType][1] || 0; let dices = [diceNum1,diceNum2]; let tzdsfbqk = [0,0,0,0];//骰子点数分布情况 for (var i = 0; i < dices.length; i++) { if(dices[i] == 1 || dices[i] == 5) tzdsfbqk[0]++; else if(dices[i] == 2 || dices[i] == 6) tzdsfbqk[1]++; else if(dices[i] == 3) tzdsfbqk[2]++; else if(dices[i] == 4) tzdsfbqk[3]++; } let everyZNGS = [0,0,0,0];//每个玩家中鸟个数 if(this.playerAllCount == 2){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[1],tzdsfbqk[0],tzdsfbqk[2],tzdsfbqk[3]]; } else if(this.playerAllCount == 3){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[2],tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[3]]; else if(chairId == 2) everyZNGS = [tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[0],tzdsfbqk[3]]; } else if(this.playerAllCount == 4){ if(chairId == 0) everyZNGS = [tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3]]; else if(chairId == 1) everyZNGS = [tzdsfbqk[3],tzdsfbqk[0],tzdsfbqk[1],tzdsfbqk[2]]; else if(chairId == 2) everyZNGS = [tzdsfbqk[2],tzdsfbqk[3],tzdsfbqk[0],tzdsfbqk[1]]; else if(chairId == 3) everyZNGS = [tzdsfbqk[1],tzdsfbqk[2],tzdsfbqk[3],tzdsfbqk[0]]; } let bsList = [1,2,4];//分表表示中0,1,2鸟输1,2,4倍 for (let i = 0; i < this.playerAllCount; ++i) { if(i == chairId) continue; let gs = everyZNGS[i]+everyZNGS[chairId]; let sy = bsList[gs] * cell; result[i] -= sy; result[chairId] += sy; } // console.warn("每个玩家中鸟个数==== tzdsfbqk "+tzdsfbqk + " everyZNGS " + everyZNGS+" result "+result); // for (var i = 0; i < result.length; i++) { // if(everyZNGS[i] == 0) result = cell; // else if(everyZNGS[i] == 1) result = cell*2; // else if(everyZNGS[i] == 2) result = cell*4; // } return result; } //得到大胡牌型的总分 proto.getDaHuFen = function (chairID) { let count = 0; for (var i = 0; i < this.everyDAHType[chairID].length; i++) { if(this.everyDAHType[chairID][i] == 1) count+=this.dahuTypeTL[i][1]; } if(count == 0) count = 2; return count; }; //得到大胡牌型的总分2 proto.getDaHuFen2 = function (chairID,typeList) { let count = 0; for (var i = 0; i < typeList.length; i++) { if(typeList[i] == 1) count+=this.dahuTypeTL[i][1]; } if(count == 0) count = 2; return count; }; //得到点炮者 proto.getLead = function (chairID,lead,yjList) { let res = -100; if(chairID != -1){ let yjgs = yjList.length if(yjgs > 1){ res = chairID; } else if(yjgs == 1){ if(yjList[0] == chairID){ res = -1; } else{ res = chairID; } } else if(yjgs == 0){ res = -1; } } if(res == -100) res = lead; return res; }