logic.js 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431
  1. 'use strict';
  2. //// 为什么选择 Lodash ?
  3. //// Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。
  4. //// Lodash 的模块化方法 非常适用于:
  5. //// 遍历 array、object 和 string
  6. //// 对值进行操作和检测
  7. //// 创建符合功能的函数
  8. var _ = require('lodash');
  9. var quick = require('quick-pomelo');
  10. var logger = quick.logger.getLogger('fhmj', __filename);
  11. // 所有牌
  12. const CARDS = [
  13. 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒
  14. 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万
  15. 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条
  16. // 51, // 中
  17. 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒
  18. 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万
  19. 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条
  20. // 51, // 中
  21. 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒
  22. 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万
  23. 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条
  24. // 51, // 中
  25. 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒
  26. 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万
  27. 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条
  28. // 51, // 中
  29. ];
  30. // 块类型
  31. const STYLE = {
  32. NULL: 0, // 无效
  33. CHI: 1, // 吃牌
  34. SUN: 2, // 顺序
  35. PENG: 3, // 碰子
  36. KE: 4, // 刻子
  37. GANG: 5, // 杠子
  38. ANGANG: 6, // 暗杠
  39. ZMGANG: 7, // 自摸明杠
  40. BUDA:8, // TL++不搭
  41. // LIANGBD:9, // TL++两张百搭和一张普通牌组成一个块
  42. // SANBD:10, // TL++三张百搭和一张普通牌组成一个块
  43. };
  44. // 椅子数
  45. const CHAIR_COUNT = 4;
  46. const CARDS_COUNT = 13;
  47. // 构造方法
  48. var Logic = function (type,gameKindTL,playerAllCount,other) {
  49. // 类型
  50. this.type = type;
  51. this.other = other;//////TL++2人3人的游戏规则
  52. this.jiangmaType = -1;////奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中
  53. this.jiangmaCount = -1;////奖码张数
  54. if(this.other & 1){
  55. this.jiangmaType = 1;
  56. if(this.other & 8) this.jiangmaCount = 2;
  57. else if(this.other & 16) this.jiangmaCount = 4;
  58. else if(this.other & 32) this.jiangmaCount = 6;
  59. }
  60. else if(this.other & 2){
  61. this.jiangmaType = 2;
  62. this.jiangmaCount = 0;
  63. }
  64. else if(this.other & 4){
  65. this.jiangmaType = 3;
  66. this.jiangmaCount = 1;
  67. }
  68. this.hzCount = 0;/////红中个数
  69. if(this.other & 64) this.hzCount = 4;
  70. else if(this.other & 1024) this.hzCount = 6;
  71. else if(this.other & 2048) this.hzCount = 8;
  72. this.isQGHJM = false;/////是否抢杠胡奖码
  73. if(this.other & 128) this.isQGHJM = true;
  74. this.isHZHG = false;/////是否荒庄荒杠
  75. if(this.other & 256) this.isHZHG = true;
  76. this.isWGHZJYM = false;/////无红中胡加一码
  77. if(this.other & 512) this.isWGHZJYM = true;
  78. this.isZNZM = this.type == 2;/////是否只能自摸,拉杠情况可以胡
  79. // console.warn("logic 奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中 "+this.jiangmaType)
  80. // console.warn("logic 奖码张数 "+this.jiangmaCount)
  81. // console.warn("logic 是否红中赖子 "+this.isHZLZ)
  82. // console.warn("logic 是否抢杠胡奖码 "+this.isQGHJM)
  83. // console.warn("logic 是否荒庄荒杠 "+this.isHZHG)
  84. // console.warn("logic 无红中胡加一码 "+this.isWGHZJYM)
  85. // console.warn("logic 是否只能自摸 "+this.isZNZM)
  86. // 七对
  87. // this.has7d = true;/////TL++因为奉化麻将当中本身就可以胡7对
  88. // 全牌
  89. var cards = _.clone(CARDS);
  90. // 添加红中红中
  91. if (this.hzCount > 0){
  92. for (let i = 0; i < this.hzCount; ++i) {
  93. cards[cards.length] = 51;
  94. }
  95. }
  96. this.castCount = 0;
  97. this.disCount = 0;
  98. this.lastCount = cards.length;//////设置剩余牌数为了测试海底捞月
  99. this.cardsPool = cards;
  100. this.cardsyl = _.clone(cards);
  101. //////以下变量全是TL++
  102. this.gameKindTL = gameKindTL || 1;////平搓还是冲刺 = 1代表平搓 = 2代表冲刺
  103. this.playerAllCount = playerAllCount || 4;////游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局
  104. this.setCardFilerIndex = 0
  105. this.baiDaCard = 51;/////TL++,拿到百搭牌
  106. this.baiDaList = [0,0,0];/////TL++,拿到百搭牌数组
  107. this.sbyBDList = []//////得到某人手中的百搭牌数组
  108. this.chuPaiCountTL = 0//////TL++,记录出牌的个数,为了判断天胡和地胡
  109. this.moPaiCountTL = 0//////TL++,记录出牌的个数,为了判断天胡和地胡
  110. this.lastMoPaiChairID = 0//////TL++,最后一个摸牌玩家的id
  111. this.addThisIsHu = 0//////TL++,胡牌判断时加上这张能不能胡
  112. this.isSeleCatcedCard = false//////判断能否胡牌的那张牌是自己抓的还是别人打出来的
  113. this.currChairIDTL = 0/////当前判断胡的chairID,用于得到当前玩家的胡牌情况
  114. this.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  115. this.isGuoHuList = [[false,0],[false,0],[false,0],[false,0],]/////TL++,各个玩家在本轮是否点击了过胡和点击过牌时的台数
  116. this.setCardFileName = '';/////设置手牌的文件名
  117. this.cardGroupIndex = 0;////要设置的牌型种类
  118. this.isZHYZ = false;/////是不是最后1张
  119. this.isMZWF = [0,1,2,3];/////是不是满足位风
  120. // console.warn("ppppppppppp 长度 "+cards.length+" cards "+cards);
  121. };
  122. Logic.setHCfileNameList =[/////全部设置牌型的文件名
  123. "setHandCard_tianhu",
  124. ]
  125. // 导出常量
  126. Logic.CARDS = CARDS;
  127. Logic.STYLE = STYLE;
  128. Logic.CHAIR_COUNT = CHAIR_COUNT;
  129. Logic.CARDS_COUNT = CARDS_COUNT;
  130. // 导出类
  131. module.exports = Logic;
  132. // 原型对象
  133. var proto = Logic.prototype;
  134. /////TL++为了得到百搭牌数组用于判断是否需要补花和手牌中百搭牌个数
  135. proto.setBDList = function () {
  136. this.baiDaList = [this.baiDaCard,this.baiDaCard,this.baiDaCard]/////TL++,拿到百搭牌
  137. };
  138. ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡
  139. proto.chuPaiTL = function () {
  140. // console.warn("111c天胡判断不正确",this.chuPaiCountTL);
  141. this.chuPaiCountTL += 1//////这个其实并不是真实的出牌个数,因为这个方法的调用在判断吃碰杠胡之前调用的
  142. }
  143. ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡
  144. proto.moPaiTL = function () {
  145. // console.warn("111c天胡判断不正确",this.chuPaiCountTL);
  146. this.moPaiCountTL += 1//////TL++,记录出牌的个数,为了判断天胡和地胡 += 1
  147. }
  148. ///////TL++重置默认数据,在每局游戏开始的洗牌函数中调用
  149. proto.resetDataOnGameStart = function () {
  150. this.chuPaiCountTL = 0//////TL++出牌个数
  151. this.moPaiCountTL = 0//////TL++,记录摸牌的个数,为了判断天胡和地胡
  152. this.lastMoPaiChairID = 0//////TL++,最后一个摸牌玩家的id
  153. this.addThisIsHu = 0//////TL++,胡牌判断时加上这张能不能胡
  154. this.isSeleCatcedCard = false//////判断能否胡牌的那张牌是自己抓的还是别人打出来的
  155. this.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  156. this.isGuoHuList = [[false,0],[false,0],[false,0],[false,0],]/////TL++,各个玩家在本轮是否点击了过胡和点击过牌时的台数
  157. this.isZHYZ = false;/////是不是最后1张
  158. }
  159. // 重新洗牌
  160. proto.shuffle = function () {
  161. this.castCount = 0;
  162. this.disCount = 0;
  163. this.cardsPool = _.clone(this.cardsyl);
  164. this.lastCount = this.cardsPool.length;
  165. this.cardsPool = _.shuffle(this.cardsPool);////随机打乱一个数组
  166. this.cardsPool = _.shuffle(this.cardsPool);////洗第二次牌
  167. // this.cardsPool = _.shuffle(this.cardsPool);////洗第三次牌
  168. };
  169. // 填充数组
  170. proto.fillDeep = function (array, o, isMore) {
  171. for (let i = 0; i < array.length; ++i) {
  172. if (!isMore) {
  173. array[i] = _.clone(o);
  174. } else {
  175. array[i] = _.cloneDeep(o);/////深度拷贝,就是重新分配内存空间,浅拷贝则是两个变量共用一个内存对象
  176. }
  177. }
  178. return array;
  179. };
  180. //////TL++ 深复制一个object类型的数据
  181. proto.deepCloneTL = function (obj){
  182. let objClone = Array.isArray(obj)?[]:{};
  183. if(obj && typeof obj==="object"){
  184. for(let key in obj){
  185. if(obj.hasOwnProperty(key)){
  186. //判断ojb子元素是否为对象,如果是,递归复制
  187. if(obj[key]&& typeof obj[key] ==="object"){
  188. objClone[key] = this.deepCloneTL(obj[key]);
  189. }else{
  190. //如果不是,简单复制
  191. objClone[key] = obj[key];
  192. }
  193. }
  194. }
  195. }
  196. return objClone;
  197. };
  198. // 获取类型
  199. proto.getType = function (card) {
  200. return Math.floor(card / 10);
  201. };
  202. // 获取牌值
  203. proto.getValue = function (card) {
  204. return card % 10;
  205. };
  206. // 手牌排序
  207. proto.sort = function (handCards) {
  208. return _.sortBy(handCards);///降序排序
  209. };
  210. // 删除手牌 /////TL++参数isBuHua表示是否因为补花而造成的删除牌
  211. proto.remove = function (handCards, cards) {
  212. if (typeof (cards) == 'number') {
  213. if (cards == handCards[handCards.length - 1]) {
  214. return (handCards.pop(), true);
  215. } else {
  216. let pos = handCards.indexOf(cards);
  217. if (pos == -1) return false;
  218. return (handCards.splice(pos, 1), true);
  219. }
  220. }
  221. var length = cards.length;
  222. if (length > 1 && cards[0] == cards[length - 1]) {
  223. if (cards[0] == handCards[handCards.length - 1]) {
  224. handCards.pop();
  225. length -= 1;
  226. }
  227. let pos = handCards.indexOf(cards[0]);
  228. if (pos == -1) return false;
  229. handCards.splice(pos, length);
  230. } else {
  231. for (let i = 0; i < length; ++i) {
  232. let pos = handCards.indexOf(cards[i]);
  233. if (pos == -1) return false;
  234. handCards.splice(pos, 1);
  235. }
  236. }
  237. return true;
  238. };
  239. // 调整手牌
  240. proto.adjust = function (handCards) {
  241. var length = handCards.length;
  242. if (length < 2) return false;
  243. if (handCards[length - 1] < handCards[length - 2]) {
  244. let moCard = handCards.pop();
  245. let pos = _.findIndex(handCards, (i) => (i >= moCard));
  246. if (pos == -1) handCards.push(moCard);
  247. else handCards.splice(pos, 0, moCard);
  248. }
  249. return true;
  250. };
  251. // 投骰子
  252. proto.dice = function () {
  253. return _.random(1, 6);
  254. };
  255. // 剩余牌数
  256. proto.leaveCount = function () {
  257. return this.lastCount;
  258. };
  259. //////TL++,人工设置测试牌型
  260. proto.setTestSendCardsTL = function () {
  261. this.setCardFileName = '';
  262. let fileName = "setHandCard_tianhu"
  263. if(!fileName) return;/////文件名字不存在
  264. // console.warn("设置手牌的文件名",fileName);
  265. this.setCardFileName = fileName
  266. var SetHandCardTL = require('./setcard/' + fileName);
  267. if(!SetHandCardTL) return;
  268. //////TL++,设置手牌的文件
  269. this.setHandCardTL = new SetHandCardTL();
  270. ////console.error("洗牌之后的牌",this.cardsPool);
  271. let ccc = this.setHandCardTL.getSCFP(this.cardGroupIndex)
  272. if(ccc){//////已经设置的手牌发完了就随机发牌
  273. this.cardsPool = ccc/////设置手牌的地方 设置牌
  274. this.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型
  275. // SetHandCardTL.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型
  276. // if(SetHandCardTL.cardGroupIndex == 1) SetHandCardTL.cardGroupIndex = 0
  277. }
  278. else{
  279. this.setCardFilerIndex += 1;
  280. this.cardGroupIndex = 0;
  281. // SetHandCardTL.cardGroupIndex = 0;
  282. if(Logic.setCardFilerIndex < Logic.setHCfileNameList.length) this.setTestSendCardsTL()
  283. }
  284. }
  285. // 初始手牌
  286. proto.handCards = function (chBanker,_PJHF,_over,recordid,_ctime) {
  287. this.resetDataOnGameStart()//////TL++
  288. this.shuffle();
  289. // if(this.hzCount == 8) {
  290. // // 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]
  291. // this.setTestSendCardsTL()///////设置手牌的地方,设置发牌 不需要设置的时候注释掉这个方法就可以了
  292. // this.lastCount = this.cardsPool.length;//////设置剩余牌数设置剩余牌数,测试完这句要删掉
  293. // }
  294. let dqjs = _over + 1;
  295. _PJHF.writexpJson(this.deepCloneTL(this.cardsPool),dqjs,recordid,_ctime);
  296. //// 下面这个是随机发牌但是起手发lzgs张癞子的逻辑
  297. // let lzgs = 3//癞子个数
  298. // let djg = 0;
  299. // for (let i = 0; i < this.cardsPool.length; i++) {
  300. // if(this.cardsPool[i] == 51){
  301. // let xx = this.cardsPool[djg]
  302. // this.cardsPool[djg] = 51;
  303. // this.cardsPool[i] = xx;
  304. // djg++
  305. // if(djg >= lzgs){
  306. // break
  307. // }
  308. // }
  309. // }
  310. /////TL++设置百搭牌数组
  311. this.setBDList()
  312. var result = [];
  313. var castCount = 0;
  314. for (let i = 0; i < this.playerAllCount; ++i) {
  315. let cardCount = CARDS_COUNT;
  316. if (i == chBanker) cardCount += 1;
  317. let cards = this.cardsPool.slice(castCount, castCount + cardCount);
  318. castCount += cardCount;
  319. result.push({ cards: this.sort(cards) });
  320. }
  321. this.castCount += castCount
  322. this.lastCount -= castCount;
  323. // this.lastCount -= this.disCountTL;////因为翻出来的百搭牌不能被摸走
  324. // console.error("发的手牌",result);
  325. return result;
  326. };
  327. // 是否无牌
  328. proto.isNoCards = function () {
  329. return this.lastCount <= 0;
  330. };
  331. // 摸牌函数
  332. proto.moCard = function (isgang) {
  333. // console.error("摸排摸排---------",isgang,this.disCountTL,this.lastCount);
  334. var card = 0;
  335. if (this.lastCount > 0) {
  336. card = this.cardsPool[this.castCount++];
  337. this.lastCount -= 1;
  338. }
  339. return { card: card };
  340. };
  341. // 是否将牌
  342. proto.isJang = function (lcard, rcard) {
  343. return lcard == rcard;
  344. };
  345. // 可否碰牌
  346. proto.isPeng = function (handCards, card) {
  347. if(card == 51) return false;
  348. for (let i = 0; i < handCards.length - 1; ++i) {
  349. if (handCards[i] == card && handCards[i + 1] == card) {
  350. return true;
  351. }
  352. }
  353. return false;
  354. };
  355. // 碰牌 TL++参数chirID为了判断圈风和位风
  356. proto.peng = function (chirID,handCards, card) {
  357. if (this.isPeng(handCards, card)) {
  358. return { style: STYLE.PENG, cards: [card, card, card], disc: [card] };
  359. }
  360. };
  361. // 吃牌,1-@**左吃, 2-*@*中吃, 3-@**右吃
  362. proto.chi = function (handCards, card, type) {
  363. var chis = this.chiAnalyze(handCards, card, type);
  364. if (chis[0]) {
  365. let res = { style: STYLE.CHI, type: type, disc: [card] };
  366. if (type == 1) {
  367. res.cards = [card, card + 1, card + 2];
  368. if (this.getValue(card) < 7) {
  369. res.disc.push(card + 3);
  370. }
  371. } else if (type == 2) {
  372. res.cards = [card - 1, card, card + 1];
  373. } else {
  374. res.cards = [card - 2, card - 1, card];
  375. if (this.getValue(card) > 3) {
  376. res.disc.push(card - 3);
  377. }
  378. }
  379. return res;
  380. }
  381. };
  382. // 杠牌,1-普通杠, 2-暗杠, 3-自摸明杠 TL++参数chirID为了判断圈风和位风
  383. proto.gang = function (chirID,handCards, card, type) {
  384. // 结果
  385. var res = null;
  386. // 明杠
  387. if (type == 1) {
  388. let gang = this.gangAnalyze(handCards, card);
  389. if (gang) {
  390. res = { style: STYLE.GANG, cards: [card, card, card] };
  391. }
  392. }
  393. // 暗杠
  394. else if (type == 2) {
  395. let anGang = this.anGangAnalyze(handCards, card);
  396. if (anGang[0]) {
  397. res = { style: STYLE.ANGANG, cards: [card, card, card] };
  398. }
  399. }
  400. return res;
  401. };
  402. // 自摸明杠,1-普通杠, 2-暗杠, 3-自摸明杠 TL++参数chirID为了判断圈风和位风
  403. proto.zmGang = function (chirID,handCards, huCards, card) {
  404. var zmGang = this.zmGangAnalyze(handCards, huCards, card);
  405. if (zmGang[0]) {
  406. return { style: STYLE.ZMGANG, cards: [card, card, card] };
  407. }
  408. };
  409. // 吃牌分析,1-@**左吃, 2-*@*中吃, 3-@**右吃, type可以不传
  410. proto.chiAnalyze = function (handCards, card, type) {
  411. // 结果集合
  412. var result = [];
  413. // 排除风字
  414. if (handCards.length < 2 || card > 40) return result;
  415. // 查找句子
  416. var length = handCards.length;
  417. for (let i = 0; i < length; ++i) {
  418. // 牌面值
  419. let value = this.getValue(card);
  420. // @**左吃,吃类型(可以不指定)
  421. if (!type || type == 1) {
  422. if (value < 8 && i < length - 1) {
  423. if (handCards[i] == card + 1 && handCards[i + 1] == card + 2) {
  424. result.push({ type: 1, card: card });
  425. }
  426. }
  427. }
  428. // *@*中吃,吃类型(可以不指定)
  429. if (!type || type == 2) {
  430. if (value > 1 && value < 9 && i < length - 1) {
  431. if (handCards[i] == card - 1 && handCards[i + 1] != card - 1) {
  432. for (let j = i + 1; j < i + 5 && j < length; ++j) {
  433. if (handCards[j] == card + 1) {
  434. result.push({ type: 2, card: card });
  435. break;
  436. }
  437. }
  438. }
  439. }
  440. }
  441. // **@右吃,吃类型(可以不指定)
  442. if (!type || type == 3) {
  443. if (value > 2 && i < length - 1) {
  444. if (handCards[i] == card - 2 && handCards[i + 1] == card - 1) {
  445. result.push({ type: 3, card: card });
  446. }
  447. }
  448. }
  449. }
  450. return result;
  451. };
  452. // 普通杠分析,1-普通杠, 2-暗杠, 3-自摸明杠
  453. proto.gangAnalyze = function (handCards, card) {
  454. // 结果对象
  455. var result = null;
  456. if(card == 51 || this.lastCount <= 0) return result;//红中不能碰杠
  457. var length = handCards.length;
  458. if (length < 3) return result;
  459. // 查找同牌
  460. for (let i = 0; i < length - 2; ++i) {
  461. if (handCards[i] == card && handCards[i + 1] == card && handCards[i + 2] == card) {
  462. result = { type: 1, card: card };
  463. break;
  464. }
  465. }
  466. return result;
  467. };
  468. // 暗杠分析,1-普通杠, 2-暗杠, 3-自摸明杠, card可以不传
  469. proto.anGangAnalyze = function (handCards, card) {
  470. // 结果对象
  471. var result = [];
  472. if(this.lastCount <= 0) return result;//红中不能碰杠
  473. var length = handCards.length;
  474. if (length < 4) return result;
  475. // 查找同牌
  476. var moCard = handCards[length - 1];
  477. for (let i = 0; i < length - 3; ++i) {
  478. // 指定杠牌,可以不指定
  479. if (card && handCards[i] != card) continue;
  480. // 判定是否刻子
  481. if (handCards[i] == handCards[i + 1] && handCards[i] == handCards[i + 2]) {
  482. // 手上有杠牌
  483. if (handCards[i] == handCards[i + 3]) {
  484. if(handCards[i] != 51){
  485. result.push({ type: 2, card: handCards[i] });
  486. }
  487. }
  488. // 刚摸到杠牌
  489. else if (handCards[i] == moCard) {
  490. if(handCards[i] != 51){
  491. result.push({ type: 2, card: moCard });
  492. }
  493. }
  494. }
  495. }
  496. return result;
  497. };
  498. // 自摸杠分析,1-普通杠, 2-暗杠, 3-自摸明杠, card可以不传
  499. proto.zmGangAnalyze = function (handCards, huCards, card) {
  500. // 返回结果
  501. var result = [];
  502. if(card == 51 || this.lastCount <= 0) return result;//红中不能碰杠
  503. // 遍历句子
  504. for (let i = 0; i < huCards.length; ++i) {
  505. if (huCards[i].style != STYLE.PENG) {
  506. continue;
  507. }
  508. let _card = huCards[i].cards[0];
  509. if (card && _card != card) continue;
  510. let pos = handCards.indexOf(_card);
  511. if (pos != -1) {
  512. result.push({ type: 3, card: _card });
  513. if (card) break;
  514. }
  515. }
  516. return result;
  517. };
  518. // 分析牌型
  519. proto.parseBlock = function (card1, card2, card3) {
  520. // 刻子
  521. if (card1 && card1 == card2 && card1 == card3) {
  522. return { style: STYLE.KE, cards: [card1, card2, card3] };
  523. }
  524. // 顺子(排除风字)
  525. var cards = this.sort([card1, card2, card3]);
  526. if (cards[2] < 40) {
  527. if (cards[2] == cards[1] + 1 && cards[1] == cards[0] + 1) {
  528. return { style: STYLE.SUN, cards: cards };
  529. }
  530. }
  531. };
  532. // TL++,得到手牌中百搭牌的个数
  533. proto.getBDCount = function (cards) {
  534. ////TL++,整个for循环判断手牌中的百搭牌个数
  535. let baiDaCount = 0
  536. for (let i = 0; i < cards.length; ++i) {
  537. if(cards[i] == this.baiDaCard) baiDaCount = baiDaCount + 1
  538. }
  539. return baiDaCount
  540. }
  541. // TL++,得到手牌中百搭牌的shuzu数组
  542. proto.getBDListZZ = function (cards) {
  543. this.sbyBDList = []//////重置某人手牌中的百搭牌数组
  544. ////TL++,整个for循环判断手牌中的百搭牌个数
  545. let baiDaCount = 0
  546. let baiDali = []
  547. for (let i = 0; i < cards.length; ++i) {
  548. if(cards[i] == this.baiDaCard){
  549. baiDali[baiDaCount] = cards[i]
  550. baiDaCount = baiDaCount + 1
  551. }
  552. }
  553. return baiDali
  554. }
  555. // TL++,得到手牌中百搭牌的index数组
  556. proto.getBDIndexList = function (cards) {
  557. ////TL++,整个for循环判断手牌中的百搭牌个数
  558. let baiDali = []
  559. for (let i = 0; i < cards.length; ++i) {
  560. let cardTL = cards[i];
  561. if(this.baiDaList[0] && cardTL == this.baiDaList[0]) baiDali[baiDali.length] = i;
  562. else if(this.baiDaList[1] && cardTL == this.baiDaList[1]) baiDali[baiDali.length] = i;
  563. else if(this.baiDaList[2] && cardTL == this.baiDaList[2]) baiDali[baiDali.length] = i;
  564. }
  565. return baiDali
  566. }
  567. // TL++,得到手牌中百搭牌的index,用于删除手牌中的百搭牌
  568. proto.getBDIndex = function (cards) {
  569. ////TL++,整个for循环判断手牌中的百搭牌个数
  570. let baiDali = []
  571. for (let i = 0; i < cards.length; ++i) {
  572. let cardTL = cards[i];
  573. if(this.sbyBDList[0] && cardTL == this.sbyBDList[0]) baiDali[baiDali.length] = i;
  574. if(this.sbyBDList[1] && cardTL == this.sbyBDList[1]) baiDali[baiDali.length] = i;
  575. if(this.sbyBDList[2] && cardTL == this.sbyBDList[2]) baiDali[baiDali.length] = i;
  576. }
  577. return baiDali
  578. }
  579. // TL++,得到默认手牌中百搭牌当的数组 cards: 手牌去除百搭之后的牌
  580. proto.getBDMakeList = function (cards,isNeedAllZi) {
  581. if(cards.length == 0){
  582. ////手上就剩百搭牌的时候 需要把所有牌都当一遍
  583. let reslist = [
  584. 11, 12, 13, 14, 15, 16, 17, 18, 19, // 筒
  585. 21, 22, 23, 24, 25, 26, 27, 28, 29, // 万
  586. 31, 32, 33, 34, 35, 36, 37, 38, 39, // 条
  587. ]
  588. return reslist;
  589. }
  590. ////TL++,整个for循环按照手牌情况确定百搭牌当的范围
  591. let makeList = this.deepCloneTL(cards)
  592. for (let i = 0; i < cards.length; ++i) {
  593. let cardTL = cards[i];
  594. let type = this.getType(cardTL);
  595. let vale = this.getValue(cardTL);
  596. if(type < 4){
  597. if(vale == 1){
  598. let makeValue = cardTL + 1;
  599. if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue;
  600. }
  601. else if(vale == 9){
  602. let makeValue = cardTL - 1;
  603. if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue;
  604. }
  605. else if(vale > 1 && vale < 9){
  606. let makeValue = cardTL - 1;
  607. if(makeList.indexOf(makeValue) == -1) makeList[makeList.length] = makeValue;
  608. let makeValue2 = cardTL + 1;
  609. if(makeList.indexOf(makeValue2) == -1) makeList[makeList.length] = makeValue2;
  610. }
  611. }
  612. }
  613. // let makeList2 = makeList.concat([41,42,43,44,51,52,53])/////给当的数组拼接字牌
  614. // var xx = [1,1,2,3,4,1,2]
  615. // var xx22 = _.uniq(xx)
  616. // console.warn("数组去重",xx,xx22);///[ 1, 1, 2, 3, 4, 1, 2 ] [ 1, 2, 3, 4 ]
  617. // xx[1] = 6
  618. // console.warn("22数组去重",xx,xx22);////[ 1, 6, 2, 3, 4, 1, 2 ] [ 1, 2, 3, 4 ]
  619. return _.uniq(makeList);
  620. }
  621. // 提取成句 card:手上的所有牌删除2张用来做将的牌之后剩下的牌 整理是否为刻子或者顺子
  622. proto._dumpFixed = function (cards, huCards) {
  623. if(this.currChairIDTL == 0){
  624. // console.error("sscc提取成句没有百搭cards",cards);
  625. // console.error("sscc提取成ju没有百搭huCards",huCards);
  626. }
  627. for (let i = 0; i < cards.length - 2; ++i) {
  628. let card = cards[i];
  629. if (card <= 0) continue;
  630. if (card == cards[i + 1] && card == cards[i + 2]) {
  631. huCards.push({ style: STYLE.KE, cards: [card, card, card] });
  632. cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0;
  633. i += 2; continue;
  634. }
  635. if (card > 40 || this.getValue(card) > 7) continue;
  636. let second = -1, third = -1;
  637. for (let j = i + 1; j < cards.length; ++j) {
  638. if (cards[j] == card + 1) second = j;
  639. if (cards[j] == card + 2) third = j;
  640. if (cards[j] > card + 2) break;
  641. if (second != -1 && third != -1) break;
  642. }
  643. if (second != -1 && third != -1) {
  644. huCards.push({ style: STYLE.SUN, cards: [card, cards[second], cards[third]] });
  645. cards[i] = 0; cards[second] = 0; cards[third] = 0;
  646. }
  647. }
  648. };
  649. // 提取成句TL++,这个方法和上面的方法的使用场景都是在没有百搭牌的环境下提取成句,区别在于上面优先提取3同本方法优先提取三同
  650. proto._dumpFixed22 = function (cards, huCards) {
  651. if(this.currChairIDTL == 0){
  652. // console.error("sscc提取成句没有百搭222cards",cards);
  653. // console.error("sscc提取成ju没有百搭222huCards",huCards);
  654. }
  655. for (let i = 0; i < cards.length - 2; ++i) {
  656. let card = cards[i];
  657. if (card <= 0) continue;
  658. if (card <= 40 || this.getValue(card) <= 7){
  659. let second = -1, third = -1;
  660. for (let j = i + 1; j < cards.length; ++j) {
  661. if (cards[j] == card + 1) second = j;
  662. if (cards[j] == card + 2) third = j;
  663. if (cards[j] > card + 2) break;
  664. if (second != -1 && third != -1) break;
  665. }
  666. if (second != -1 && third != -1) {
  667. huCards.push({ style: STYLE.SUN, cards: [card, cards[second], cards[third]] });
  668. cards[i] = 0; cards[second] = 0; cards[third] = 0;
  669. }
  670. }
  671. card = cards[i];
  672. if (card <= 0) continue;
  673. if (card == cards[i + 1] && card == cards[i + 2]) {
  674. huCards.push({ style: STYLE.KE, cards: [card, card, card] });
  675. cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0;
  676. i += 2; continue;
  677. }
  678. }
  679. };
  680. //////TL++返回结果,封装此方法是为了代码复用
  681. proto.outHures = function (huRes,handCards,hucardTL) {
  682. // if(this.currChairIDTL == 0) console.warn("outHuresoutHu++++++++++++++",this.isGuoHuList[this.currChairIDTL][0],huRes.huCards.length,this.isGuoHuList);
  683. if (huRes.huCards.length >= 4){
  684. return huRes;////没有点击过胡直接胡
  685. }
  686. }
  687. //////TL++,判断一手张牌是否为百搭牌
  688. proto.judgeACardISBD = function (card) {
  689. return card == this.baiDaCard;
  690. }
  691. // 提取成句 card:手上的所有牌删除2张用来做将的牌之后剩下的牌 整理是否为刻子或者顺子
  692. proto._dumpFixed333 = function (_cards, huCards) {
  693. // if(this.currChairIDTL == 0){
  694. // console.error("sscc提取成句没有百搭cards",_cards,this.addThisIsHu);
  695. // console.error("sscc提取成ju没有百搭huCards",huCards);
  696. // }
  697. let cards = []//////剔除别人打出的那张牌之后的手牌
  698. for (let i = 0; i < _cards.length; ++i) {
  699. if(_cards[i] == this.addThisIsHu){
  700. cards = _cards.slice(0, i);////手牌数组的前i个元素
  701. cards = cards.concat(_cards.slice(i + 1));////给数组cards拼接上手牌的第 i+1 个以后的全部数组元素
  702. break;
  703. }
  704. }
  705. let count = huCards
  706. for (let i = 0; i < cards.length - 2; ++i) {
  707. let card = cards[i];
  708. if(card <= 0) continue;
  709. if (card == cards[i + 1] && card == cards[i + 2]) {
  710. count += 1;
  711. cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0;
  712. i += 2; continue;
  713. }
  714. if (card > 40 || this.getValue(card) > 7) continue;
  715. let second = -1, third = -1;
  716. for (let j = i + 1; j < cards.length; ++j) {
  717. if (cards[j] == card + 1) second = j;
  718. if (cards[j] == card + 2) third = j;
  719. if (cards[j] > card + 2) break;
  720. if (second != -1 && third != -1) break;
  721. }
  722. if (second != -1 && third != -1) {
  723. count += 1;
  724. cards[i] = 0; cards[second] = 0; cards[third] = 0;
  725. }
  726. }
  727. // if(this.currChairIDTL == 0) console.warn("我的神啊抛搭 买买买",count,count >= 4);
  728. this.isPaoDa = count >= 4
  729. };
  730. ////这个一般会执行3次 除了打牌的那个人之外的3个人,因为打牌的那个人肯定是不能胡或者不想胡所以就不判断了
  731. // 胡牌分析 chairID(TL++这个参数) 手牌 加上这张判断能不能胡 手上的吃碰杠牌 是否自己摸上来的
  732. proto.huAnalyze = function (chairID,handCards, card, huCards, isTouch) {
  733. // console.error("sscc777胡牌分析card",card);
  734. // console.error("sscc777胡牌分析handCards",handCards);
  735. // console.error("sscc777胡牌分析huCards",huCards);
  736. // console.error("sscc777胡牌分析isTouch",isTouch);
  737. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  738. this.isPaoDa = false/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  739. this.isQiDui = false;//////TL++,是否7对
  740. let tempAllTai = 0/////临时总台数
  741. let tempres = {}///本函数的返回值
  742. this.addThisIsHu = card//////TL++,胡牌判断时加上这张能不能胡
  743. this.isSeleCatcedCard = isTouch//////判断能否胡牌的那张牌是自己抓的还是别人打出来的
  744. this.currChairIDTL = chairID/////当前判断胡的chairID,用于得到当前玩家的花牌情况
  745. this.dangAfterBDListTL = [];/////7月18日+的
  746. // console.warn("胡牌分析 isGuoHuList ",this.isGuoHuList," chairID ",chairID," isTouch ",isTouch);
  747. if(this.isGuoHuList[chairID][0]){
  748. // console.warn("此人点过胡了 ",chairID," isTouch ",(!isTouch));
  749. if(!isTouch){
  750. // console.warn("不是此人摸牌 ",chairID,isTouch);
  751. return false;
  752. }
  753. }
  754. let baiDaCount22 = 0
  755. let bdIndexlist = []
  756. if (!isTouch){
  757. baiDaCount22 = this.getBDCount(handCards)
  758. this.sbyBDList = this.getBDListZZ(handCards)
  759. handCards = handCards.concat(card);/////不是自己抓的就把这张牌拼接进手牌中
  760. handCards = this.sort(handCards);
  761. bdIndexlist = this.getBDIndexList(handCards)
  762. }
  763. else{
  764. handCards = this.sort(handCards);
  765. baiDaCount22 = this.getBDCount(handCards)
  766. this.sbyBDList = this.getBDListZZ(handCards)
  767. bdIndexlist = this.getBDIndexList(handCards)
  768. }
  769. // console.warn("判断13不搭手上百搭牌个数出错了?????",baiDaCount22,this.sbyBDList,bdIndexlist)
  770. handCards = this.sort(handCards);
  771. var huRes = { card: card, jiang: 0, huCards: [] };
  772. // 重设将牌
  773. var resetHuRes = (jiang) => {
  774. huRes.jiang = jiang;
  775. huRes.huCards = [];
  776. for (let huCard of huCards) huRes.huCards.push(huCard);
  777. };
  778. // 手牌不全
  779. var length = handCards.length;
  780. if (length % 3 != 2) return;
  781. let hucardTL = huCards//////TL++,保存碰杠牌的初始值,因为这个参数会在下面的代码中被修改掉
  782. //////TL++,判断是否全是字牌,因为如果全是字牌是可以胡牌的
  783. let sspgpbb = this.deepCloneTL(huRes)/////手上的碰杠牌
  784. for (let huCard of huCards) sspgpbb.huCards.push(huCard)/////手上的碰杠牌
  785. if(baiDaCount22 == 4 && this.hzCount == 4){
  786. //选择4红中规则的时候,手里有4张红中的话可以直接胡,6红中8红中不可直接胡
  787. // tempres = huCards
  788. return huRes;
  789. }
  790. // let str3a3 = "logic xmpdptpx: " + baiDaCount22;
  791. // logger.info(str3a3);////cssj
  792. // console.warn("判断胡--------isTouch baiDaCount22",isTouch ,baiDaCount22,this.addThisIsHu);
  793. // if(chairID == 0) console.warn("xxxxxxxxxxxxxxxxxxxxxxxxx能走到这里说明不是7对和百搭的手牌",handCards);
  794. // if(chairID == 0) console.warn("ccccccccccccc手牌百搭牌index",bdIndexlist);
  795. if(baiDaCount22 == 0){/////没有百搭的时候
  796. // let str3a5 = "logic wbd: ";
  797. // logger.info(str3a5);////cssj
  798. // 确定将牌
  799. for (let i = 0; i < length - 1; ++i) {
  800. if (!this.isJang(handCards[i], handCards[i + 1])) continue;
  801. resetHuRes(handCards[i]);////设置将牌
  802. let cards = handCards.slice(0, i);////手牌数组的前i个元素
  803. cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  804. this._dumpFixed(cards, huRes.huCards);
  805. i += 1;/////TL++,为了减少运算
  806. let tempres22 = this.outHures(huRes,handCards,hucardTL);
  807. if(tempres22){
  808. // tempAllTai = this.allTaiShu22;/////临时总台数;
  809. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  810. // console.warn("444MMMMMMMMMMMMMMM",tempres,tempres.huCards);
  811. }
  812. }
  813. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;
  814. }
  815. else{/////有百搭的时候
  816. let card2 = []//////用于存放手牌中将所有百搭牌去掉之后的手牌
  817. for (let xx = 0; xx < this.sbyBDList.length; ++xx){
  818. card2 = handCards.slice(0,bdIndexlist[xx] - xx)////得到数组中的前bdIndexlist[xx] 个元素
  819. card2 = card2.concat(handCards.slice(bdIndexlist[xx]+1 - xx))////得到数组中的最后bdIndexlist[xx] +1 个元素
  820. handCards = card2
  821. // console.error("有百搭删除掉百搭牌",handCards,card2);
  822. }
  823. // console.warn("删除百搭之后的手牌222",handCards);
  824. let bdzs = this.sbyBDList.length;/////百搭张数
  825. let dangPaiList = this.getBDMakeList(handCards);/////百搭可当的范围数组,此做法为了剔除不必要的当法以减少运算量
  826. let aBDAllDangFa = dangPaiList.length;//////当前每张百搭牌的当法总数
  827. let dangAfterBDList = [];/////百搭牌当完之后
  828. let copyhandCards = this.deepCloneTL(handCards)
  829. var huResTL = [];
  830. for (let huCard of huCards) huResTL.push(huCard);
  831. // this.judgePAODA22(bdzs,copyhandCards,dangPaiList,huResTL.length);/////7月18日放在了这里 以前在上面,
  832. // let str3a5 = "logic ybd: " + bdzs;
  833. // logger.info(str3a5);////cssj
  834. // console.warn("删除百搭之后的可当牌222",dangPaiList);
  835. if(bdzs == 1){///////手上只有一张百搭的情况
  836. for (let n = 0; n < aBDAllDangFa; ++n) {
  837. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  838. dangAfterBDList[0] = dangPaiList[n];
  839. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  840. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  841. // if(dangAfterBDList[0] == this.sbyBDList[0]){
  842. // this.isHanDa = true;/////TL++,当前是不是还搭
  843. // }
  844. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  845. cards22 = this.sort(cards22);
  846. // if(this.currChairIDTL == 0) console.warn("111百搭当完之后的手牌222",cards22,dangAfterBDList);
  847. // 确定将牌
  848. for (let i = 0; i < cards22.length - 1; ++i) {
  849. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  850. resetHuRes(cards22[i]);////设置将牌
  851. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  852. // this.judgePAODA(1,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  853. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  854. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  855. this._dumpFixed(cards, huRes.huCards);
  856. i += 1;/////TL++,为了减少运算
  857. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  858. // this.judgePAODA(1,bcjp,dangAfterBDList);/////7月18日放在了这里 以前在上面,
  859. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  860. // if(this.currChairIDTL == 1) console.warn("111zhangMMMMMMMMMMMMMMM",tempres,huRes.huCards.length,this.allTaiShu,tempAllTai,this.allTaiShu22,tempres22);
  861. if(tempres22){
  862. // tempAllTai = this.allTaiShu22;/////临时总台数;
  863. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  864. // if(this.currChairIDTL == 1) console.warn("11MM",tempres,tempres.huCards);
  865. }
  866. }
  867. // if(this.currChairIDTL == 1) console.warn("111zhangMMMMMMMMMMMMMMM",tempres);
  868. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;
  869. }
  870. // if(this.currChairIDTL == 1) console.warn("111zhangMMMMMMMMMMMMMMM",tempres);
  871. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;
  872. }
  873. else if(bdzs == 2){///////手上只有2张百搭的情况
  874. for (let m = 0; m < aBDAllDangFa; m++) {
  875. for (let n = m; n < aBDAllDangFa; n++) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  876. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  877. dangAfterBDList[0] = dangPaiList[m];
  878. dangAfterBDList[1] = dangPaiList[n];
  879. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  880. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  881. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1]){
  882. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  883. // }
  884. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  885. cards22 = this.sort(cards22);
  886. // if(this.currChairIDTL == 0) console.warn("2222百搭当完之后的手牌222",cards22,dangAfterBDList);
  887. // 确定将牌
  888. for (let i = 0; i < cards22.length - 1; ++i) {
  889. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  890. resetHuRes(cards22[i]);////设置将牌
  891. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  892. // this.judgePAODA(2,cards22[i],dangAfterBDList,cards22);/////判断抛搭 /////7月18日以前在这里
  893. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  894. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  895. this._dumpFixed(cards, huRes.huCards);
  896. i += 1;/////TL++,为了减少运算
  897. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  898. // this.judgePAODA(2,bcjp,dangAfterBDList,cards22);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  899. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  900. if(tempres22){
  901. // tempAllTai = this.allTaiShu22;/////临时总台数;
  902. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  903. // if(this.currChairIDTL == 0) console.warn("2222zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  904. }
  905. }
  906. // if(this.currChairIDTL == 0) console.warn("222zhangMMMMMMMMMMMMMMM",tempres);
  907. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  908. }
  909. }
  910. // if(this.currChairIDTL == 0) console.warn("222zhangMMMMMMMMMMMMMMM",tempres);
  911. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面,
  912. }
  913. else if(bdzs == 3){///////手上只有3张百搭的情况
  914. for (let m = 0; m < aBDAllDangFa; ++m) {
  915. for (let p = m; p < aBDAllDangFa; ++p) {
  916. for (let n = p; n < aBDAllDangFa; ++n) {
  917. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  918. dangAfterBDList[0] = dangPaiList[m];
  919. dangAfterBDList[1] = dangPaiList[p];
  920. dangAfterBDList[2] = dangPaiList[n];
  921. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  922. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  923. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  924. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  925. // }
  926. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  927. cards22 = this.sort(cards22);
  928. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  929. // 确定将牌
  930. for (let i = 0; i < cards22.length - 1; ++i) {
  931. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  932. // jiangCount = jiangCount + 1
  933. resetHuRes(cards22[i]);////设置将牌
  934. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  935. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  936. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  937. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  938. this._dumpFixed(cards, huRes.huCards);
  939. i += 1;/////TL++,为了减少运算
  940. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  941. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  942. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  943. if(tempres22){
  944. // tempAllTai = this.allTaiShu22;/////临时总台数;
  945. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  946. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  947. }
  948. }
  949. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  950. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  951. }
  952. }
  953. }
  954. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  955. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  956. }
  957. else if(bdzs == 4){///////手上只有3张百搭的情况
  958. for (let m = 0; m < aBDAllDangFa; ++m) {
  959. for (let p = m; p < aBDAllDangFa; ++p) {
  960. for (let n = p; n < aBDAllDangFa; ++n) {
  961. for (let l = n; l < aBDAllDangFa; ++l) {
  962. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  963. dangAfterBDList[0] = dangPaiList[m];
  964. dangAfterBDList[1] = dangPaiList[p];
  965. dangAfterBDList[2] = dangPaiList[n];
  966. dangAfterBDList[3] = dangPaiList[l];
  967. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  968. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  969. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  970. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  971. // }
  972. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  973. cards22 = this.sort(cards22);
  974. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  975. // 确定将牌
  976. for (let i = 0; i < cards22.length - 1; ++i) {
  977. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  978. // jiangCount = jiangCount + 1
  979. resetHuRes(cards22[i]);////设置将牌
  980. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  981. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  982. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  983. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  984. this._dumpFixed(cards, huRes.huCards);
  985. i += 1;/////TL++,为了减少运算
  986. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  987. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  988. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  989. if(tempres22){
  990. // tempAllTai = this.allTaiShu22;/////临时总台数;
  991. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  992. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  993. }
  994. }
  995. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  996. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  997. }
  998. }
  999. }
  1000. }
  1001. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1002. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  1003. }
  1004. else if(bdzs == 5){///////手上只有3张百搭的情况
  1005. for (let m = 0; m < aBDAllDangFa; ++m) {
  1006. for (let p = m; p < aBDAllDangFa; ++p) {
  1007. for (let n = p; n < aBDAllDangFa; ++n) {
  1008. for (let l = n; l < aBDAllDangFa; ++l) {
  1009. for (let o = l; o < aBDAllDangFa; ++o) {
  1010. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1011. dangAfterBDList[0] = dangPaiList[m];
  1012. dangAfterBDList[1] = dangPaiList[p];
  1013. dangAfterBDList[2] = dangPaiList[n];
  1014. dangAfterBDList[3] = dangPaiList[l];
  1015. dangAfterBDList[4] = dangPaiList[o];
  1016. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  1017. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  1018. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  1019. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  1020. // }
  1021. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1022. cards22 = this.sort(cards22);
  1023. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  1024. // 确定将牌
  1025. for (let i = 0; i < cards22.length - 1; ++i) {
  1026. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1027. // jiangCount = jiangCount + 1
  1028. resetHuRes(cards22[i]);////设置将牌
  1029. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  1030. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  1031. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1032. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1033. this._dumpFixed(cards, huRes.huCards);
  1034. i += 1;/////TL++,为了减少运算
  1035. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  1036. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  1037. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  1038. if(tempres22){
  1039. // tempAllTai = this.allTaiShu22;/////临时总台数;
  1040. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  1041. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  1042. }
  1043. }
  1044. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1045. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1052. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  1053. }
  1054. else if(bdzs == 6){///////手上只有3张百搭的情况
  1055. for (let m = 0; m < aBDAllDangFa; ++m) {
  1056. for (let p = m; p < aBDAllDangFa; ++p) {
  1057. for (let n = p; n < aBDAllDangFa; ++n) {
  1058. for (let l = n; l < aBDAllDangFa; ++l) {
  1059. for (let o = l; o < aBDAllDangFa; ++o) {
  1060. for (let x = o; x < aBDAllDangFa; ++x) {
  1061. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1062. dangAfterBDList[0] = dangPaiList[m];
  1063. dangAfterBDList[1] = dangPaiList[p];
  1064. dangAfterBDList[2] = dangPaiList[n];
  1065. dangAfterBDList[3] = dangPaiList[l];
  1066. dangAfterBDList[4] = dangPaiList[o];
  1067. dangAfterBDList[5] = dangPaiList[x];
  1068. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  1069. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  1070. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  1071. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  1072. // }
  1073. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1074. cards22 = this.sort(cards22);
  1075. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  1076. // 确定将牌
  1077. for (let i = 0; i < cards22.length - 1; ++i) {
  1078. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1079. // jiangCount = jiangCount + 1
  1080. resetHuRes(cards22[i]);////设置将牌
  1081. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  1082. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  1083. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1084. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1085. this._dumpFixed(cards, huRes.huCards);
  1086. i += 1;/////TL++,为了减少运算
  1087. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  1088. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  1089. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  1090. if(tempres22){
  1091. // tempAllTai = this.allTaiShu22;/////临时总台数;
  1092. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  1093. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  1094. }
  1095. }
  1096. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1097. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  1098. }
  1099. }
  1100. }
  1101. }
  1102. }
  1103. }
  1104. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1105. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  1106. }
  1107. else if(bdzs == 7){///////手上只有3张百搭的情况
  1108. for (let m = 0; m < aBDAllDangFa; ++m) {
  1109. for (let p = m; p < aBDAllDangFa; ++p) {
  1110. for (let n = p; n < aBDAllDangFa; ++n) {
  1111. for (let l = n; l < aBDAllDangFa; ++l) {
  1112. for (let o = l; o < aBDAllDangFa; ++o) {
  1113. for (let x = o; x < aBDAllDangFa; ++x) {
  1114. for (let y = x; y < aBDAllDangFa; ++y) {
  1115. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1116. dangAfterBDList[0] = dangPaiList[m];
  1117. dangAfterBDList[1] = dangPaiList[p];
  1118. dangAfterBDList[2] = dangPaiList[n];
  1119. dangAfterBDList[3] = dangPaiList[l];
  1120. dangAfterBDList[4] = dangPaiList[o];
  1121. dangAfterBDList[5] = dangPaiList[x];
  1122. dangAfterBDList[6] = dangPaiList[y];
  1123. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  1124. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  1125. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  1126. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  1127. // }
  1128. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1129. cards22 = this.sort(cards22);
  1130. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  1131. // 确定将牌
  1132. for (let i = 0; i < cards22.length - 1; ++i) {
  1133. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1134. // jiangCount = jiangCount + 1
  1135. resetHuRes(cards22[i]);////设置将牌
  1136. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  1137. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  1138. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1139. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1140. this._dumpFixed(cards, huRes.huCards);
  1141. i += 1;/////TL++,为了减少运算
  1142. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  1143. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  1144. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  1145. if(tempres22){
  1146. // tempAllTai = this.allTaiShu22;/////临时总台数;
  1147. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  1148. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  1149. }
  1150. }
  1151. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1152. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. }
  1159. }
  1160. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1161. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  1162. }
  1163. else if(bdzs == 8){///////手上只有3张百搭的情况
  1164. for (let m = 0; m < aBDAllDangFa; ++m) {
  1165. for (let p = m; p < aBDAllDangFa; ++p) {
  1166. for (let n = p; n < aBDAllDangFa; ++n) {
  1167. for (let l = n; l < aBDAllDangFa; ++l) {
  1168. for (let o = l; o < aBDAllDangFa; ++o) {
  1169. for (let x = o; x < aBDAllDangFa; ++x) {
  1170. for (let y = x; y < aBDAllDangFa; ++y) {
  1171. for (let z = y; z < aBDAllDangFa; ++z) {
  1172. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1173. dangAfterBDList[0] = dangPaiList[m];
  1174. dangAfterBDList[1] = dangPaiList[p];
  1175. dangAfterBDList[2] = dangPaiList[n];
  1176. dangAfterBDList[3] = dangPaiList[l];
  1177. dangAfterBDList[4] = dangPaiList[o];
  1178. dangAfterBDList[5] = dangPaiList[x];
  1179. dangAfterBDList[6] = dangPaiList[y];
  1180. dangAfterBDList[7] = dangPaiList[z];
  1181. this.dangAfterBDListTL = dangAfterBDList;/////7月18日+的
  1182. // this.isHanDa = false;//////TL++,是否还搭(百搭牌用作原牌型,不累计)
  1183. // if(dangAfterBDList[0] == this.sbyBDList[0] && dangAfterBDList[1] == this.sbyBDList[1] && dangAfterBDList[2] == this.sbyBDList[2]){
  1184. // this.isHanDa = true;/////TL++,当前是不是抛搭,因为是抛搭的话不能打倒胡(吃胡)
  1185. // }
  1186. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1187. cards22 = this.sort(cards22);
  1188. // if(this.currChairIDTL == 0) console.warn("3333百搭当完之后的手牌222",cards22,dangAfterBDList);
  1189. // 确定将牌
  1190. for (let i = 0; i < cards22.length - 1; ++i) {
  1191. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1192. // jiangCount = jiangCount + 1
  1193. resetHuRes(cards22[i]);////设置将牌
  1194. let bcjp = cards22[i]; ///////本次的将牌 7月18日+的
  1195. // this.judgePAODA(3,cards22[i],dangAfterBDList);/////判断抛搭 /////7月18日以前在这里
  1196. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1197. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1198. this._dumpFixed(cards, huRes.huCards);
  1199. i += 1;/////TL++,为了减少运算
  1200. // if(huRes.huCards.length < 4) this.isPaoDa = false;////此当法不能组成23333的胡牌牌型 7月18日+的
  1201. // this.judgePAODA(3,bcjp,dangAfterBDList);/////判断抛搭 /////7月18日放在了这里 以前在上面,
  1202. let tempres22 = this.outHures(huRes,cards22,hucardTL);
  1203. if(tempres22){
  1204. // tempAllTai = this.allTaiShu22;/////临时总台数;
  1205. tempres = this.deepCloneTL(tempres22)//////这样写tempres =tempres22是错误的 这里需要深复制
  1206. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres,tempres.huCards);
  1207. }
  1208. }
  1209. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1210. // if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日以前在这里
  1211. }
  1212. }
  1213. }
  1214. }
  1215. }
  1216. }
  1217. }
  1218. }
  1219. // if(this.currChairIDTL == 0) console.warn("333zhangMMMMMMMMMMMMMMM",tempres);
  1220. if(tempres && tempres.huCards && tempres.huCards.length >= 4) return tempres;/////7月18日放在了这里 以前在上面
  1221. }
  1222. }
  1223. };
  1224. // // TL++胡牌提示 chairID(TL++这个参数) 手牌 手上的吃碰杠牌 这个是胡牌提示里不统计台数
  1225. proto.hutip = function (chairID,_handCards, _huCards,_allhuCards,outCards) {
  1226. return {
  1227. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1228. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1229. };////服务端运算量太大放到前端去计算了
  1230. this.yscs = 0
  1231. // console.warn("hutip777胡牌提示handCards ",chairID,_handCards,_huCards,this.yscs);
  1232. // console.error("sscc777胡牌提示huCards",_huCards);
  1233. let hutipRes = [];
  1234. let handCards1 = _.clone(_handCards);
  1235. // if(chairID == 1) console.warn("sscc777胡牌提示handCards1 ",chairID,_handCards);
  1236. let huCards = _.clone(_huCards);
  1237. let allhuCards = _.clone(_allhuCards);////用统计胡牌提示的剩余牌
  1238. let baiDaCount22 = this.getBDCount(_handCards);
  1239. let dangPaiList = this.getBDMakeList(handCards1);
  1240. if(baiDaCount22 == 4 && this.hzCount == 4){
  1241. //选择4红中规则的时候,手里有4张红中的话可以直接胡,6红中8红中不可直接胡
  1242. let kehuData2 = {
  1243. renyi:1,//////是否可胡任意牌,0表示不满足1表示满足
  1244. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1245. };
  1246. return kehuData2;
  1247. }
  1248. if(baiDaCount22 < this.hzCount && this.hzCount > 0 && _handCards.indexOf(this.baiDaCard) == -1 && this.baiDaCard < 60){
  1249. dangPaiList[dangPaiList.length] = this.baiDaCard;
  1250. }
  1251. // if(chairID == 1) console.warn("hutip777胡牌提示 dangPaiList ",dangPaiList.length,dangPaiList);
  1252. let kdcdp = 0;////可打出的牌 就是打出这个牌之后可以胡
  1253. let dczhkhdp = [];////打出kdcdp之后可以胡的牌
  1254. let yjpdgdsp = 0;////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了
  1255. // let yjpdgdzh = [];////已经判断过的组合 把28换成26 和 把26换成28 的结果是一样的所以可以剔除以减少运算
  1256. for (var i = 0; i < handCards1.length; i++) {
  1257. kdcdp = handCards1[i];////可打出的牌
  1258. dczhkhdp = [];
  1259. if(handCards1[i] == yjpdgdsp) continue;////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了
  1260. yjpdgdsp = handCards1[i];////已经判断过的手牌 为了减少运算量判断过的手牌就不再判断了
  1261. var huResTL = [];
  1262. for (let huCard of huCards) huResTL.push(huCard);
  1263. let copyhandCards = this.deepCloneTL(_handCards)
  1264. for (let x = 0; x < copyhandCards.length; ++x) {
  1265. if(this.judgeACardISBD(copyhandCards[x])){
  1266. copyhandCards[x] = 0;////剔除手里的百搭去判断抛搭
  1267. }
  1268. }
  1269. copyhandCards[i] = 0;///剔除手里的百搭和打出那张之后剩下的手牌去判断抛搭
  1270. let copyhandCardsqbd = _.compact(_.clone(copyhandCards));
  1271. let ispd = this.hutipJudgePAODA(baiDaCount22,copyhandCardsqbd,dangPaiList,huResTL.length,kdcdp);////打出kdcdp之后是否抛搭
  1272. // if(ymyknsqdhssbd != 2){////13不搭不存在抛搭
  1273. // ispd = this.hutipJudgePAODA(baiDaCount22,copyhandCardsqbd,dangPaiList,huResTL.length,kdcdp);/////20200903,
  1274. // }
  1275. dangPaiList = this.sort(dangPaiList);
  1276. // console.warn("打出kdcdp之后是否抛搭 ",kdcdp,ispd,this.yscs);
  1277. if(ispd){
  1278. ////打出kdcdp之后可以抛搭了
  1279. let data = {
  1280. "canTing": kdcdp,////表示打出这张牌之后可以听牌
  1281. "youjin": 1,////打出这张牌之后是不是游金(抛搭)这个在象山麻将里面没有用
  1282. "tpxq": dczhkhdp
  1283. }
  1284. hutipRes[hutipRes.length] = data;
  1285. }
  1286. else{
  1287. ////打出kdcdp之后不能抛搭
  1288. for (var k = 0; k < dangPaiList.length; k++) {
  1289. this.yscs++;
  1290. let handCards = _.clone(handCards1);
  1291. // console.error("222sscc777胡牌提示huCards",i,handCards[i] , dangPaiList[k],handCards);
  1292. handCards[i] = dangPaiList[k];
  1293. // yjpdgdzh[yjpdgdzh.length] = zcpdzh;////小的在前大的在后
  1294. // console.error("333sscc777胡牌提示huCards",i,handCards[i] , dangPaiList[k],handCards);
  1295. // this.hutip2(chairID,handCards, dangPaiList[k], huCards, handCards[i]);
  1296. handCards = this.sort(handCards);
  1297. // 手牌不全
  1298. var length = handCards.length;
  1299. if (length % 3 != 2) return;
  1300. // console.warn("pandau 0ceccewcde -------开始调用 hutip33");
  1301. let huRes22 = this.hutip33(chairID,handCards, dangPaiList[k], huCards,false);
  1302. if (huRes22) {
  1303. ////打出kdcdp如果摸到dangPaiList[k]可以胡
  1304. let syzs = this.getACardSYZS(dangPaiList[k],_handCards,allhuCards,outCards);
  1305. // console.warn("111????????????????????????????????",dangPaiList[k],syzs);
  1306. dczhkhdp[dczhkhdp.length] = [dangPaiList[k],-1,syzs];////[可胡的牌,剩余张数]
  1307. }
  1308. }
  1309. // console.warn("222????????????????????????????????",dczhkhdp.length);
  1310. if(dczhkhdp.length > 0){
  1311. ////至此表示打出handCards[i]之后可以听牌
  1312. let data = {
  1313. "canTing": kdcdp,////表示打出这张牌之后可以听牌
  1314. "youjin": 0,////打出这张牌之后是不是游金(抛搭)这个在象山麻将里面没有用
  1315. "tpxq": dczhkhdp
  1316. }
  1317. hutipRes[hutipRes.length] = data;
  1318. }
  1319. }
  1320. }
  1321. // console.warn("333????????????????????????????????",hutipRes);
  1322. // console.warn("222sscc777胡牌提示handCards ",chairID,_handCards,_huCards,this.yscs);
  1323. let kehuData3 = {
  1324. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1325. kehuData:hutipRes/////对象数组,分别表示打哪张可胡哪几张数据
  1326. };
  1327. return kehuData3;
  1328. // return hutipRes;
  1329. };
  1330. ////TL++得到一张牌的剩余张数 用于胡牌提示提示该张的剩余张数
  1331. proto.getACardSYZS = function (card,_handCards,allhuCards,outCards) {
  1332. ////下面这段是适合胡牌提示里用的剩余牌数统计
  1333. let yjcxdzs = 0;////该牌已经出现的张数
  1334. for (var i = 0; i < _handCards.length; i++) {
  1335. if(card == _handCards[i]) yjcxdzs++;////该牌已经出现在自己手牌里的张数
  1336. }
  1337. // console.warn("111得到一张牌的剩余张数 手牌张数",yjcxdzs,_handCards);
  1338. for (var i = 0; i < allhuCards.length; i++) {
  1339. if(allhuCards[i].length == 0) continue;////该玩家没有碰杠牌
  1340. // console.warn("222得到一张牌的剩余张数 碰杠杠牌",card,yjcxdzs,i,JSON.stringify(_.clone(allhuCards[i])));
  1341. for (var k = 0; k < allhuCards[i].length; k++) {
  1342. let pgp = allhuCards[i][k].cards;
  1343. if(!pgp) continue;
  1344. for (var j = 0; j < pgp.length; j++) {
  1345. if(card == pgp[j]) yjcxdzs++;////该牌已经出现在自己手牌里的张数
  1346. }
  1347. }
  1348. }
  1349. for (var i = 0; i < outCards.length; i++) {
  1350. if(outCards[i].length == 0) continue;////该玩家没有碰杠牌
  1351. // console.warn("2得到一张牌的剩余张数 打出去的牌",card,yjcxdzs,i,JSON.stringify(_.clone(outCards[i])));
  1352. for (var k = 0; k < outCards[i].length; k++) {
  1353. if(card == outCards[i][k]) yjcxdzs++;////该牌已经出现在所有打出去牌里的张数;
  1354. }
  1355. }
  1356. let zs = 4
  1357. if(card == 51) zs = this.hzCount;
  1358. // if(this.judgeACardISBD(card)) zs = 3;
  1359. let syzs = zs - yjcxdzs;////剩余张数 = 总张数 - 已经出现的张数
  1360. // console.warn("333得到一张牌的剩余张数",card,syzs);
  1361. return syzs;
  1362. };
  1363. //////TL++,胡牌提示判断抛搭
  1364. proto.hutipJudgePAODA = function (_baidacount,_hd,_df,_cpcount,_addThisIsHu) {
  1365. let baidacount = _baidacount
  1366. let handCards = _hd
  1367. let dangPaiList = _df
  1368. let cpcount = _cpcount
  1369. let dangAfterBDList = []
  1370. let aBDAllDangFa = dangPaiList.length;//////当前每张百搭牌的当法总数
  1371. if(baidacount == 1){
  1372. if(this._dumpFixedHutip(handCards,cpcount,_addThisIsHu)) return true;
  1373. }
  1374. else if(baidacount == 2){
  1375. for (let m = 0; m < aBDAllDangFa; m++) {
  1376. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1377. dangAfterBDList[0] = dangPaiList[m];
  1378. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1379. cards22 = this.sort(cards22);
  1380. // if(this.currChairIDTL == 1) console.warn("抛搭方法的参数******",cpcount,cards22)
  1381. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1382. }
  1383. }
  1384. else if(baidacount == 3){
  1385. for (let m = 0; m < aBDAllDangFa; ++m) {
  1386. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1387. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1388. dangAfterBDList[0] = dangPaiList[m];
  1389. dangAfterBDList[1] = dangPaiList[n];
  1390. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1391. cards22 = this.sort(cards22);
  1392. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1393. }
  1394. }
  1395. }
  1396. else if(baidacount == 4){
  1397. for (let m = 0; m < aBDAllDangFa; ++m) {
  1398. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1399. for (let o = n; o < aBDAllDangFa; ++o) {
  1400. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1401. dangAfterBDList[0] = dangPaiList[m];
  1402. dangAfterBDList[1] = dangPaiList[n];
  1403. dangAfterBDList[2] = dangPaiList[o];
  1404. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1405. cards22 = this.sort(cards22);
  1406. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1407. }
  1408. }
  1409. }
  1410. }
  1411. else if(baidacount == 5){
  1412. for (let m = 0; m < aBDAllDangFa; ++m) {
  1413. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1414. for (let o = n; o < aBDAllDangFa; ++o) {
  1415. for (let l = o; l < aBDAllDangFa; ++l) {
  1416. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1417. dangAfterBDList[0] = dangPaiList[m];
  1418. dangAfterBDList[1] = dangPaiList[n];
  1419. dangAfterBDList[2] = dangPaiList[o];
  1420. dangAfterBDList[3] = dangPaiList[l];
  1421. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1422. cards22 = this.sort(cards22);
  1423. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1424. }
  1425. }
  1426. }
  1427. }
  1428. }
  1429. else if(baidacount == 6){
  1430. for (let m = 0; m < aBDAllDangFa; ++m) {
  1431. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1432. for (let o = n; o < aBDAllDangFa; ++o) {
  1433. for (let l = o; l < aBDAllDangFa; ++l) {
  1434. for (let x = l; x < aBDAllDangFa; ++x) {
  1435. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1436. dangAfterBDList[0] = dangPaiList[m];
  1437. dangAfterBDList[1] = dangPaiList[n];
  1438. dangAfterBDList[2] = dangPaiList[o];
  1439. dangAfterBDList[3] = dangPaiList[l];
  1440. dangAfterBDList[4] = dangPaiList[x];
  1441. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1442. cards22 = this.sort(cards22);
  1443. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1444. }
  1445. }
  1446. }
  1447. }
  1448. }
  1449. }
  1450. else if(baidacount == 7){
  1451. for (let m = 0; m < aBDAllDangFa; ++m) {
  1452. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1453. for (let o = n; o < aBDAllDangFa; ++o) {
  1454. for (let l = o; l < aBDAllDangFa; ++l) {
  1455. for (let x = l; x < aBDAllDangFa; ++x) {
  1456. for (let y = x; y < aBDAllDangFa; ++y) {
  1457. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1458. dangAfterBDList[0] = dangPaiList[m];
  1459. dangAfterBDList[1] = dangPaiList[n];
  1460. dangAfterBDList[2] = dangPaiList[o];
  1461. dangAfterBDList[3] = dangPaiList[l];
  1462. dangAfterBDList[4] = dangPaiList[x];
  1463. dangAfterBDList[5] = dangPaiList[y];
  1464. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1465. cards22 = this.sort(cards22);
  1466. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1467. }
  1468. }
  1469. }
  1470. }
  1471. }
  1472. }
  1473. }
  1474. else if(baidacount == 7){
  1475. for (let m = 0; m < aBDAllDangFa; ++m) {
  1476. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1477. for (let o = n; o < aBDAllDangFa; ++o) {
  1478. for (let l = o; l < aBDAllDangFa; ++l) {
  1479. for (let x = l; x < aBDAllDangFa; ++x) {
  1480. for (let y = x; y < aBDAllDangFa; ++y) {
  1481. for (let z = y; z < aBDAllDangFa; ++z) {
  1482. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1483. dangAfterBDList[0] = dangPaiList[m];
  1484. dangAfterBDList[1] = dangPaiList[n];
  1485. dangAfterBDList[2] = dangPaiList[o];
  1486. dangAfterBDList[3] = dangPaiList[l];
  1487. dangAfterBDList[4] = dangPaiList[x];
  1488. dangAfterBDList[5] = dangPaiList[y];
  1489. dangAfterBDList[6] = dangPaiList[z];
  1490. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1491. cards22 = this.sort(cards22);
  1492. if(this._dumpFixedHutip(cards22,cpcount,_addThisIsHu)) return true;
  1493. }
  1494. }
  1495. }
  1496. }
  1497. }
  1498. }
  1499. }
  1500. }
  1501. return false;
  1502. }
  1503. // 胡牌提示提取成句 card:手上的所有牌删除2张用来做将的牌之后剩下的牌 整理是否为刻子或者顺子
  1504. proto._dumpFixedHutip = function (_cards, huCards,_addThisIsHu) {
  1505. // if(this.currChairIDTL == 0){
  1506. // console.error("sscc 胡牌提示提取成句 没有百搭cards",_cards,_addThisIsHu);
  1507. // console.error("sscc提取成ju没有百搭huCards",huCards);
  1508. // }
  1509. let cards = _cards;
  1510. // console.warn("胡牌提示提取成句 ",cards.length,cards);
  1511. let count = huCards
  1512. for (let i = 0; i < cards.length - 2; ++i) {
  1513. let card = cards[i];
  1514. if(card <= 0) continue;
  1515. if (card == cards[i + 1] && card == cards[i + 2]) {
  1516. count += 1;
  1517. cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0;
  1518. i += 2; continue;
  1519. }
  1520. if (card > 40 || this.getValue(card) > 7) continue;
  1521. let second = -1, third = -1;
  1522. for (let j = i + 1; j < cards.length; ++j) {
  1523. if (cards[j] == card + 1) second = j;
  1524. if (cards[j] == card + 2) third = j;
  1525. if (cards[j] > card + 2) break;
  1526. if (second != -1 && third != -1) break;
  1527. }
  1528. if (second != -1 && third != -1) {
  1529. count += 1;
  1530. cards[i] = 0; cards[second] = 0; cards[third] = 0;
  1531. }
  1532. }
  1533. // if(this.currChairIDTL == 0) console.warn("胡牌提示提取成句 买买买",count,count >= 4);
  1534. return count >= 4
  1535. };
  1536. ////下面这个胡牌算法由于运算量太大准备弃用,碰到了需要判断52.59w副不同的14张手牌是否能胡
  1537. // 胡牌提示里调用 手牌 加上这张判断能不能胡 手上的吃碰杠牌 返回参数手牌是否可胡(true或者false)
  1538. proto.hutip22 = function (chairID,handCards, _card, huCards,_ymyknsqdhssbd) {
  1539. // console.error("sscc777胡牌提示card",_card);
  1540. // console.error("sscc777胡牌提示handCards",handCards);
  1541. // console.error("sscc777胡牌提示huCards",huCards);
  1542. // this.dangAfterBDListTL = [];/////7月18日+的
  1543. let baiDaCount22 = 0
  1544. let bdIndexlist = []
  1545. handCards = this.sort(handCards);
  1546. baiDaCount22 = this.getBDCount(handCards)
  1547. let sbyBDList = this.getBDListZZ(handCards)
  1548. bdIndexlist = this.getBDIndexList(handCards)
  1549. var huRes = { card: _card, jiang: 0, huCards: [] };
  1550. // 重设将牌
  1551. var resetHuRes = (jiang) => {
  1552. huRes.jiang = jiang;
  1553. huRes.huCards = [];
  1554. for (let huCard of huCards) huRes.huCards.push(huCard);
  1555. };
  1556. // 手牌不全
  1557. var length = handCards.length;
  1558. if (length % 3 != 2) return;
  1559. let hucardTL = huCards//////TL++,保存碰杠牌的初始值,因为这个参数会在下面的代码中被修改掉
  1560. //////TL++,判断是否全是字牌,因为如果全是字牌是可以胡牌的
  1561. let sspgpbb = this.deepCloneTL(huRes)/////手上的碰杠牌
  1562. for (let huCard of huCards) sspgpbb.huCards.push(huCard)/////手上的碰杠牌
  1563. // let isallziP = this.isAllZiPai(chairID,handCards,sspgpbb.huCards); /////TL++,这里之所以不return是因为为了判断是否是清老头
  1564. // let is8HuaP = this.everyFllowerCardList[chairID].length == 8
  1565. if(handCards.length > Logic.CARDS_COUNT){
  1566. // console.warn("111费时间 ");
  1567. ////14张手牌的话采用判断是否是七对和13不搭的必要
  1568. // 是否七对
  1569. let isqd = false;
  1570. var dcount = 0;
  1571. var counts = {};
  1572. for (let i = 0; i < handCards.length; ++i) {
  1573. let card = handCards[i];
  1574. if(this.judgeACardISBD(card)) continue;/////百搭牌不做基础牌进行判断
  1575. counts[card] = (counts[card] || 0) + 1;
  1576. if (counts[card] >= 2) {
  1577. dcount += 1;
  1578. counts[card] = 0;
  1579. }
  1580. }
  1581. if(dcount + baiDaCount22 >= 7 && dcount >= 4) isqd = true;
  1582. if(isqd) return true;
  1583. // console.warn("222费时间 ");
  1584. //// TL++是否13不搭
  1585. if(_ymyknsqdhssbd){
  1586. let isssbd = true;
  1587. for (let n = 0; n < handCards.length - 1; ++n) {
  1588. let card = handCards[n];
  1589. let nnn = n + 1;
  1590. if(this.judgeACardISBD(card)) continue;
  1591. if(this.judgeACardISBD(handCards[nnn])) nnn++;
  1592. if(this.judgeACardISBD(handCards[nnn])) nnn++;
  1593. if(this.judgeACardISBD(handCards[nnn])) nnn++;
  1594. if(card == handCards[nnn] && card != 0 ) isssbd = false;//////有将牌(0除外)直接返回false(undifine)
  1595. /////同花色的两张牌差值小于3直接返回false(undifine)
  1596. if(card < 40 && card > handCards[nnn] -3 && this.getType(card) == this.getType(handCards[nnn])) isssbd = false ;
  1597. if(card > 60 && !this.judgeACardISBD(card)) isssbd = false;/////补花牌不算
  1598. if(!isssbd) break;
  1599. }
  1600. if(isssbd) return true;
  1601. return false;///前面已经判断过有可能是13不搭了
  1602. }
  1603. }
  1604. let yscs2 = 0
  1605. // console.warn("333费时间 this.yscs yscs2",this.yscs,yscs2);
  1606. // let str3a3 = "logic xmpdptpx: " + baiDaCount22;
  1607. // logger.info(str3a3);////cssj
  1608. // console.warn("判断胡--------isTouch baiDaCount22",isTouch ,baiDaCount22,this.addThisIsHu);
  1609. // if(chairID == 0) console.warn("xxxxxxxxxxxxxxxxxxxxxxxxx能走到这里说明不是7对和百搭的手牌",handCards);
  1610. // if(chairID == 0) console.warn("ccccccccccccc手牌百搭牌index",bdIndexlist);
  1611. if(baiDaCount22 == 0){/////没有百搭的时候
  1612. // 确定将牌
  1613. for (let i = 0; i < length - 1; ++i) {
  1614. if (!this.isJang(handCards[i], handCards[i + 1])) continue;
  1615. resetHuRes(handCards[i]);////设置将牌
  1616. let cards = handCards.slice(0, i);////手牌数组的前i个元素
  1617. cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1618. this._dumpFixed(cards, huRes.huCards);
  1619. i += 1;/////TL++,为了减少运算
  1620. if(huRes.huCards.length >= 4) return true;
  1621. }
  1622. }
  1623. else{/////有百搭的时候
  1624. let card2 = []//////用于存放手牌中将所有百搭牌去掉之后的手牌
  1625. for (let xx = 0; xx < sbyBDList.length; ++xx){
  1626. card2 = handCards.slice(0,bdIndexlist[xx] - xx)////得到数组中的前bdIndexlist[xx] 个元素
  1627. card2 = card2.concat(handCards.slice(bdIndexlist[xx]+1 - xx))////得到数组中的最后bdIndexlist[xx] +1 个元素
  1628. handCards = card2
  1629. // console.error("有百搭删除掉百搭牌",handCards,card2);
  1630. }
  1631. // console.warn("删除百搭之后的手牌222",handCards);
  1632. let bdzs = sbyBDList.length;/////百搭张数
  1633. let dangPaiList = this.getBDMakeList(handCards);/////百搭可当的范围数组,此做法为了剔除不必要的当法以减少运算量
  1634. let aBDAllDangFa = dangPaiList.length;//////当前每张百搭牌的当法总数
  1635. let dangAfterBDList = [];/////百搭牌当完之后
  1636. // console.warn("删除百搭之后的可当牌222",dangPaiList);
  1637. if(bdzs == 1){///////手上只有一张百搭的情况
  1638. for (let n = 0; n < aBDAllDangFa; ++n) {
  1639. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1640. dangAfterBDList[0] = dangPaiList[n];
  1641. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1642. cards22 = this.sort(cards22);
  1643. // 确定将牌
  1644. for (let i = 0; i < cards22.length - 1; ++i) {
  1645. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1646. resetHuRes(cards22[i]);////设置将牌
  1647. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1648. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1649. this._dumpFixed(cards, huRes.huCards);
  1650. i += 1;/////TL++,为了减少运算
  1651. if(huRes.huCards.length >= 4) return true
  1652. }
  1653. }
  1654. }
  1655. else if(bdzs == 2){///////手上只有2张百搭的情况
  1656. for (let m = 0; m < aBDAllDangFa; m++) {
  1657. for (let n = m; n < aBDAllDangFa; n++) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1658. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1659. dangAfterBDList[0] = dangPaiList[m];
  1660. dangAfterBDList[1] = dangPaiList[n];
  1661. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1662. cards22 = this.sort(cards22);
  1663. // 确定将牌
  1664. for (let i = 0; i < cards22.length - 1; ++i) {
  1665. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1666. resetHuRes(cards22[i]);////设置将牌
  1667. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1668. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1669. this._dumpFixed(cards, huRes.huCards);
  1670. i += 1;/////TL++,为了减少运算
  1671. if(huRes.huCards.length >= 4) return true
  1672. }
  1673. }
  1674. }
  1675. }
  1676. else if(bdzs == 3){///////手上只有3张百搭的情况
  1677. for (let m = 0; m < aBDAllDangFa; ++m) {
  1678. for (let p = m; p < aBDAllDangFa; ++p) {
  1679. for (let n = p; n < aBDAllDangFa; ++n) {
  1680. this.yscs++;
  1681. yscs2++;
  1682. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1683. dangAfterBDList[0] = dangPaiList[m];
  1684. dangAfterBDList[1] = dangPaiList[p];
  1685. dangAfterBDList[2] = dangPaiList[n];
  1686. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1687. cards22 = this.sort(cards22);
  1688. // 确定将牌
  1689. for (let i = 0; i < cards22.length - 1; ++i) {
  1690. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1691. resetHuRes(cards22[i]);////设置将牌
  1692. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1693. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1694. this._dumpFixed(cards, huRes.huCards);
  1695. i += 1;/////TL++,为了减少运算
  1696. if(huRes.huCards.length >= 4) return true
  1697. }
  1698. }
  1699. }
  1700. }
  1701. }
  1702. else if(bdzs == 4){///////手上只有3张百搭的情况
  1703. for (let m = 0; m < aBDAllDangFa; ++m) {
  1704. for (let p = m; p < aBDAllDangFa; ++p) {
  1705. for (let n = p; n < aBDAllDangFa; ++n) {
  1706. for (let l = n; l < aBDAllDangFa; ++l) {
  1707. this.yscs++;
  1708. yscs2++;
  1709. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1710. dangAfterBDList[0] = dangPaiList[m];
  1711. dangAfterBDList[1] = dangPaiList[p];
  1712. dangAfterBDList[2] = dangPaiList[n];
  1713. dangAfterBDList[3] = dangPaiList[l];
  1714. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1715. cards22 = this.sort(cards22);
  1716. // 确定将牌
  1717. for (let i = 0; i < cards22.length - 1; ++i) {
  1718. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1719. resetHuRes(cards22[i]);////设置将牌
  1720. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1721. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1722. this._dumpFixed(cards, huRes.huCards);
  1723. i += 1;/////TL++,为了减少运算
  1724. if(huRes.huCards.length >= 4) return true
  1725. }
  1726. }
  1727. }
  1728. }
  1729. }
  1730. }
  1731. else if(bdzs == 5){///////手上只有3张百搭的情况
  1732. for (let m = 0; m < aBDAllDangFa; ++m) {
  1733. for (let p = m; p < aBDAllDangFa; ++p) {
  1734. for (let n = p; n < aBDAllDangFa; ++n) {
  1735. for (let l = n; l < aBDAllDangFa; ++l) {
  1736. for (let o = l; o < aBDAllDangFa; ++o) {
  1737. this.yscs++;
  1738. yscs2++;
  1739. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1740. dangAfterBDList[0] = dangPaiList[m];
  1741. dangAfterBDList[1] = dangPaiList[p];
  1742. dangAfterBDList[2] = dangPaiList[n];
  1743. dangAfterBDList[3] = dangPaiList[l];
  1744. dangAfterBDList[4] = dangPaiList[o];
  1745. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1746. cards22 = this.sort(cards22);
  1747. // 确定将牌
  1748. for (let i = 0; i < cards22.length - 1; ++i) {
  1749. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1750. resetHuRes(cards22[i]);////设置将牌
  1751. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1752. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1753. this._dumpFixed(cards, huRes.huCards);
  1754. i += 1;/////TL++,为了减少运算
  1755. if(huRes.huCards.length >= 4) return true
  1756. }
  1757. }
  1758. }
  1759. }
  1760. }
  1761. }
  1762. }
  1763. else if(bdzs == 6){///////手上只有3张百搭的情况
  1764. for (let m = 0; m < aBDAllDangFa; ++m) {
  1765. for (let p = m; p < aBDAllDangFa; ++p) {
  1766. for (let n = p; n < aBDAllDangFa; ++n) {
  1767. for (let l = n; l < aBDAllDangFa; ++l) {
  1768. for (let o = l; o < aBDAllDangFa; ++o) {
  1769. for (let x = o; x < aBDAllDangFa; ++x) {
  1770. this.yscs++;
  1771. yscs2++;
  1772. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1773. dangAfterBDList[0] = dangPaiList[m];
  1774. dangAfterBDList[1] = dangPaiList[p];
  1775. dangAfterBDList[2] = dangPaiList[n];
  1776. dangAfterBDList[3] = dangPaiList[l];
  1777. dangAfterBDList[4] = dangPaiList[o];
  1778. dangAfterBDList[5] = dangPaiList[x];
  1779. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1780. cards22 = this.sort(cards22);
  1781. // 确定将牌
  1782. for (let i = 0; i < cards22.length - 1; ++i) {
  1783. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1784. resetHuRes(cards22[i]);////设置将牌
  1785. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1786. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1787. this._dumpFixed(cards, huRes.huCards);
  1788. i += 1;/////TL++,为了减少运算
  1789. if(huRes.huCards.length >= 4) return true
  1790. }
  1791. }
  1792. }
  1793. }
  1794. }
  1795. }
  1796. }
  1797. }
  1798. else if(bdzs == 7){///////手上只有3张百搭的情况
  1799. for (let m = 0; m < aBDAllDangFa; ++m) {
  1800. for (let p = m; p < aBDAllDangFa; ++p) {
  1801. for (let n = p; n < aBDAllDangFa; ++n) {
  1802. for (let l = n; l < aBDAllDangFa; ++l) {
  1803. for (let o = l; o < aBDAllDangFa; ++o) {
  1804. for (let x = o; x < aBDAllDangFa; ++x) {
  1805. for (let y = x; y < aBDAllDangFa; ++y) {
  1806. this.yscs++;
  1807. yscs2++;
  1808. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1809. dangAfterBDList[0] = dangPaiList[m];
  1810. dangAfterBDList[1] = dangPaiList[p];
  1811. dangAfterBDList[2] = dangPaiList[n];
  1812. dangAfterBDList[3] = dangPaiList[l];
  1813. dangAfterBDList[4] = dangPaiList[o];
  1814. dangAfterBDList[5] = dangPaiList[x];
  1815. dangAfterBDList[6] = dangPaiList[y];
  1816. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1817. cards22 = this.sort(cards22);
  1818. // 确定将牌
  1819. for (let i = 0; i < cards22.length - 1; ++i) {
  1820. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1821. resetHuRes(cards22[i]);////设置将牌
  1822. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1823. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1824. this._dumpFixed(cards, huRes.huCards);
  1825. i += 1;/////TL++,为了减少运算
  1826. if(huRes.huCards.length >= 4) return true
  1827. }
  1828. }
  1829. }
  1830. }
  1831. }
  1832. }
  1833. }
  1834. }
  1835. }
  1836. else if(bdzs == 8){///////手上只有3张百搭的情况
  1837. for (let m = 0; m < aBDAllDangFa; ++m) {
  1838. for (let p = m; p < aBDAllDangFa; ++p) {
  1839. for (let n = p; n < aBDAllDangFa; ++n) {
  1840. for (let l = n; l < aBDAllDangFa; ++l) {
  1841. for (let o = l; o < aBDAllDangFa; ++o) {
  1842. for (let x = o; x < aBDAllDangFa; ++x) {
  1843. for (let y = x; y < aBDAllDangFa; ++y) {
  1844. for (let z = y; z < aBDAllDangFa; ++z) {
  1845. this.yscs++;
  1846. yscs2++;
  1847. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1848. dangAfterBDList[0] = dangPaiList[m];
  1849. dangAfterBDList[1] = dangPaiList[p];
  1850. dangAfterBDList[2] = dangPaiList[n];
  1851. dangAfterBDList[3] = dangPaiList[l];
  1852. dangAfterBDList[4] = dangPaiList[o];
  1853. dangAfterBDList[5] = dangPaiList[x];
  1854. dangAfterBDList[6] = dangPaiList[y];
  1855. dangAfterBDList[7] = dangPaiList[z];
  1856. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1857. cards22 = this.sort(cards22);
  1858. // 确定将牌
  1859. for (let i = 0; i < cards22.length - 1; ++i) {
  1860. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1861. resetHuRes(cards22[i]);////设置将牌
  1862. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1863. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1864. this._dumpFixed(cards, huRes.huCards);
  1865. i += 1;/////TL++,为了减少运算
  1866. if(huRes.huCards.length >= 4) return true
  1867. }
  1868. }
  1869. }
  1870. }
  1871. }
  1872. }
  1873. }
  1874. }
  1875. }
  1876. }
  1877. }
  1878. // console.warn("444费时间 this.yscs yscs2",this.yscs,yscs2);
  1879. // console.warn("xxxxxx4444ccc",this.currChairIDTL,tempres,isallziP , is8HuaP);
  1880. if(isallziP || is8HuaP) {
  1881. return true;
  1882. }
  1883. // console.warn("胡牌提示 打这个胡不了",handCards, _card);
  1884. return false;
  1885. };
  1886. // 胡牌提示里调用 手牌 加上这张判断能不能胡 手上的吃碰杠牌 返回参数手牌是否可胡(true或者false)
  1887. proto.hutip33 = function (chairID,handCards, _card, huCards,_ymyknsqdhssbd) {
  1888. // console.error("sscc777胡牌提示card",_card);
  1889. // console.error("sscc777胡牌提示handCards",handCards);
  1890. // console.error("sscc777胡牌提示huCards",huCards);
  1891. // this.dangAfterBDListTL = [];/////7月18日+的
  1892. let baiDaCount22 = 0
  1893. let bdIndexlist = []
  1894. handCards = this.sort(handCards);
  1895. baiDaCount22 = this.getBDCount(handCards)
  1896. let sbyBDList = this.getBDListZZ(handCards)
  1897. bdIndexlist = this.getBDIndexList(handCards)
  1898. // console.warn("oooooooo bdIndexlist",bdIndexlist,handCards);
  1899. var huRes = { card: _card, jiang: 0, huCards: [] };
  1900. // 重设将牌
  1901. var resetHuRes = (jiang) => {
  1902. huRes.jiang = jiang;
  1903. huRes.huCards = [];
  1904. for (let huCard of huCards) huRes.huCards.push(huCard);
  1905. };
  1906. // 手牌不全
  1907. var length = handCards.length;
  1908. if (length % 3 != 2) return;
  1909. let hucardTL = huCards//////TL++,保存碰杠牌的初始值,因为这个参数会在下面的代码中被修改掉
  1910. //////TL++,判断是否全是字牌,因为如果全是字牌是可以胡牌的
  1911. let sspgpbb = this.deepCloneTL(huRes)/////手上的碰杠牌
  1912. for (let huCard of huCards) sspgpbb.huCards.push(huCard)/////手上的碰杠牌
  1913. let yscs2 = 0
  1914. // console.warn("333费时间 this.yscs yscs2",this.yscs,yscs2);
  1915. if(baiDaCount22 == 0){/////没有百搭的时候
  1916. // 确定将牌
  1917. for (let i = 0; i < length - 1; ++i) {
  1918. if (!this.isJang(handCards[i], handCards[i + 1])) continue;
  1919. resetHuRes(handCards[i]);////设置将牌
  1920. let cards = handCards.slice(0, i);////手牌数组的前i个元素
  1921. cards = cards.concat(handCards.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1922. this._dumpFixed(cards, huRes.huCards);
  1923. i += 1;/////TL++,为了减少运算
  1924. if(huRes.huCards.length >= 4) return true;
  1925. }
  1926. }
  1927. else{/////有百搭的时候
  1928. let card2 = []//////用于存放手牌中将所有百搭牌去掉之后的手牌
  1929. for (let xx = 0; xx < sbyBDList.length; ++xx){
  1930. card2 = handCards.slice(0,bdIndexlist[xx] - xx)////得到数组中的前bdIndexlist[xx] 个元素
  1931. card2 = card2.concat(handCards.slice(bdIndexlist[xx]+1 - xx))////得到数组中的最后bdIndexlist[xx] +1 个元素
  1932. handCards = card2
  1933. // console.error("有百搭删除掉百搭牌",handCards,card2);
  1934. }
  1935. let bdzs = sbyBDList.length;/////百搭张数
  1936. let dangPaiList = this.getBDMakeList(handCards);/////百搭可当的范围数组,此做法为了剔除不必要的当法以减少运算量
  1937. let aBDAllDangFa = dangPaiList.length;//////当前每张百搭牌的当法总数
  1938. let dangAfterBDList = [];/////百搭牌当完之后
  1939. // console.warn("删除百搭之后的可当牌222",dangPaiList);
  1940. if(bdzs == 1){///////手上只有一张百搭的情况
  1941. for (let n = 0; n < aBDAllDangFa; ++n) {
  1942. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1943. dangAfterBDList[0] = dangPaiList[n];
  1944. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1945. cards22 = this.sort(cards22);
  1946. // 确定将牌
  1947. for (let i = 0; i < cards22.length - 1; ++i) {
  1948. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1949. resetHuRes(cards22[i]);////设置将牌
  1950. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1951. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1952. this._dumpFixed(cards, huRes.huCards);
  1953. i += 1;/////TL++,为了减少运算
  1954. if(huRes.huCards.length >= 4) return true
  1955. }
  1956. }
  1957. }
  1958. // else{///////手上有多于2张百搭的情况
  1959. // console.warn("222ppppp",baiDaCount22,handCards)
  1960. // ////能走到这里已经就不可能是13不搭和七对了
  1961. // this.duobaidaHutip(baiDaCount22,handCards,huRes);
  1962. // }
  1963. if(bdzs == 2){///////手上只有一张百搭的情况
  1964. for (let m = 0; m < aBDAllDangFa; ++m) {
  1965. for (let n = m; n < aBDAllDangFa; ++n) {////////这是一个组合的问题而不是排列,所以让n=m要比n=0可以减少一半的运算量
  1966. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1967. dangAfterBDList[0] = dangPaiList[m];
  1968. dangAfterBDList[1] = dangPaiList[n];
  1969. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1970. cards22 = this.sort(cards22);
  1971. // 确定将牌
  1972. for (let i = 0; i < cards22.length - 1; ++i) {
  1973. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1974. resetHuRes(cards22[i]);////设置将牌
  1975. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1976. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  1977. this._dumpFixed(cards, huRes.huCards);
  1978. i += 1;/////TL++,为了减少运算
  1979. if(huRes.huCards.length >= 4) return true
  1980. }
  1981. }
  1982. }
  1983. }
  1984. if(bdzs == 3){///////手上只有一张百搭的情况
  1985. for (let m = 0; m < aBDAllDangFa; ++m) {
  1986. for (let p = m; p < aBDAllDangFa; ++p) {
  1987. for (let n = p; n < aBDAllDangFa; ++n) {
  1988. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  1989. dangAfterBDList[0] = dangPaiList[m];
  1990. dangAfterBDList[1] = dangPaiList[p];
  1991. dangAfterBDList[2] = dangPaiList[n];
  1992. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  1993. cards22 = this.sort(cards22);
  1994. // 确定将牌
  1995. for (let i = 0; i < cards22.length - 1; ++i) {
  1996. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  1997. resetHuRes(cards22[i]);////设置将牌
  1998. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  1999. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2000. this._dumpFixed(cards, huRes.huCards);
  2001. i += 1;/////TL++,为了减少运算
  2002. if(huRes.huCards.length >= 4) return true
  2003. }
  2004. }
  2005. }
  2006. }
  2007. }
  2008. if(bdzs == 4){///////手上只有一张百搭的情况
  2009. for (let m = 0; m < aBDAllDangFa; ++m) {
  2010. for (let p = m; p < aBDAllDangFa; ++p) {
  2011. for (let n = p; n < aBDAllDangFa; ++n) {
  2012. for (let k = n; k < aBDAllDangFa; ++k) {
  2013. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  2014. dangAfterBDList[0] = dangPaiList[m];
  2015. dangAfterBDList[1] = dangPaiList[p];
  2016. dangAfterBDList[2] = dangPaiList[n];
  2017. dangAfterBDList[3] = dangPaiList[k];
  2018. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  2019. cards22 = this.sort(cards22);
  2020. // 确定将牌
  2021. for (let i = 0; i < cards22.length - 1; ++i) {
  2022. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2023. resetHuRes(cards22[i]);////设置将牌
  2024. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2025. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2026. this._dumpFixed(cards, huRes.huCards);
  2027. i += 1;/////TL++,为了减少运算
  2028. if(huRes.huCards.length >= 4) return true
  2029. }
  2030. }
  2031. }
  2032. }
  2033. }
  2034. }
  2035. if(bdzs == 5){///////手上只有一张百搭的情况
  2036. for (let m = 0; m < aBDAllDangFa; ++m) {
  2037. for (let p = m; p < aBDAllDangFa; ++p) {
  2038. for (let n = p; n < aBDAllDangFa; ++n) {
  2039. for (let k = n; k < aBDAllDangFa; ++k) {
  2040. for (let l = k; l < aBDAllDangFa; ++l) {
  2041. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  2042. dangAfterBDList[0] = dangPaiList[m];
  2043. dangAfterBDList[1] = dangPaiList[p];
  2044. dangAfterBDList[2] = dangPaiList[n];
  2045. dangAfterBDList[3] = dangPaiList[k];
  2046. dangAfterBDList[4] = dangPaiList[l];
  2047. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  2048. cards22 = this.sort(cards22);
  2049. // 确定将牌
  2050. for (let i = 0; i < cards22.length - 1; ++i) {
  2051. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2052. resetHuRes(cards22[i]);////设置将牌
  2053. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2054. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2055. this._dumpFixed(cards, huRes.huCards);
  2056. i += 1;/////TL++,为了减少运算
  2057. if(huRes.huCards.length >= 4) return true
  2058. }
  2059. }
  2060. }
  2061. }
  2062. }
  2063. }
  2064. }
  2065. if(bdzs == 6){///////手上只有一张百搭的情况
  2066. for (let m = 0; m < aBDAllDangFa; ++m) {
  2067. for (let p = m; p < aBDAllDangFa; ++p) {
  2068. for (let n = p; n < aBDAllDangFa; ++n) {
  2069. for (let k = n; k < aBDAllDangFa; ++k) {
  2070. for (let l = k; l < aBDAllDangFa; ++l) {
  2071. for (let x = l; x < aBDAllDangFa; ++x) {
  2072. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  2073. dangAfterBDList[0] = dangPaiList[m];
  2074. dangAfterBDList[1] = dangPaiList[p];
  2075. dangAfterBDList[2] = dangPaiList[n];
  2076. dangAfterBDList[3] = dangPaiList[k];
  2077. dangAfterBDList[4] = dangPaiList[l];
  2078. dangAfterBDList[5] = dangPaiList[x];
  2079. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  2080. cards22 = this.sort(cards22);
  2081. // 确定将牌
  2082. for (let i = 0; i < cards22.length - 1; ++i) {
  2083. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2084. resetHuRes(cards22[i]);////设置将牌
  2085. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2086. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2087. this._dumpFixed(cards, huRes.huCards);
  2088. i += 1;/////TL++,为了减少运算
  2089. if(huRes.huCards.length >= 4) return true
  2090. }
  2091. }
  2092. }
  2093. }
  2094. }
  2095. }
  2096. }
  2097. }
  2098. if(bdzs == 7){///////手上只有一张百搭的情况
  2099. for (let m = 0; m < aBDAllDangFa; ++m) {
  2100. for (let p = m; p < aBDAllDangFa; ++p) {
  2101. for (let n = p; n < aBDAllDangFa; ++n) {
  2102. for (let k = n; k < aBDAllDangFa; ++k) {
  2103. for (let l = k; l < aBDAllDangFa; ++l) {
  2104. for (let x = l; x < aBDAllDangFa; ++x) {
  2105. for (let y = x; y < aBDAllDangFa; ++y) {
  2106. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  2107. dangAfterBDList[0] = dangPaiList[m];
  2108. dangAfterBDList[1] = dangPaiList[p];
  2109. dangAfterBDList[2] = dangPaiList[n];
  2110. dangAfterBDList[3] = dangPaiList[k];
  2111. dangAfterBDList[4] = dangPaiList[l];
  2112. dangAfterBDList[5] = dangPaiList[x];
  2113. dangAfterBDList[6] = dangPaiList[y];
  2114. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  2115. cards22 = this.sort(cards22);
  2116. // 确定将牌
  2117. for (let i = 0; i < cards22.length - 1; ++i) {
  2118. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2119. resetHuRes(cards22[i]);////设置将牌
  2120. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2121. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2122. this._dumpFixed(cards, huRes.huCards);
  2123. i += 1;/////TL++,为了减少运算
  2124. if(huRes.huCards.length >= 4) return true
  2125. }
  2126. }
  2127. }
  2128. }
  2129. }
  2130. }
  2131. }
  2132. }
  2133. }
  2134. if(bdzs == 8){///////手上只有一张百搭的情况
  2135. for (let m = 0; m < aBDAllDangFa; ++m) {
  2136. for (let p = m; p < aBDAllDangFa; ++p) {
  2137. for (let n = p; n < aBDAllDangFa; ++n) {
  2138. for (let k = n; k < aBDAllDangFa; ++k) {
  2139. for (let l = k; l < aBDAllDangFa; ++l) {
  2140. for (let x = l; x < aBDAllDangFa; ++x) {
  2141. for (let y = x; y < aBDAllDangFa; ++y) {
  2142. for (let z = y; z < aBDAllDangFa; ++z) {
  2143. //////刚开始给百搭牌当后数组赋初始值,全当可当数组的第一个元素,好处是可以确定当后的数组长度
  2144. dangAfterBDList[0] = dangPaiList[m];
  2145. dangAfterBDList[1] = dangPaiList[p];
  2146. dangAfterBDList[2] = dangPaiList[n];
  2147. dangAfterBDList[3] = dangPaiList[k];
  2148. dangAfterBDList[4] = dangPaiList[l];
  2149. dangAfterBDList[5] = dangPaiList[x];
  2150. dangAfterBDList[6] = dangPaiList[y];
  2151. dangAfterBDList[7] = dangPaiList[z];
  2152. let cards22 = handCards.concat(dangAfterBDList)/////百搭牌当完之后的手牌数组
  2153. cards22 = this.sort(cards22);
  2154. // 确定将牌
  2155. for (let i = 0; i < cards22.length - 1; ++i) {
  2156. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2157. resetHuRes(cards22[i]);////设置将牌
  2158. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2159. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2160. this._dumpFixed(cards, huRes.huCards);
  2161. i += 1;/////TL++,为了减少运算
  2162. if(huRes.huCards.length >= 4) return true
  2163. }
  2164. }
  2165. }
  2166. }
  2167. }
  2168. }
  2169. }
  2170. }
  2171. }
  2172. }
  2173. }
  2174. // console.warn("444费时间 this.yscs yscs2",this.yscs,yscs2);
  2175. // console.warn("xxxxxx4444ccc",this.currChairIDTL,tempres,isallziP , is8HuaP);
  2176. // console.warn("胡牌提示 打这个胡不了",handCards, _card);
  2177. return false;
  2178. };
  2179. ////手上有2张及以上百搭时候的胡牌提示时候判胡算法
  2180. proto.duobaidaHutip = function (_baiDaCount22,_handCards,huRes) {
  2181. //将牌不动用百搭
  2182. let cards22 = _.clone(_handCards);
  2183. for (let i = 0; i < cards22.length - 1; ++i) {
  2184. if (!this.isJang(cards22[i], cards22[i + 1])) continue;
  2185. let cards = cards22.slice(0, i);////手牌数组的前i个元素
  2186. cards = cards.concat(cards22.slice(i + 2));////给数组cards拼接上手牌的第 i+2 个以后的全部数组元素 这句是将手牌删除2张将牌之后得到的牌
  2187. this._dumpFixeddbd(cards, huRes.huCards);
  2188. i += 1;/////TL++,为了减少运算
  2189. if(huRes.huCards.length >= 4) return true
  2190. }
  2191. //将牌动用1张百搭
  2192. ////1张牌要么配合百搭做成刻子要么做成顺子
  2193. //将牌动用2张百搭
  2194. return false;
  2195. }
  2196. // 提取成句多百搭胡牌提示时调用 card:手上的所有牌删除2张用来做将的牌之后剩下的牌 整理是否为刻子或者顺子
  2197. proto._dumpFixeddbd = function (cards, huCards) {
  2198. for (let i = 0; i < cards.length - 2; ++i) {
  2199. let card = cards[i];
  2200. if (card <= 0) continue;
  2201. if (card == cards[i + 1] && card == cards[i + 2]) {
  2202. huCards.push({ style: STYLE.KE, cards: [card, card, card] });
  2203. cards[i] = 0; cards[i + 1] = 0; cards[i + 2] = 0;
  2204. i += 2; continue;
  2205. }
  2206. if (card > 40 || this.getValue(card) > 7) continue;
  2207. let second = -1, third = -1;
  2208. for (let j = i + 1; j < cards.length; ++j) {
  2209. if (cards[j] == card + 1) second = j;
  2210. if (cards[j] == card + 2) third = j;
  2211. if (cards[j] > card + 2) break;
  2212. if (second != -1 && third != -1) break;
  2213. }
  2214. if (second != -1 && third != -1) {
  2215. huCards.push({ style: STYLE.SUN, cards: [card, cards[second], cards[third]] });
  2216. cards[i] = 0; cards[second] = 0; cards[third] = 0;
  2217. }
  2218. }
  2219. };
  2220. // 获得奖码列表和计算奖码分数函数
  2221. proto.getJiangmaInfo = function (isMZJYM) {
  2222. // console.warn("获得奖码列表函数 奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中 "+this.jiangmaType)
  2223. let jiangmaList = []
  2224. let jmzs = 0;//奖码张数
  2225. if(this.jiangmaType == 2){
  2226. //摸几奖几
  2227. jmzs = this.getValue(this.addThisIsHu);//胡的那张牌的牌值
  2228. if(this.addThisIsHu == 51) jmzs = 10;
  2229. }
  2230. else{
  2231. //159奖码 一码全中
  2232. jmzs = this.jiangmaCount;
  2233. if(isMZJYM ){
  2234. //满足无红中加1码
  2235. jmzs++;
  2236. }
  2237. }
  2238. if(this.isLaGang){
  2239. // console.warn("现在 是 拉杠胡了");
  2240. if(!this.isQGHJM){
  2241. //没有选择抢杠胡奖码
  2242. jmzs = 0;
  2243. // console.warn("现在 是 拉杠胡了 选则了抢杠胡不奖码 现在不奖码");
  2244. }
  2245. }
  2246. else{
  2247. // console.warn("现在 不是 拉杠胡了");
  2248. }
  2249. let castC1 = this.castCount;//已经消耗的
  2250. let lastC1 = this.lastCount;
  2251. for (var i = 0; i < jmzs; i++) {
  2252. let card = 0;
  2253. if (lastC1 > 0) {
  2254. card = this.cardsPool[castC1++];
  2255. lastC1 -= 1;
  2256. }
  2257. if(card > 0) jiangmaList[i] = card;
  2258. else break;
  2259. }
  2260. // console.warn("获得奖码列表函数 奖码列表 ",jiangmaList," 长度 ",jiangmaList.length," addThisIsHu ",this.addThisIsHu)
  2261. //下面是计算奖码分数
  2262. let mafen = 0;
  2263. if(this.jiangmaType == 1 || this.jiangmaType == 2){
  2264. //159奖码 摸几奖几
  2265. let count = 0
  2266. for (var i = 0; i < jiangmaList.length; i++) {
  2267. let pz = this.getValue(jiangmaList[i]);//牌值
  2268. if (pz == 1 || pz == 5 || pz == 9 || jiangmaList[i] == 51 ){
  2269. count++
  2270. }
  2271. }
  2272. mafen = 2 * count;
  2273. }
  2274. else if(this.jiangmaType == 3){
  2275. //一码全中
  2276. let count = this.getValue(jiangmaList[0]);
  2277. if(jiangmaList[0] == 51) count = 10;
  2278. mafen = count;
  2279. }
  2280. // console.warn("获得奖码分数 mafen ",mafen)
  2281. return { jiangmaList:jiangmaList,mafen:mafen}
  2282. };