logic.js 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509
  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. 101,102,103,104,105,106,107,108,109,110,111,112,113,////这代表黑桃A~K
  14. 203,204,205,206,207,208,209,210,211,212,213,////这代表红桃A~K
  15. 303,304,305,306,307,308,309,310,311,312,313,////这代表梅花A~K
  16. 403,404,405,406,407,408,409,410,411,412,////这代表方片A~K
  17. // 516,517, ////代表小王和大王
  18. ];
  19. // 块类型
  20. const STYLE = {
  21. ERROR: 1, // 牌型不存在
  22. NULL: 2, // 无效(牌型存在但是大不过)
  23. YAOBUQI: 3, // 要不起
  24. DAN: 4, // 单牌
  25. YIDUI: 5, // 一对子
  26. LIANDUI: 6, // 连对(2对或2对以上点数相连的牌,如:5566;)
  27. SANDAIYI: 7, // 三带一
  28. SANDAIER: 8, // 三带二
  29. SIDAIER: 9, // 四带二
  30. SIDAISAN: 10, // 四带三
  31. FEIJI:11, // 飞机
  32. SHUNZI:12, // 顺子
  33. ZHADAN:13, // 炸弹
  34. };
  35. // 椅子数
  36. const CHAIR_COUNT = 3;
  37. const CARDS_COUNT = 15;
  38. // 构造方法
  39. var Logic = function (type,gameKindTL,playerAllCount,other) {
  40. // 类型
  41. this.type = type;
  42. this.other = other;//////TL++2人3人的游戏规则
  43. this.isHTSFB = false;//是否红桃十翻倍
  44. if(this.other & 1){
  45. this.isHTSFB = true;
  46. }
  47. this.isZDBKC = false;//是否炸弹不可拆
  48. if(this.other & 2){
  49. this.isZDBKC = true;
  50. }
  51. this.isCanSiDaiEr = false;//是否可四带2
  52. if(this.other & 4){
  53. this.isCanSiDaiEr = true;
  54. }
  55. this.isSiCanDaiSan = false;//是否可四带3
  56. if(this.other & 32){
  57. this.isSiCanDaiSan = true;
  58. }
  59. this.cardCount = 15;//张数
  60. if(this.other & 8){//
  61. //一副牌去除大小王、去除3个A、去除3个2,去除一个方片K,共剩45张牌,每人15张牌;(一手牌中只有1个黑桃2,1个黑桃A,3个K);
  62. this.cardCount = 15;
  63. }
  64. else if(this.other & 16){//
  65. //一副牌去除大小王、去除1个A、去除3个2,共48张牌,每人16张牌;(一手牌只有1个2,3个A);
  66. this.cardCount = 16;
  67. }
  68. this.isYPBC = true;//是否有牌必出(能大过必须出牌大掉)
  69. // console.warn("是否红桃十翻倍 "+this.isHTSFB)
  70. // console.warn("是否炸弹不可拆 "+this.isZDBKC)
  71. // console.warn("是否可四带2 "+this.isCanSiDaiEr)
  72. // console.warn("是否可四带3 "+this.isSiCanDaiSan)
  73. // console.warn("张数 "+this.cardCount)
  74. // 全牌
  75. var cards = _.clone(CARDS);
  76. //添加红中红中
  77. if (this.cardCount == 16){
  78. cards[cards.length] = 201;
  79. cards[cards.length] = 301;
  80. cards[cards.length] = 413;
  81. }
  82. // console.warn("牌池总张数 "+cards.length+"' "+cards)
  83. this.castCount = 0;
  84. // this.disCount = 0;
  85. this.lastCount = cards.length;//////设置剩余牌数为了测试海底捞月
  86. this.cardsPool = cards;
  87. this.cardsyl = _.clone(cards);
  88. this.styleTL = STYLE;
  89. this.dahuTypeTL = [
  90. ["牌型不存在"], ///// 0 牌型不存在
  91. ["无效"], ///// 1 无效(牌型存在但是大不过)
  92. ["要不起"], ///// 2 要不起
  93. ["单牌"], ///// 3 单牌
  94. ["一对子"], ///// 4 一对子
  95. ["连对"], ///// 5 连对(2对或2对以上点数相连的牌,如:5566;)
  96. ["三带一"], ///// 6 三带一
  97. ["三带二"], ///// 7 三带二
  98. ["四带二"], ///// 8 四带二
  99. ["四带三"], ///// 9 四带三
  100. ["飞机"], ///// 10 飞机
  101. ["顺子"], ///// 11 顺子
  102. ["炸弹"], ///// 12 炸弹
  103. ];
  104. //////以下变量全是TL++
  105. this.gameKindTL = gameKindTL || 1;////没啥用
  106. this.playerAllCount = playerAllCount || 4;////游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局
  107. this.setCardFilerIndex = 0
  108. this.currChairIDTL = 0/////当前判断胡的chairID,用于得到当前玩家的胡牌情况
  109. this.setCardFileName = '';/////设置手牌的文件名
  110. this.cardGroupIndex = 0;////要设置的牌型种类
  111. this.uidsfydsq = [];//uid和是否有定时器的对应
  112. this.everyJPQSYSJ = [0,0,0];//每个玩家记牌器剩余时间
  113. this.dczsList = this.fillDeep(Array(13), 0);//打出张数列表,用于记牌器
  114. };
  115. Logic.setHCfileNameList =[/////全部设置牌型的文件名
  116. "setHandCard_tianhu",
  117. ]
  118. // 导出常量
  119. Logic.CARDS = CARDS;
  120. Logic.STYLE = STYLE;
  121. Logic.CHAIR_COUNT = CHAIR_COUNT;
  122. Logic.CARDS_COUNT = CARDS_COUNT;
  123. // 导出类
  124. module.exports = Logic;
  125. // 原型对象
  126. var proto = Logic.prototype;
  127. ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡
  128. proto.chuPaiTL = function () {
  129. // console.warn("111c天胡判断不正确",this.chuPaiCountTL);
  130. this.chuPaiCountTL += 1//////这个其实并不是真实的出牌个数,因为这个方法的调用在判断吃碰杠胡之前调用的
  131. }
  132. ///////TL++在table类中出牌函数中调用,为了判断天胡和地胡
  133. proto.moPaiTL = function () {
  134. // console.warn("111c天胡判断不正确",this.chuPaiCountTL);
  135. this.moPaiCountTL += 1//////TL++,记录出牌的个数,为了判断天胡和地胡 += 1
  136. }
  137. ///////TL++重置默认数据,在每局游戏开始的洗牌函数中调用
  138. proto.resetDataOnGameStart = function () {
  139. this.dczsList = this.fillDeep(Array(13), 0);//打出张数列表,用于记牌器
  140. this.chuPaiCountTL = 0//////TL++出牌个数
  141. this.moPaiCountTL = 0//////TL++,记录摸牌的个数,为了判断天胡和地胡
  142. this.lastMoPaiChairID = 0//////TL++,最后一个摸牌玩家的id
  143. }
  144. // 重新洗牌
  145. proto.shuffle = function () {
  146. this.castCount = 0;
  147. // this.disCount = 0;
  148. this.cardsPool = _.clone(this.cardsyl);
  149. this.lastCount = this.cardsPool.length;
  150. this.cardsPool = _.shuffle(this.cardsPool);////随机打乱一个数组
  151. this.cardsPool = _.shuffle(this.cardsPool);////洗第二次牌
  152. // this.cardsPool = _.shuffle(this.cardsPool);////洗第三次牌
  153. };
  154. // 填充数组
  155. proto.fillDeep = function (array, o, isMore) {
  156. for (let i = 0; i < array.length; ++i) {
  157. if (!isMore) {
  158. array[i] = _.clone(o);
  159. } else {
  160. array[i] = _.cloneDeep(o);/////深度拷贝,就是重新分配内存空间,浅拷贝则是两个变量共用一个内存对象
  161. }
  162. }
  163. return array;
  164. };
  165. //////TL++ 深复制一个object类型的数据
  166. proto.deepCloneTL = function (obj){
  167. let objClone = Array.isArray(obj)?[]:{};
  168. if(obj && typeof obj==="object"){
  169. for(let key in obj){
  170. if(obj.hasOwnProperty(key)){
  171. //判断ojb子元素是否为对象,如果是,递归复制
  172. if(obj[key]&& typeof obj[key] ==="object"){
  173. objClone[key] = this.deepCloneTL(obj[key]);
  174. }else{
  175. //如果不是,简单复制
  176. objClone[key] = obj[key];
  177. }
  178. }
  179. }
  180. }
  181. return objClone;
  182. };
  183. // 获取类型
  184. proto.getType = function (card) {
  185. return Math.floor(card / 100);
  186. };
  187. // 获取牌值
  188. proto.getValue = function (card) {
  189. return card % 100;
  190. };
  191. //排序时使用的获取牌值
  192. proto.getValuepx = function (card) {
  193. let v = card % 100;
  194. if(v == 1 || v == 2) v+=13;
  195. return v;
  196. }
  197. // 手牌排序
  198. proto.sort = function (handCards) {
  199. // return _.sortBy(handCards);///降序排序
  200. // console.warn("111手牌排序",JSON.stringify(handCards));
  201. // 111手牌排序 [101,102,103,104,105,106,107,108,109,110,111,112,113,403,404,201]
  202. var ng = _.groupBy(handCards, function (n) {
  203. let value = n % 100;
  204. if(value == 1) value = 14;
  205. if(value == 2) value = 15;
  206. return value;
  207. });
  208. // console.warn("222手牌排序",JSON.stringify(ng));
  209. // 222手牌排序 {"3":[103,403],"4":[104,404],"5":[105],"6":[106],"7":[107],"8":[108],"9":[109],"10":[110],"11":[111],"12":[112],"13":[113],"14":[101,201],"15":[102]}
  210. // let xxc = _.sortBy(ng, function(o) { return o.length; });
  211. // 333手牌排序 [[105],[106],[107],[108],[109],[110],[111],[112],[113],[102],[103,403],[104,404],[101,201]]
  212. let xxc = _.sortBy(ng, function(o) {
  213. let value = o[0] % 100;
  214. if(value == 1) value = 14;
  215. if(value == 2) value = 15;
  216. return value;
  217. });
  218. // 333手牌排序 [[103,403],[104,404],[105],[106],[107],[108],[109],[110],[111],[112],[113],[101,201],[102]]
  219. // console.warn("333手牌排序",JSON.stringify(xxc));
  220. let res = [];
  221. for (var i = 0; i < xxc.length; i++) {
  222. res = res.concat(_.sortBy(xxc[i]))
  223. // console.warn("444手牌排序",JSON.stringify(res));
  224. // 444手牌排序 [105]
  225. // 444手牌排序 [105,106]
  226. // 444手牌排序 [105,106,107]
  227. // 444手牌排序 [105,106,107,108]
  228. // 444手牌排序 [105,106,107,108,109]
  229. // 444手牌排序 [105,106,107,108,109,110]
  230. // 444手牌排序 [105,106,107,108,109,110,111]
  231. // 444手牌排序 [105,106,107,108,109,110,111,112]
  232. // 444手牌排序 [105,106,107,108,109,110,111,112,113]
  233. // 444手牌排序 [105,106,107,108,109,110,111,112,113,102]
  234. // 444手牌排序 [105,106,107,108,109,110,111,112,113,102,103,403]
  235. // 444手牌排序 [105,106,107,108,109,110,111,112,113,102,103,403,104,404]
  236. // 444手牌排序 [105,106,107,108,109,110,111,112,113,102,103,403,104,404,101,201]
  237. }
  238. // console.warn("555手牌排序",JSON.stringify(res));
  239. //下面是验证排序过程中是否出错(改变原数组)了
  240. let lygdys = _.difference(handCards,res);////另一个队员的人数
  241. let lygdys2 = _.difference(res,handCards);////另一个队员的人数
  242. if(lygdys.length > 0 || lygdys2.length > 0 || handCards.length != res.length){
  243. console.error("111==============================这把派出错了 =======",handCards);
  244. console.error("222==============================这把派出错了 =======",res);
  245. return handCards;
  246. }
  247. // console.warn("1010手牌排序",JSON.stringify(res));
  248. // 555手牌排序 [105,106,107,108,109,110,111,112,113,102,103,403,104,404,101,201]
  249. // 1010手牌排序 [103,403,104,404,105,106,107,108,109,110,111,112,113,101,201,102]
  250. return res;
  251. };
  252. // 删除手牌
  253. proto.remove = function (handCards, cards) {
  254. if (typeof (cards) == 'number') {
  255. if (cards == handCards[handCards.length - 1]) {
  256. return (handCards.pop(), true);
  257. } else {
  258. let pos = handCards.indexOf(cards);
  259. if (pos == -1) return false;
  260. return (handCards.splice(pos, 1), true);
  261. }
  262. }
  263. // console.warn("删除手牌");
  264. var length = cards.length;
  265. for (let i = 0; i < length; ++i) {
  266. let pos = handCards.indexOf(cards[i]);
  267. if (pos == -1) return false;
  268. }
  269. for (let i = 0; i < length; ++i) {
  270. let pos = handCards.indexOf(cards[i]);
  271. if (pos == -1) return false;
  272. handCards.splice(pos, 1);
  273. }
  274. return true;
  275. };
  276. // 剩余牌数
  277. proto.leaveCount = function () {
  278. return this.lastCount;
  279. };
  280. // 设置打出张数列表
  281. proto.setDCZSList = function (outCards) {
  282. for (var i = 0; i < outCards.length; i++) {
  283. let pz = this.getValue(outCards[i]);
  284. this.dczsList[pz-1]++
  285. }
  286. };
  287. // 获得打出张数列表
  288. proto.getDCZSList = function (chairID) {
  289. if(chairID < 0) return [];
  290. if(this.everyJPQSYSJ[chairID] <= 0) return [];
  291. return this.dczsList;
  292. };
  293. //////TL++,人工设置测试牌型
  294. proto.setTestSendCardsTL = function () {
  295. this.setCardFileName = '';
  296. let fileName = "setHandCard_pdk"
  297. if(!fileName) return;/////文件名字不存在
  298. // console.warn("设置手牌的文件名",fileName);
  299. this.setCardFileName = fileName
  300. var SetHandCardTL = require('./setcard/' + fileName);
  301. if(!SetHandCardTL) return;
  302. //////TL++,设置手牌的文件
  303. this.setHandCardTL = new SetHandCardTL();
  304. ////console.error("洗牌之后的牌",this.cardsPool);
  305. let ccc = this.setHandCardTL.getSCFP(this.cardGroupIndex)
  306. if(ccc){//////已经设置的手牌发完了就随机发牌
  307. this.cardsPool = ccc/////设置手牌的地方 设置牌
  308. this.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型
  309. // SetHandCardTL.cardGroupIndex += 1; ////此句是否存在代表是否只发某一种牌型
  310. // if(SetHandCardTL.cardGroupIndex == 1) SetHandCardTL.cardGroupIndex = 0
  311. }
  312. else{
  313. this.setCardFilerIndex += 1;
  314. this.cardGroupIndex = 0;
  315. // SetHandCardTL.cardGroupIndex = 0;
  316. if(Logic.setCardFilerIndex < Logic.setHCfileNameList.length) this.setTestSendCardsTL()
  317. }
  318. }
  319. // 初始手牌
  320. proto.handCards = function (chBanker,_PJHF,_over,recordid,_ctime) {
  321. this.resetDataOnGameStart()//////TL++
  322. this.shuffle();
  323. // if(this.hzCount == 8) {
  324. // this.cardsPool = [405,309,109,306,204,408,307,105,312,110,410,304,208,210,406,213,212,106,204,412,305,103,308,107,404,411,104,409,112,209,303,313,207,403,211,101,311,310,205,206,407,113,111,108,102]
  325. // this.cardsPool = [405,309,109,306,203,408,307,105,312,110,410,304,208,210,406,213,212,106,204,412,305,103,308,107,404,411,104,409,112,209,303,313,207,403,211,101,311,310,205,206,407,113,111,108,102]
  326. // this.cardsPool = [405,309,109,306,211,408,307,105,312,110,410,304,208,210,406,213,212,106,204,412,305,111,308,107,404,411,104,409,112,209,311,313,207,403,211,101,311,310,205,206,407,113,111,108,102]
  327. // this.cardsPool = [405,309,109,306,203,408,307,105,312,110,410,304,208,213,406,213,212,106,204,412,305,103,308,107,404,411,104,409,112,209,303,313,207,403,211,101,311,310,205,206,407,113,111,108,102]
  328. // this.cardsPool = [405,309,109,306,203,408,307,105,312,110,410,304,208,209,406,213,212,106,204,412,305,103,308,107,404,411,104,409,112,209,303,309,207,403,211,101,311,310,205,206,407,109,111,108,102,104,204,304]
  329. // this.cardsPool = [405,309,109,306,205,408,307,105,312,110,410,304,208,209,406,213,212,106,204,412,305,105,308,107,404,411,104,409,112,209,305,309,207,405,211,101,311,310,205,206,407,109,111,108,102,104,204,304]
  330. // this.cardsPool = [405,310,110,306,205,408,307,105,312,110,410,304,208,210,406,213,212,106,204,412,305,105,308,107,404,411,104,410,112,210,305,310,207,405,211,101,311,310,205,206,407,110,111,108,102,104,204,304]
  331. // this.cardsPool = [405,309,109,306,203,408,307,105,312,110,410,304,208,209,406,213,212,106,204,412,305,103,308,107,404,411,104,409,112,209,303,309,207,403,211,101,311,310,205,206,407,109,111,108,102,104,204,304]
  332. // this.cardsPool = [406,210,103,308,407,305,113,211,207,410,209,205,404,208,309,108,313,106,403,312,102,206,212,405,311,304,409,303,213,310,306,111,110,411,107,109,203,204,112,104,307,101,408,412,105]
  333. this.setTestSendCardsTL()///////设置手牌的地方,设置发牌 不需要设置的时候注释掉这个方法就可以了
  334. // this.lastCount = this.cardsPool.length;//////设置剩余牌数设置剩余牌数,测试完这句要删掉
  335. // }
  336. let dqjs = _over + 1;
  337. _PJHF.writexpJson(this.deepCloneTL(this.cardsPool),dqjs,recordid,_ctime);
  338. var result = [];
  339. // console.warn("发的牌池"+"牌数 "+this.cardsPool.length+" "+JSON.stringify(this.cardsPool));
  340. var castCount = 0;
  341. for (let i = 0; i < this.playerAllCount; ++i) {
  342. let cardCount = this.cardCount;
  343. // if (i == chBanker) cardCount += 1;
  344. let cards = this.cardsPool.slice(castCount, castCount + cardCount);
  345. castCount += cardCount;
  346. result.push({ cards: this.sort(cards) });
  347. }
  348. this.castCount += castCount
  349. this.lastCount -= castCount;
  350. //上面的发牌方式是前15张发给第一个人,中间15张发给第二个人,后15张发给第三个人,下面是每人发一张直到牌发完
  351. // let everyCards = [[],[],[]];
  352. // for (let i = 0; i < this.cardsPool.length; ++i) {
  353. // let fgs = i%3;
  354. // let djz = everyCards[fgs].length;
  355. // if(djz >= this.cardCount) break;
  356. // everyCards[fgs][djz] = this.cardsPool[i];
  357. // this.castCount += 1
  358. // this.lastCount -= 1;
  359. // }
  360. // for (let i = 0; i < this.playerAllCount; ++i) {
  361. // result.push({ cards: this.sort(everyCards[i]) });
  362. // }
  363. // // 下面是每人发4张(5张)直到牌发完
  364. // let everyCards = [[],[],[]];
  365. // if(this.cardCount == 15){
  366. // let cardCount = 5;
  367. // var castCount = 0;
  368. // for (let i = 0; i < 3; ++i) {
  369. // for (let j = 0; j < 3; ++j) {
  370. // let cards = this.cardsPool.slice(castCount, castCount + cardCount);
  371. // castCount += cardCount;
  372. // everyCards[j] = everyCards[j].concat(cards)
  373. // this.castCount += cardCount
  374. // this.lastCount -= cardCount;
  375. // }
  376. // }
  377. // }
  378. // else if(this.cardCount == 16){
  379. // let cardCount = 4;
  380. // for (let i = 0; i < 4; ++i) {
  381. // for (let j = 0; j < 3; ++j) {
  382. // let cards = this.cardsPool.slice(castCount, castCount + cardCount);
  383. // castCount += cardCount;
  384. // everyCards[j] = everyCards[j].concat(cards)
  385. // this.castCount += cardCount
  386. // this.lastCount -= cardCount;
  387. // }
  388. // }
  389. // }
  390. // console.warn("发的手牌",JSON.stringify(everyCards));
  391. // for (let i = 0; i < this.playerAllCount; ++i) {
  392. // result.push({ cards: this.sort(everyCards[i]) });
  393. // }
  394. // // 下面是每人发3张
  395. // let everyCards = [[],[],[]];
  396. // let cardCount = 3;
  397. // var castCount = 0;
  398. // for (let i = 0; i < 5; ++i) {
  399. // for (let j = 0; j < 3; ++j) {
  400. // let cards = this.cardsPool.slice(castCount, castCount + cardCount);
  401. // castCount += cardCount;
  402. // everyCards[j] = everyCards[j].concat(cards)
  403. // this.castCount += cardCount
  404. // this.lastCount -= cardCount;
  405. // }
  406. // }
  407. // if(this.cardCount == 16){
  408. // let cardCount2 = 1;
  409. // for (let j = 0; j < 3; ++j) {
  410. // let cards = this.cardsPool.slice(castCount, castCount + cardCount2);
  411. // castCount += cardCount2;
  412. // everyCards[j] = everyCards[j].concat(cards)
  413. // this.castCount += cardCount2
  414. // this.lastCount -= cardCount2;
  415. // }
  416. // }
  417. // console.warn("发的手牌",JSON.stringify(everyCards));
  418. // for (let i = 0; i < this.playerAllCount; ++i) {
  419. // result.push({ cards: this.sort(everyCards[i]) });
  420. // }
  421. // console.warn("发的手牌",JSON.stringify(result)+" "+this.castCount+" "+this.lastCount);
  422. return result;
  423. };
  424. // 是否无牌
  425. proto.isNoCards = function () {
  426. return this.lastCount <= 0;
  427. };
  428. // 分析牌型
  429. proto.parseBlock = function (card1, card2, card3) {
  430. // 刻子
  431. if (card1 && card1 == card2 && card1 == card3) {
  432. return { style: STYLE.KE, cards: [card1, card2, card3] };
  433. }
  434. // 顺子(排除风字)
  435. var cards = this.sort([card1, card2, card3]);
  436. if (cards[2] < 40) {
  437. if (cards[2] == cards[1] + 1 && cards[1] == cards[0] + 1) {
  438. return { style: STYLE.SUN, cards: cards };
  439. }
  440. }
  441. };
  442. ////TL++得到首局出牌玩家
  443. proto.getSCId = function (handCards) {
  444. let res = -1;
  445. for (let i = 0; i < handCards.length; ++i) {
  446. if(handCards[i].cards.indexOf(103) != -1){
  447. res = i;//首局黑桃3先出
  448. break;
  449. }
  450. }
  451. //二人时两人手牌都没有黑桃三则按照3到2的排序,看谁手上有黑桃。
  452. // 譬如没有黑桃3 ,就黑桃4 ,没有黑桃4,就黑桃5.但是除了黑桃3.其他的不需要第一手牌必出
  453. //两人手上都没有黑桃的话就按照红桃的3到2的排序看谁手上有红桃
  454. if(res == -1){
  455. let pdsx = [103,104,105,106,107,108,109,110,111,112,113,203,204,205,206,207,208,209,210,211,212,213]
  456. for (let j = 0; j < pdsx.length; ++j) {
  457. for (let i = 0; i < handCards.length; ++i) {
  458. if(handCards[i].cards.indexOf(pdsx[j]) != -1){
  459. res = i;//首局黑桃3先出
  460. break;
  461. }
  462. }
  463. }
  464. }
  465. return res;
  466. }
  467. proto.getIsHeLi = function (daicards,tipAllKind,_vgs,isHTSSC) {
  468. let bsyqk = [[-1,-1,-1],[-1,-1,-1]];//可带牌被使用情况[[第一张是否做顺子了,第一张是否做连对了,第一张是否做对子了],[第二张是否做顺子了,第二张是否做连对了,第二张是否做对子了]]
  469. for (var i = 0; i < tipAllKind.length; i++) {
  470. if(tipAllKind[i].type == STYLE.SHUNZI){
  471. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  472. let szIndex1 = tipAllKind[i].tipCards[j].indexOf(daicards[0]);
  473. if(szIndex1 != -1) bsyqk[0][0] = szIndex1
  474. let szIndex2 = tipAllKind[i].tipCards[j].indexOf(daicards[1]);
  475. if(szIndex2 != -1) bsyqk[1][0] = szIndex2
  476. }
  477. }
  478. if(tipAllKind[i].type == STYLE.LIANDUI){
  479. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  480. let szIndex1 = tipAllKind[i].tipCards[j].indexOf(daicards[0]);
  481. if(szIndex1 != -1) bsyqk[0][1] = szIndex1
  482. let szIndex2 = tipAllKind[i].tipCards[j].indexOf(daicards[1]);
  483. if(szIndex2 != -1) bsyqk[1][1] = szIndex2
  484. }
  485. }
  486. if(tipAllKind[i].type == STYLE.YIDUI){
  487. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  488. let szIndex1 = tipAllKind[i].tipCards[j].indexOf(daicards[0]);
  489. if(szIndex1 != -1) bsyqk[0][2] = szIndex1
  490. let szIndex2 = tipAllKind[i].tipCards[j].indexOf(daicards[1]);
  491. if(szIndex2 != -1) bsyqk[1][2] = szIndex2
  492. }
  493. }
  494. }
  495. let isheli = true;
  496. for (var i = 0; i < bsyqk.length; i++) {
  497. for (var j = 0; j < bsyqk[i].length; j++) {
  498. if(bsyqk[i][j] != -1){
  499. isheli = false;
  500. break;
  501. }
  502. }
  503. if(!isheli) break;
  504. }
  505. let res = {
  506. isheli:isheli,
  507. bsyqk:bsyqk,
  508. };
  509. return res;
  510. }
  511. proto.changeShunZiPai = function (tipCards,shunziCards,vgs,isHTSSC) {
  512. // console.warn("得到三带四带可带牌数组 changeShunZiPai tipCards "+JSON.stringify(tipCards) +" shunziCards "+JSON.stringify(shunziCards));
  513. // let sdpz = this.getValuepx(tipCards[0])
  514. let szxb = shunziCards.indexOf(tipCards[0]);
  515. let res = [this.deepCloneTL(shunziCards)];
  516. if(szxb != -1){
  517. for (var i = 0; i < vgs.length; i++) {
  518. if(vgs[i][0] == tipCards[0]){
  519. if(vgs[i].length == 3){
  520. res = [];
  521. if(szxb >= 5){
  522. let szp = this.deepCloneTL(shunziCards);
  523. res[res.length] = szp.slice(0,szxb-1);
  524. // console.warn(" changeShunZiPai111 res "+JSON.stringify(res)+" szxb "+szxb);
  525. }
  526. if(shunziCards.length - szxb > 5){
  527. let szp = this.deepCloneTL(shunziCards);
  528. res[res.length] = szp.slice(szxb+1, szp.length);
  529. // console.warn(" changeShunZiPai222 res "+JSON.stringify(res)+" szxb "+szxb);
  530. }
  531. }
  532. else if(vgs[i].length == 4) res[0][szxb] = vgs[i][3];
  533. break;
  534. }
  535. }
  536. }
  537. // console.warn("得到三带四带可带牌数组 changeShunZiPai res "+JSON.stringify(res)+" szxb "+szxb);
  538. return res;
  539. }
  540. //在传进来的连对list参数中去掉指定的豹子之后,返回可做连对的list
  541. proto.changeLDByBZ = function (ldList,bzList,sdTip) {
  542. // console.warn("changeLDByBZ ldList "+JSON.stringify(ldList)+" bzList "+JSON.stringify(bzList)+" sdTip "+JSON.stringify(sdTip));
  543. let duiziList = [];
  544. let isbhbz = false;//连对里是否包含指定豹子
  545. for (var i = 0; i < ldList.length; i++) {
  546. if(bzList.indexOf(ldList[i]) != -1){
  547. isbhbz = true;
  548. }
  549. else{
  550. if(i%2 == 0) {
  551. duiziList[duiziList.length] = [ldList[i],ldList[i+1]]
  552. }
  553. }
  554. }
  555. if(!isbhbz) return ldList;
  556. let lianduiList = [];
  557. if(duiziList.length >= 2){
  558. let pdz = this.getValuepx(duiziList[0][0]);
  559. let pdIndex = 0;
  560. lianduiList[0] = [duiziList[0]];
  561. // console.warn("出牌提示 连对list "+JSON.stringify(lianduiList));
  562. for (var i = 1; i < duiziList.length; i++) {
  563. if((pdz+i-pdIndex) == this.getValuepx(duiziList[i][0])){
  564. let lianduiListLastItemIndex = lianduiList.length-1;
  565. let lianduiListLastItemLastIndex = lianduiList[lianduiList.length-1].length;
  566. lianduiList[lianduiListLastItemIndex][lianduiListLastItemLastIndex] = duiziList[i];
  567. }
  568. else{
  569. // console.warn("出牌提示 连对到这里了嘛222 "+JSON.stringify(duiziList[i]));
  570. lianduiList[lianduiList.length] = [];
  571. lianduiList[lianduiList.length-1] = [duiziList[i]];
  572. pdz = this.getValuepx(duiziList[i][0]);
  573. pdIndex = i;
  574. }
  575. }
  576. }
  577. let lianduiTip = [];
  578. for (var i = 0; i < lianduiList.length; i++) {
  579. if(lianduiList[i].length >= 2){
  580. let lds = [];
  581. for (var j = 0; j < lianduiList[i].length; j++) {
  582. lds = lds.concat(lianduiList[i][j])
  583. }
  584. if(lds.length == 4){
  585. for (var z = 0; z < sdTip.length; z++) {
  586. if(sdTip[z].indexOf(lds[0]) != -1 || sdTip[z].indexOf(lds[2]) != -1){
  587. //拆开一个豹子去做4张的连对不划算
  588. lds = [];
  589. // kzld = false;
  590. break;
  591. }
  592. }
  593. }
  594. lianduiTip[lianduiTip.length] = lds;
  595. }
  596. }
  597. let kzlddp = [];//可做连对的牌
  598. for (var j = 0; j < lianduiTip.length; j++) {
  599. for (var z= 0; z < lianduiTip[j].length; z++) {
  600. kzlddp = kzlddp.concat(lianduiTip[j][z]);
  601. }
  602. }
  603. // console.warn("changeLDByBZ duiziList "+JSON.stringify(duiziList)+" lianduiList "+JSON.stringify(lianduiList)+" lianduiTip "+JSON.stringify(lianduiTip)+" kzlddp "+JSON.stringify(kzlddp));
  604. return kzlddp;
  605. }
  606. //优化三带二提示牌所带的牌 之前带的是手上的最小牌,缺点是带的牌可能会拆散手上的顺子对子连对等等
  607. proto.getNewDaiPai = function (cards,tipAllKind,vgs,isHTSSC,tipCards) {
  608. let handCards = this.deepCloneTL(cards);
  609. let sdekdItem = [tipCards[3],tipCards[4]];
  610. let sdebzItem = [tipCards[0],tipCards[1],tipCards[2]];
  611. // console.warn("????? 优化三带二提示牌所带的牌 sdekdItem "+JSON.stringify(sdekdItem)+" sdebzItem "+JSON.stringify(sdebzItem)+" tipCards "+JSON.stringify(tipCards));
  612. let kzszdp = [];
  613. let kzlddp = [];
  614. let kzdzdp = [];
  615. let dsldcd = 0;//带三的连对长度
  616. for (var i = 0; i < tipAllKind.length; i++) {
  617. if(tipAllKind[i].type == STYLE.SHUNZI){
  618. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  619. let changeed = this.changeShunZiPai(tipCards,tipAllKind[i].tipCards[j],vgs,isHTSSC);
  620. for (var z = 0; z < changeed.length; z++) {
  621. kzszdp = kzszdp.concat(changeed[z]);
  622. }
  623. }
  624. }
  625. }
  626. let sdTip = [];
  627. for (var i = 0; i < vgs.length; i++) {
  628. if(vgs[i].length == 3){
  629. sdTip[sdTip.length] = vgs[i];
  630. }
  631. if(!this.isZDBKC && vgs[i].length == 4){
  632. if(kzszdp.indexOf(vgs[i][0]) != -1) sdTip[sdTip.length] = [vgs[i][1],vgs[i][2],vgs[i][3]];
  633. else sdTip[sdTip.length] = [vgs[i][0],vgs[i][1],vgs[i][2]];
  634. }
  635. }
  636. for (var i = 0; i < tipAllKind.length; i++) {
  637. if(tipAllKind[i].type == STYLE.LIANDUI){
  638. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  639. let kzld = true;
  640. // console.warn("这里出错了??? "+tipAllKind[i].tipCards[j] + " sdebzItem[0] "+sdebzItem[0]+" sdTip "+JSON.stringify(sdTip));
  641. let newLDList = this.changeLDByBZ(tipAllKind[i].tipCards[j],sdebzItem,sdTip);
  642. if( newLDList.length != tipAllKind[i].tipCards[j].length){
  643. kzld = false;
  644. kzlddp = kzlddp.concat(newLDList);
  645. }
  646. // if(tipAllKind[i].tipCards[j].indexOf(sdebzItem[0]) != -1) kzld = false;
  647. // if(this.getValuepx(tipAllKind[i].tipCards[j][0]) != this.getValuepx(sdebzItem[0])) kzld = false;
  648. if(kzld){
  649. if(tipAllKind[i].tipCards[j].length == 4){
  650. for (var z = 0; z < sdTip.length; z++) {
  651. if(sdTip[z].indexOf(tipAllKind[i].tipCards[j][0]) != -1 || sdTip[z].indexOf(tipAllKind[i].tipCards[j][2] != -1)){
  652. //拆开一个豹子去做4张的连对不划算
  653. kzld = false;
  654. break;
  655. }
  656. }
  657. }
  658. }
  659. if(kzld){
  660. kzlddp = kzlddp.concat(tipAllKind[i].tipCards[j]);
  661. // if(isHTSSC && tipAllKind[i].tipCards[j][0] == 103) dsldcd = tipAllKind[i].tipCards[j].length;
  662. }
  663. }
  664. }
  665. }
  666. for (var i = 0; i < tipAllKind.length; i++) {
  667. if(tipAllKind[i].type == STYLE.YIDUI){
  668. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  669. let kzdz = true;
  670. if(this.getValuepx(tipAllKind[i].tipCards[j][0]) == this.getValuepx(sdebzItem[0])) kzdz = false;
  671. if(kzdz && kzlddp.indexOf(tipAllKind[i].tipCards[j][0]) != -1) kzdz = false;
  672. let pai = tipAllKind[i].tipCards[j][0];
  673. for (var z = 0; z < vgs.length; z++) {
  674. if(vgs[z][0] == tipAllKind[i].tipCards[j][0]){
  675. if(vgs[z].length == 4){
  676. pai = vgs[3];
  677. break;
  678. }
  679. }
  680. }
  681. if(kzdz && kzszdp.indexOf(pai) != -1) kzdz = false;
  682. if(kzdz){
  683. kzdzdp = kzdzdp.concat(tipAllKind[i].tipCards[j]);
  684. }
  685. }
  686. }
  687. }
  688. // console.warn("得到三带四带可带牌数组 调整之后 kzdzdp "+JSON.stringify(kzdzdp) +" kzlddp "+JSON.stringify(kzlddp)+" kzszdp "+JSON.stringify(kzszdp) );
  689. let kzdpdp = [];//可做单牌的牌
  690. for (var i = 0; i < handCards.length; i++) {
  691. let zszIndex = -1;//做顺子下标
  692. let zldIndex = -1;//做连对下标
  693. let zdzIndex = -1;//做对子下标
  694. zszIndex = kzszdp.indexOf(handCards[i]);
  695. zldIndex = kzlddp.indexOf(handCards[i]);
  696. zdzIndex = kzdzdp.indexOf(handCards[i]);
  697. if(zszIndex == -1 && zldIndex == -1 && zdzIndex == -1) {
  698. let iskd = true;
  699. for (var j = 0; j < sdTip.length; j++) {
  700. if(sdTip[j].indexOf(handCards[i]) != -1){
  701. iskd = false;
  702. break;
  703. }
  704. }
  705. if(iskd) kzdpdp[kzdpdp.length] = handCards[i];
  706. }
  707. }
  708. // console.warn("得到三带四带可带牌数组 kzdpdp "+JSON.stringify(kzdpdp) );
  709. // if(isHTSSC && kzdpdp.indexOf(103) == -1){
  710. // if(handCards.indexOf(103) != -1){//加这个判断是为了防止在首局黑桃三出牌之后判断第二家能否要起的时候把103添加给第二家的出牌提示
  711. // kzdpdp = [103].concat(kzdpdp);
  712. // if(vgs[0][0] == 103 && vgs[0].length == 2 && lianduiTip[0][0][0] == 103){
  713. // //黑桃3首出的时候,由于必须带三导致带黑桃三的连对失败,就剔除掉连对列表里面带黑桃三的这个连对
  714. // if(dsldcd == 2){
  715. // console.warn("得到三带四带可带牌数组111 kzdzdp "+JSON.stringify(kzdzdp)+" kzlddp "+JSON.stringify(kzlddp) );
  716. // kzdzdp = [kzlddp[0],kzlddp[1],kzlddp[2],kzlddp[3]].concat(kzdzdp);
  717. // kzlddp =kzlddp.slice(4, kzlddp.length);
  718. // console.warn("得到三带四带可带牌数组222 kzdzdp "+JSON.stringify(kzdzdp)+" kzlddp "+JSON.stringify(kzlddp) );
  719. // }
  720. // else if(dsldcd > 2){
  721. // kzdzdp = [kzlddp[0],kzlddp[1]].concat(kzdzdp);
  722. // kzlddp =kzlddp.slice(2, kzlddp.length);
  723. // }
  724. // }
  725. // }
  726. // }
  727. let res = [];
  728. res = res.concat(kzdpdp);
  729. res = res.concat(kzdzdp);
  730. res = res.concat(kzlddp);
  731. res = res.concat(kzszdp);
  732. // console.warn("得到三带四带可带牌数组 结果去重之前 "+JSON.stringify(res));
  733. res = _.uniq(res);
  734. if(this.getValuepx(res[0]) > this.getValuepx(res[1]) && this.getValuepx(res[1]) == this.getValuepx(res[2])){
  735. let qsg = [res[1],res[2],res[0]];
  736. res = res.slice(3, res.length);
  737. res = qsg.concat(res);
  738. }
  739. // console.warn("得到三带四带可带牌数组 结果去重之后 "+JSON.stringify(res));
  740. return [res[0],res[1]];
  741. }
  742. //优化三带二提示牌所带的牌 之前带的是手上的最小牌,缺点是带的牌可能会拆散手上的顺子对子连对等等
  743. proto.getKeDaisSort2 = function (cards,_tipAllKind,_vgs,isHTSSC) {
  744. if(cards.length <= 5) return
  745. let tipAllKind = this.deepCloneTL(_tipAllKind);
  746. let vgs = this.deepCloneTL(_vgs);
  747. let handCards = this.deepCloneTL(cards);
  748. for (var i = 0; i < tipAllKind.length; i++) {
  749. if(tipAllKind[i].type == STYLE.SANDAIER){
  750. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  751. let sdetsItem = tipAllKind[i].tipCards[j];
  752. let sdekdItem = [tipAllKind[i].tipCards[j][3],tipAllKind[i].tipCards[j][4]]
  753. let isHeLi = this.getIsHeLi(sdekdItem,tipAllKind)//这个三带二带的是否需要优化
  754. // console.warn("三带二提示牌 "+JSON.stringify(tipAllKind[i].tipCards[j])+" 带的牌 "+sdekdItem+" 是否合理 "+JSON.stringify(isHeLi));
  755. if(!isHeLi.isheli){
  756. let newDaiPai = this.getNewDaiPai(handCards,tipAllKind,vgs,isHTSSC,tipAllKind[i].tipCards[j])
  757. tipAllKind[i].tipCards[j][3] = newDaiPai[0];
  758. tipAllKind[i].tipCards[j][4] = newDaiPai[1];
  759. _tipAllKind[i].tipCards[j] = tipAllKind[i].tipCards[j];
  760. }
  761. }
  762. }
  763. }
  764. }
  765. //得到三带四带可带牌数组 之前带的是手上的最小牌,缺点是带的牌可能会拆散手上的顺子对子连对等等
  766. // proto.getKeDaisSort = function (cards,_tipAllKind,_vgs,isHTSSC,sdTip) {
  767. // let tipAllKind = this.deepCloneTL(_tipAllKind);
  768. // let vgs = this.deepCloneTL(_vgs);
  769. // let handCards = this.deepCloneTL(cards);
  770. // let kzszdp = [];
  771. // for (var i = 0; i < tipAllKind.length; i++) {
  772. // if(tipAllKind[i].type == STYLE.SHUNZI){
  773. // for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  774. // // let iskd = true;
  775. // // for (var z = 0; z < sdTip.length; z++) {
  776. // // for (var x = 0; x < sdTip[z].length; x++) {
  777. // // if(tipAllKind[i].tipCards[j].indexOf(sdTip[z][x]) != -1){
  778. // // iskd = false;
  779. // // break;
  780. // // }
  781. // // }
  782. // // if(iskd == false) break;
  783. // // }
  784. // // console.warn("得到三带四带可带牌数组 提示里面可做顺子的牌 "+JSON.stringify(tipAllKind[i].tipCards[j])+" iskd "+iskd);
  785. // // if(!iskd) continue;
  786. // kzszdp = kzszdp.concat(tipAllKind[i].tipCards[j]);
  787. // }
  788. // }
  789. // }
  790. // console.warn("得到三带四带可带牌数组 可做顺子的牌 "+JSON.stringify(kzszdp)+" 手牌 "+JSON.stringify(handCards)+" vgs "+JSON.stringify(vgs) );
  791. // let duiziList = [];
  792. // let duiziList2 = [];
  793. // // let pzgsList = [];//牌值个数list
  794. // for (var i = 0; i < vgs.length; i++) {
  795. // let iskd = true;
  796. // for (var j = 0; j < sdTip.length; j++) {
  797. // if(sdTip[j].indexOf(vgs[i][0]) != -1){
  798. // iskd = false;
  799. // break;
  800. // }
  801. // }
  802. // if(!iskd) continue;
  803. // if(vgs[i].length == 2 || vgs[i].length == 3){
  804. // duiziList[duiziList.length] = [vgs[i][0],vgs[i][1]];
  805. // duiziList2[duiziList2.length] = [vgs[i][0],vgs[i][1]];
  806. // }
  807. // if(!this.isZDBKC && vgs[i].length == 4){
  808. // duiziList[duiziList.length] = [vgs[i][0],vgs[i][1]];
  809. // duiziList2[duiziList2.length] = [vgs[i][0],vgs[i][1]];
  810. // duiziList2[duiziList2.length] = [vgs[i][2],vgs[i][3]];
  811. // }
  812. // }
  813. // let lianduiList = [];
  814. // let dsldcd = 0;//带三的连对长度
  815. // if(duiziList.length >= 2){
  816. // let pdz = this.getValuepx(duiziList[0][0]);
  817. // if(isHTSSC && pdz == 3 && duiziList[0][0] == 103) dsldcd = 1;
  818. // let pdIndex = 0;
  819. // lianduiList[0] = [duiziList[0]];
  820. // // console.warn("出牌提示 连对list "+JSON.stringify(lianduiList));
  821. // for (var i = 1; i < duiziList.length; i++) {
  822. // if((pdz+i-pdIndex) == this.getValuepx(duiziList[i][0])){
  823. // if(isHTSSC && pdz == 3) dsldcd++;
  824. // let lianduiListLastItemIndex = lianduiList.length-1;
  825. // let lianduiListLastItemLastIndex = lianduiList[lianduiList.length-1].length;
  826. // lianduiList[lianduiListLastItemIndex][lianduiListLastItemLastIndex] = duiziList[i];
  827. // }
  828. // else{
  829. // // console.warn("出牌提示 连对到这里了嘛222 "+JSON.stringify(duiziList[i]));
  830. // lianduiList[lianduiList.length] = [];
  831. // lianduiList[lianduiList.length-1] = [duiziList[i]];
  832. // pdz = this.getValuepx(duiziList[i][0]);
  833. // pdIndex = i;
  834. // }
  835. // }
  836. // }
  837. // let lianduiTip = [];
  838. // for (var i = 0; i < lianduiList.length; i++) {
  839. // if(lianduiList[i].length >= 2){
  840. // let lds = [];
  841. // for (var j = 0; j < lianduiList[i].length; j++) {
  842. // lds = lds.concat(lianduiList[i][j])
  843. // }
  844. // lianduiTip[lianduiTip.length] = lds;
  845. // }
  846. // }
  847. // let kzlddp = [];//可做连对的牌
  848. // for (var j = 0; j < lianduiTip.length; j++) {
  849. // for (var z= 0; z < lianduiTip[j].length; z++) {
  850. // kzlddp = kzlddp.concat(lianduiTip[j][z]);
  851. // }
  852. // }
  853. // let kzdzdp = [];//可做对子的牌
  854. // for (var i = 0; i < duiziList2.length; i++) {
  855. // let iskzld = false;
  856. // for (var j = 0; j < lianduiTip.length; j++) {
  857. // if(iskzld) break;
  858. // for (var z= 0; z < lianduiTip[j].length; z++) {
  859. // if(duiziList2[i][0] == lianduiTip[j][z][0]){
  860. // iskzld = true;
  861. // break;
  862. // }
  863. // }
  864. // }
  865. // if(!iskzld) kzdzdp = kzdzdp.concat(duiziList2[i]);
  866. // }
  867. // console.warn("得到三带四带可带牌数组 duiziList "+JSON.stringify(duiziList) +" lianduiTip "+JSON.stringify(lianduiTip) );
  868. // console.warn("得到三带四带可带牌数组 kzdzdp "+JSON.stringify(kzdzdp) +" kzlddp "+JSON.stringify(kzlddp) );
  869. // // let kzdpdp = [];
  870. // // for (var i = 0; i < vgs.length; i++) {
  871. // // if(vgs[i].length == 1 ) kzdpdp[kzdpdp.length] =[vgs[i][0];
  872. // // }
  873. // for (var i = 0; i < handCards.length; i++) {
  874. // let zszIndex = -1;//做顺子下标
  875. // let zldIndex = -1;//做连对下标
  876. // let zdzIndex = -1;//做对子下标
  877. // zszIndex = kzszdp.indexOf(handCards[i]);
  878. // zldIndex = kzlddp.indexOf(handCards[i]);
  879. // zdzIndex = kzdzdp.indexOf(handCards[i]);
  880. // if(zszIndex == -1 && zldIndex == -1 && zdzIndex == -1) {
  881. // }
  882. // else{
  883. // let vg = [];//牌值列表
  884. // for (var j = 0; j < vgs.length; j++) {
  885. // if(vgs[j][0] == handCards[i]) {
  886. // vg = vgs[j];
  887. // break;
  888. // }
  889. // }
  890. // // if(vg.length >= 3){
  891. // if(vg.length == 2){
  892. // console.warn("到这里了嘛??? ",zszIndex,zdzIndex,handCards[i]);
  893. // if(zszIndex != -1 && zdzIndex != -1) {
  894. // console.warn("到这里了嘛???222 ",zszIndex,zdzIndex,handCards[i]);
  895. // let cards = kzdzdp.slice(0, zdzIndex);////手牌数组的前zdzIndex个元素
  896. // cards = cards.concat(kzdzdp.slice(zdzIndex + 2));
  897. // kzdzdp = [];
  898. // kzdzdp = this.deepCloneTL(cards);
  899. // }
  900. // }
  901. // if(vg.length == 3){
  902. // if(zldIndex != -1){
  903. // kzlddp[zldIndex] = vg[1];
  904. // kzlddp[zldIndex+1] = vg[2];
  905. // }
  906. // else if(zszIndex != -1 && zdzIndex != -1) {
  907. // kzlddp[zldIndex] = vg[1];
  908. // kzlddp[zldIndex+1] = vg[2];
  909. // }
  910. // }
  911. // // else if(vg.length == 4){
  912. // // if(zldIndex != -1){
  913. // // kzlddp[zldIndex] = vg[2];
  914. // // kzlddp[zldIndex+1] = vg[3];
  915. // // }
  916. // // else if(zszIndex != -1 && zdzIndex != -1) {
  917. // // kzlddp[zldIndex] = vg[2];
  918. // // kzlddp[zldIndex+1] = vg[3];
  919. // // }
  920. // // }
  921. // // }
  922. // }
  923. // }
  924. // console.warn("得到三带四带可带牌数组 调整之后 kzdzdp "+JSON.stringify(kzdzdp) +" kzlddp "+JSON.stringify(kzlddp) );
  925. // let kzdpdp = [];//可做单牌的牌
  926. // for (var i = 0; i < handCards.length; i++) {
  927. // // console.warn("出牌提示 ?? "+handCards[i]+ " v "+this.getValuepx(handCards[i])+" 三带牌值 "+JSON.stringify(sdPaiZhi) );
  928. // // let iddp = (kzszdp.indexOf(handCards[i]) == -1);
  929. // // if(iddp) iddp = (kzlddp.indexOf(handCards[i]) == -1);
  930. // // if(iddp) iddp = (kzdzdp.indexOf(handCards[i]) == -1);
  931. // // if(iddp) {
  932. // // kzdpdp[kzdpdp.length] = handCards[i];
  933. // // }
  934. // let zszIndex = -1;//做顺子下标
  935. // let zldIndex = -1;//做连对下标
  936. // let zdzIndex = -1;//做对子下标
  937. // zszIndex = kzszdp.indexOf(handCards[i]);
  938. // zldIndex = kzlddp.indexOf(handCards[i]);
  939. // zdzIndex = kzdzdp.indexOf(handCards[i]);
  940. // if(zszIndex == -1 && zldIndex == -1 && zdzIndex == -1) {
  941. // let iskd = true;
  942. // for (var j = 0; j < sdTip.length; j++) {
  943. // if(sdTip[j].indexOf(handCards[i]) != -1){
  944. // iskd = false;
  945. // break;
  946. // }
  947. // }
  948. // if(iskd) kzdpdp[kzdpdp.length] = handCards[i];
  949. // }
  950. // }
  951. // console.warn("得到三带四带可带牌数组 kzdpdp "+JSON.stringify(kzdpdp) );
  952. // if(isHTSSC && kzdpdp.indexOf(103) == -1){
  953. // if(handCards.indexOf(103) != -1){//加这个判断是为了防止在首局黑桃三出牌之后判断第二家能否要起的时候把103添加给第二家的出牌提示
  954. // kzdpdp = [103].concat(kzdpdp);
  955. // if(vgs[0][0] == 103 && vgs[0].length == 2 && lianduiTip[0][0][0] == 103){
  956. // //黑桃3首出的时候,由于必须带三导致带黑桃三的连对失败,就剔除掉连对列表里面带黑桃三的这个连对
  957. // if(dsldcd == 2){
  958. // console.warn("得到三带四带可带牌数组111 kzdzdp "+JSON.stringify(kzdzdp)+" kzlddp "+JSON.stringify(kzlddp) );
  959. // kzdzdp = [kzlddp[0],kzlddp[1],kzlddp[2],kzlddp[3]].concat(kzdzdp);
  960. // kzlddp =kzlddp.slice(4, kzlddp.length);
  961. // console.warn("得到三带四带可带牌数组222 kzdzdp "+JSON.stringify(kzdzdp)+" kzlddp "+JSON.stringify(kzlddp) );
  962. // }
  963. // else if(dsldcd > 2){
  964. // kzdzdp = [kzlddp[0],kzlddp[1]].concat(kzdzdp);
  965. // kzlddp =kzlddp.slice(2, kzlddp.length);
  966. // }
  967. // }
  968. // }
  969. // }
  970. // let res = [];
  971. // res = res.concat(kzdpdp);
  972. // res = res.concat(kzdzdp);
  973. // res = res.concat(kzlddp);
  974. // res = res.concat(kzszdp);
  975. // console.warn("得到三带四带可带牌数组 结果去重之前 "+JSON.stringify(res));
  976. // res = _.uniq(res);
  977. // // return _.uniq(res);
  978. // // console.warn("得到三带四带可带牌数组 结果去重之后 "+JSON.stringify(res));
  979. // if(this.getValuepx(res[0]) > this.getValuepx(res[1]) && this.getValuepx(res[1]) == this.getValuepx(res[2])){
  980. // let qsg = [res[1],res[2],res[0]];
  981. // res = res.slice(3, res.length);
  982. // res = qsg.concat(res);
  983. // }
  984. // return res;
  985. // }
  986. /**
  987. * 根据牌返回牌值的个数
  988. * 如[202,203,204,302,403] 返回[1,2,2] 1个4 2个2 2个3
  989. 如[102,302,402,106,306,406,307,107,207,308,108,408,208,] 返回[ 3, 3, 3, 4 ]
  990. * @param {*} cards
  991. */
  992. proto.getPokeValueArr = function (cards) {
  993. // console.warn("根据牌返回牌值的个数111 "+JSON.stringify(cards));
  994. // 根据牌返回牌值的个数111 [107,106,105,404,104,403,103]
  995. var getLogicValue = function (card) {
  996. let value = card % 100;
  997. if(value == 1) value = 14;
  998. if(value == 2) value = 15;
  999. return value;
  1000. };
  1001. var cg = _.groupBy(_.map(cards, function (n) { return getLogicValue(n) }));
  1002. // console.warn("根据牌返回牌值的个数222 "+JSON.stringify(cg));
  1003. // 根据牌返回牌值的个数222 {"3":[3,3],"4":[4,4],"5":[5],"6":[6],"7":[7]}
  1004. var cgs = Object.keys(cg);
  1005. // console.warn("根据牌返回牌值的个数333 "+JSON.stringify(cgs));
  1006. // 根据牌返回牌值的个数333 ["3","4","5","6","7"]
  1007. var ng = _.map(cgs, function (n) { return cg[n].length });
  1008. // console.warn("根据牌返回牌值的个444 "+JSON.stringify(ng));
  1009. // 根据牌返回牌值的个444 [2,2,1,1,1]
  1010. ng = _.sortBy(ng);
  1011. // console.warn("根据牌返回牌值的个555 "+JSON.stringify(ng));
  1012. // 根据牌返回牌值的个555 [1,1,1,2,2]
  1013. return ng;
  1014. }
  1015. proto.aCardIsHefa = function (card) {
  1016. return this.getType(card) >= 1 && this.getType(card) <= 4 && this.getValue(card) >= 1 && this.getValue(card) <= 13
  1017. }
  1018. //得到手牌中牌值最大的数组
  1019. proto.getMaxDanList = function (cards) {
  1020. let max = 0;
  1021. for(var i = 0; i < cards.length; i++){ //遍历当前数组
  1022. let v = this.getValuepx(cards[i]);
  1023. if(v > max) max = v;
  1024. }
  1025. let res = [];
  1026. for(var i = 0; i < cards.length; i++){ //遍历当前数组
  1027. let v = this.getValuepx(cards[i]);
  1028. if(v == max) res[res.length] = cards[i];
  1029. }
  1030. return res;
  1031. }
  1032. //得到list中是否含有豹子 用于判断连对是否拆了豹子
  1033. proto.getIsHanBaozi = function (list,vgs) {
  1034. for (var i = 0; i < vgs.length; i++) {
  1035. if(vgs[i].length >= 3 ){
  1036. for (var j = 0; j < list.length; j++) {
  1037. if(vgs[i].indexOf(list[j]) != -1) return true;
  1038. }
  1039. }
  1040. }
  1041. return false;
  1042. }
  1043. // // TL++出牌提示 chairID(TL++这个参数) 手牌 上家出牌 是否黑桃三首出 是否下家只剩一张了
  1044. proto.getOutTip = function (chairID,_handCards,lastOut,isHTSSC,isXJZSYZ) {
  1045. // console.error("sscc777出牌提示handCards",chairID,JSON.stringify(_handCards),JSON.stringify(lastOut),isHTSSC);
  1046. let tipRes = [];////最终返回结果
  1047. let handCards = _.clone(_handCards);
  1048. var ng = _.groupBy(handCards, function (n) {
  1049. let value = n % 100;
  1050. if(value == 1) value = 14;
  1051. if(value == 2) value = 15;
  1052. return value;
  1053. });
  1054. // console.warn("222出牌提示 ",JSON.stringify(ng));
  1055. var kgs = Object.keys(ng);
  1056. // console.warn("出牌提示根据牌返回牌值的个数333 kgs "+JSON.stringify(kgs));
  1057. let vgs = _.sortBy(ng, function(o) {
  1058. let value = o[0] % 100;
  1059. if(value == 1) value = 14;
  1060. if(value == 2) value = 15;
  1061. return value;
  1062. });
  1063. // console.warn("根据牌返回牌值的个数444 vgs "+JSON.stringify(vgs));
  1064. let pzfbqk = this.getPokeValueArr(handCards);//牌值分布情况
  1065. let lpzfbqk = [];//上次有效出牌牌值分布情况
  1066. if(lastOut.cards.length > 0){
  1067. lpzfbqk = this.getPokeValueArr(lastOut.cards);
  1068. }
  1069. // console.warn("222出牌提示 手牌牌值分布情况 ",JSON.stringify(pzfbqk));
  1070. // console.warn("222出牌提示 上次出牌牌值分布情况 ",JSON.stringify(lpzfbqk));
  1071. let spCount = handCards.length;
  1072. let tipAllKind = [];////提示的所有种可能性
  1073. let bkzcszddp = [];//不可组成顺子的单牌
  1074. let isKeShunzi = false;
  1075. let isblFirst = (lastOut.type == -1 && lastOut.cards.length == 0);//是否本轮第一个出牌
  1076. let baoziList = [];
  1077. for (var i = 0; i < vgs.length; i++) {
  1078. if(vgs[i].length == 3 ) baoziList[baoziList.length] = [vgs[i][0],vgs[i][1],vgs[i][2]];
  1079. if(!this.isZDBKC && vgs[i].length == 4) baoziList[baoziList.length] = [vgs[i][0],vgs[i][1],vgs[i][2]];
  1080. }
  1081. // console.warn("出牌提示 豹子list "+JSON.stringify(baoziList));
  1082. if(baoziList.length >= 2){
  1083. let lianbaoList = [];
  1084. let pdz = this.getValuepx(baoziList[0][0]);
  1085. let pdIndex = 0;
  1086. lianbaoList[0] = [baoziList[0]];
  1087. // console.warn("出牌提示 豹子list "+JSON.stringify(baoziList));
  1088. for (var i = 1; i < baoziList.length; i++) {
  1089. // console.warn("出牌提示 豹子 i "+i+" pdz "+pdz+" pdIndex "+pdIndex);
  1090. if((pdz+i-pdIndex) == this.getValuepx(baoziList[i][0])){
  1091. let lianbaoListLastItemIndex = lianbaoList.length-1;
  1092. let lianbaoListLastItemLastIndex = lianbaoList[lianbaoList.length-1].length;
  1093. // console.warn("出牌提示 豹子到这里了嘛111 "+lianbaoListLastItemIndex+" "+lianbaoListLastItemLastIndex+" "+JSON.stringify(lianbaoList));
  1094. lianbaoList[lianbaoListLastItemIndex][lianbaoListLastItemLastIndex] = baoziList[i];
  1095. }
  1096. else{
  1097. // console.warn("出牌提示 豹子到这里了嘛222 "+JSON.stringify(lianbaoList));
  1098. lianbaoList[lianbaoList.length] = [];
  1099. lianbaoList[lianbaoList.length-1] = [baoziList[i]];
  1100. pdz = this.getValuepx(baoziList[i][0]);
  1101. pdIndex = i;
  1102. }
  1103. }
  1104. // console.warn("出牌提示 lianbaolist "+JSON.stringify(lianbaoList));
  1105. let lianbaoList2 = [];
  1106. let fjPaiZhi = [];
  1107. for (var i = 0; i < lianbaoList.length; i++) {
  1108. if(lianbaoList[i].length >= 2){
  1109. for (var j = 0; j < lianbaoList[i].length; j++) {
  1110. fjPaiZhi[fjPaiZhi.length] = this.getValuepx(lianbaoList[i][j][0])
  1111. }
  1112. lianbaoList2[lianbaoList2.length] = lianbaoList[i];
  1113. }
  1114. }
  1115. // console.warn("出牌提示 lianbaolist2 "+JSON.stringify(lianbaoList2)+" 飞机3张牌值 "+JSON.stringify(fjPaiZhi));
  1116. if(lianbaoList2.length > 0){
  1117. if(lastOut.type == STYLE.FEIJI && lastOut.cards.length == 10){
  1118. //别人打的是个2连豹的飞机,自己手上是个3连豹(4连豹)的飞机,将自己的3(4)连豹拆分成多个2连豹的飞机
  1119. if(lianbaoList2.length == 1 && lianbaoList2[0].length > 2){
  1120. let lianbaoList3 = [];
  1121. let item = [];
  1122. for (var i = 0; i < lianbaoList2[0].length; i++) {
  1123. if(item.length < 2) item[item.length] = lianbaoList2[0][i];
  1124. if(item.length == 2){
  1125. lianbaoList3[lianbaoList3.length] = item;
  1126. item = [];
  1127. item[item.length] = lianbaoList2[0][i];
  1128. }
  1129. }
  1130. lianbaoList2 = [];
  1131. for (var i = 0; i < lianbaoList3.length; i++) {
  1132. if(lianbaoList3[i].length >= 2){
  1133. lianbaoList2[lianbaoList2.length] = lianbaoList3[i];
  1134. }
  1135. }
  1136. // console.warn("出牌提示 lianbaolist3 "+JSON.stringify(lianbaoList3)+" lianbaoList2 "+JSON.stringify(lianbaoList2));
  1137. }
  1138. }
  1139. let kedais = [];
  1140. for (var i = 0; i < handCards.length; i++) {
  1141. // console.warn("出牌提示 ?? "+handCards[i]+ " v "+this.getValuepx(handCards[i])+" 三带牌值 "+JSON.stringify(sdPaiZhi) );
  1142. if(!this.isZDBKC){
  1143. if(fjPaiZhi.indexOf(this.getValuepx(handCards[i])) == -1) kedais[kedais.length] = handCards[i];
  1144. }
  1145. else{
  1146. let iszd = false;
  1147. for (var j = 0; j < vgs.length; j++) {
  1148. if(vgs[j].length == 4 && vgs[j].indexOf(handCards[i]) != -1){
  1149. iszd = true;
  1150. break;
  1151. }
  1152. }
  1153. if(!iszd && fjPaiZhi.indexOf(this.getValuepx(handCards[i])) == -1) kedais[kedais.length] = handCards[i];
  1154. }
  1155. if(kedais.length >= lianbaoList2[0].length*2) break
  1156. }
  1157. let ckedais = this.deepCloneTL(kedais);
  1158. // console.warn("出牌提示 飞机list "+JSON.stringify(lianbaoList2)+" 可带 "+kedais);
  1159. let feijiTip = [];
  1160. for (var i = 0; i < lianbaoList2.length; i++) {
  1161. if(lianbaoList2[i].length >= 2){
  1162. if(spCount >= lianbaoList2[i].length*5){
  1163. kedais = this.deepCloneTL(ckedais);
  1164. if(kedais.length < lianbaoList2[i].length*2){
  1165. // console.warn("手上的单牌不够飞机带,就需要拆豹子带了"+" 可带 "+kedais+" handCards[j] "+handCards[j]);
  1166. //手上的单牌不够飞机带,就需要拆豹子带了
  1167. for (var j = 0; j < handCards.length; j++) {
  1168. let isCanAddToFJkedais = true;//是否可以添加进飞机可带
  1169. for (var jj = 0; jj < lianbaoList2[i].length; jj++) {
  1170. if(lianbaoList2[i][jj].indexOf(handCards[j]) != -1 || kedais.indexOf(handCards[j]) != -1){
  1171. isCanAddToFJkedais = false;
  1172. break;
  1173. }
  1174. }
  1175. if(isCanAddToFJkedais) {
  1176. kedais[kedais.length] = handCards[j];
  1177. }
  1178. else continue;
  1179. if(kedais.length >= lianbaoList2[i].length*2) break
  1180. }
  1181. }
  1182. let dd = [kedais[0],kedais[1],kedais[2],kedais[3]];
  1183. if(lianbaoList2[i].length == 3) dd = dd.concat([kedais[4],kedais[5]]);
  1184. feijiTip[feijiTip.length] = [];
  1185. for (var j = 0; j < lianbaoList2[i].length; j++) {
  1186. feijiTip[feijiTip.length-1] = feijiTip[feijiTip.length-1].concat(lianbaoList2[i][j]);
  1187. }
  1188. feijiTip[feijiTip.length-1] = feijiTip[feijiTip.length-1].concat(dd);
  1189. }
  1190. else{
  1191. if(isblFirst){
  1192. feijiTip[feijiTip.length] = [];
  1193. for (var j = 0; j < lianbaoList2[i].length; j++) {
  1194. feijiTip[feijiTip.length-1] = feijiTip[feijiTip.length-1].concat(lianbaoList2[i][j]);
  1195. }
  1196. feijiTip[feijiTip.length-1] = feijiTip[feijiTip.length-1].concat(kedais);
  1197. }
  1198. }
  1199. }
  1200. }
  1201. // console.warn("出牌提示 飞机结果 "+JSON.stringify(feijiTip));
  1202. if(feijiTip.length > 0){
  1203. tipAllKind[tipAllKind.length] = {
  1204. type: STYLE.FEIJI,
  1205. tipCards: feijiTip
  1206. };
  1207. }
  1208. }
  1209. }
  1210. if(spCount >= 5){
  1211. let bkzsz = [];
  1212. if(this.isZDBKC){
  1213. for (var i = 0; i < vgs.length; i++) {
  1214. if(vgs[i].length == 4 ) bkzsz[bkzsz.length] = this.getValuepx(vgs[i][0]);
  1215. }
  1216. }
  1217. // console.warn("不可左顺子的牌值 "+JSON.stringify(bkzsz)+" kgs "+JSON.stringify(kgs));
  1218. let szgs = 0;
  1219. let szpz = [];
  1220. let sindex = 0;
  1221. if(bkzsz.length > 0 ){
  1222. for (var i = 0; i < kgs.length; i++) {
  1223. if(parseInt(kgs[i]) == 15) continue;
  1224. if(bkzsz.indexOf(parseInt(kgs[i])) == -1) {
  1225. szpz[0] = [kgs[i]];
  1226. sindex = i+1;
  1227. break;
  1228. }
  1229. }
  1230. }
  1231. else{
  1232. szpz[0] = [kgs[0]];
  1233. sindex = 1;
  1234. }
  1235. // console.warn("出牌提示 顺子牌值111 "+JSON.stringify(szpz) );
  1236. if(szpz.length > 0) {
  1237. for (var i = sindex; i < kgs.length; i++) {
  1238. if (parseInt(kgs[i]) == 15) continue;
  1239. if (bkzsz.length > 0 && bkzsz.indexOf(parseInt(kgs[i])) != -1) continue;
  1240. if ((parseInt(szpz[szgs][0]) + szpz[szgs].length) == parseInt(kgs[i])) {
  1241. szpz[szgs][szpz[szgs].length] = kgs[i];
  1242. } else {
  1243. if (szpz[szgs].length >= 5) szgs++;
  1244. szpz[szgs] = [kgs[i]];
  1245. }
  1246. }
  1247. // console.warn("出牌提示 顺子牌值111 "+JSON.stringify(szpz) );
  1248. if (_.last(szpz).length < 5) {
  1249. szpz = _.initial(szpz);
  1250. }
  1251. }
  1252. // console.warn("出牌提示 顺子牌值222 "+JSON.stringify(szpz) );
  1253. // if(isKeShunzi){
  1254. let szTip = [];
  1255. for (var i = 0; i < szpz.length; i++) {
  1256. if(szpz[i].length < 5) continue
  1257. szTip[i] = [];
  1258. for (var j = 0; j < szpz[i].length; j++) {
  1259. if(j == 0 && szpz[i][j] == "3"){
  1260. if(ng["3"].indexOf(103) != -1) szTip[i][j] = 103;
  1261. else szTip[i][j] = ng["3"][0];
  1262. }
  1263. else szTip[i][j] = ng[szpz[i][j]][0]
  1264. }
  1265. }
  1266. if(lastOut.type == STYLE.SHUNZI ){
  1267. //上家出顺子的话把自己手上能大过的顺子加入提示数组
  1268. // console.warn("上家出顺子的话把自己手上能大过的顺子加入提示数组");
  1269. let isExitBiger = false;//是否存在更大的
  1270. for (var i = 0; i < szpz.length; i++) {
  1271. if(szpz[i].length == lastOut.cards.length){
  1272. if(parseInt(szpz[i][0]) > this.getValuepx(lastOut.cards[0])){
  1273. isExitBiger = true;
  1274. break;
  1275. }
  1276. }
  1277. }
  1278. // console.warn("shifou有现成的能大过的提示数组 "+isExitBiger+" szpz "+JSON.stringify(szpz));
  1279. if(!isExitBiger){
  1280. //上面的写法是只提示出来一个最小的能大的过的顺子,下面是提示出来所有能大得过的顺子
  1281. for (var i = 0; i < szpz.length; i++) {
  1282. if(szpz[i].length >= lastOut.cards.length){
  1283. // console.warn("看看自己顺子的最大值能否大过别人出的顺子的最大值 ",parseInt(szpz[i][szpz[i].length-1]) , this.getValuepx(lastOut.cards[lastOut.cards.length-1]));
  1284. if(parseInt(szpz[i][szpz[i].length-1]) > this.getValuepx(lastOut.cards[lastOut.cards.length-1])){
  1285. let minIndex = -1;
  1286. for (var jj = 0; jj < szpz[i].length; jj++) {
  1287. if(parseInt(szpz[i][jj]) > this.getValuepx(lastOut.cards[0])){
  1288. minIndex = jj;
  1289. // minIndex2 = jj;
  1290. break;
  1291. }
  1292. }
  1293. // console.warn("找大的过的顺子 "+minIndex+" "+szpz[i].length +" "+ (minIndex+lastOut.cards.length));
  1294. if(minIndex > -1){
  1295. //提示一个能大得过的最小顺子
  1296. if(szpz[i].length < minIndex+lastOut.cards.length){
  1297. break;//手上的大的过的顺子不够长
  1298. }
  1299. let geshu = szpz[i].length - minIndex-lastOut.cards.length
  1300. for (var z = 0; z <= geshu; z++) {
  1301. // console.warn("找大的过的顺子 "+minIndex+" "+szpz[i].length +" "+ geshu);
  1302. let newbigger = [];
  1303. for (var j = minIndex; j < minIndex+lastOut.cards.length; j++) {
  1304. newbigger[newbigger.length] = ng[szpz[i][j]][0];
  1305. }
  1306. // console.warn("加入大的过的顺子 "+JSON.stringify(newbigger));
  1307. szTip[szTip.length] = newbigger;
  1308. minIndex++;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. }
  1314. }
  1315. else{
  1316. //有现成的能大过的提示数组,再把更长的顺子拆开的能大的过的进行提示
  1317. for (var i = 0; i < szpz.length; i++) {
  1318. let isNeedPD = true;
  1319. if(szpz[i].length == lastOut.cards.length){
  1320. if(parseInt(szpz[i][0]) > this.getValuepx(lastOut.cards[0])){
  1321. isNeedPD = false;
  1322. break;
  1323. }
  1324. }
  1325. if(isNeedPD){
  1326. if(szpz[i].length >= lastOut.cards.length){
  1327. // console.warn("看看自己顺子的最大值能否大过别人出的顺子的最大值 ",parseInt(szpz[i][szpz[i].length-1]) , this.getValuepx(lastOut.cards[lastOut.cards.length-1]));
  1328. if(parseInt(szpz[i][szpz[i].length-1]) > this.getValuepx(lastOut.cards[lastOut.cards.length-1])){
  1329. let minIndex = -1;
  1330. for (var jj = 0; jj < szpz[i].length; jj++) {
  1331. if(parseInt(szpz[i][jj]) > this.getValuepx(lastOut.cards[0])){
  1332. minIndex = jj;
  1333. // minIndex2 = jj;
  1334. break;
  1335. }
  1336. }
  1337. // console.warn("找大的过的顺子 "+minIndex+" "+szpz[i].length +" "+ (minIndex+lastOut.cards.length));
  1338. if(minIndex > -1){
  1339. //提示一个能大得过的最小顺子
  1340. if(szpz[i].length < minIndex+lastOut.cards.length){
  1341. break;//手上的大的过的顺子不够长
  1342. }
  1343. let geshu = szpz[i].length - minIndex-lastOut.cards.length
  1344. for (var z = 0; z <= geshu; z++) {
  1345. // console.warn("找大的过的顺子 "+minIndex+" "+szpz[i].length +" "+ geshu);
  1346. let newbigger = [];
  1347. for (var j = minIndex; j < minIndex+lastOut.cards.length; j++) {
  1348. newbigger[newbigger.length] = ng[szpz[i][j]][0];
  1349. }
  1350. // console.warn("加入大的过的顺子 "+JSON.stringify(newbigger));
  1351. szTip[szTip.length] = newbigger;
  1352. minIndex++;
  1353. }
  1354. }
  1355. }
  1356. }
  1357. }
  1358. }
  1359. }
  1360. }
  1361. // console.warn("出牌提示 顺子牌值2 "+JSON.stringify(szTip) );
  1362. tipAllKind[tipAllKind.length] = {
  1363. type: STYLE.SHUNZI,
  1364. tipCards: szTip
  1365. };
  1366. }
  1367. // let isKeSidai = false;
  1368. if(!this.isZDBKC && pzfbqk.indexOf(4) != -1){
  1369. //可四带
  1370. let sdTip = [];
  1371. let sdPaiZhi = [];
  1372. if(this.isCanSiDaiEr || this.isSiCanDaiSan){
  1373. for (var i = 0; i < vgs.length; i++) {
  1374. if(vgs[i].length == 4){
  1375. sdTip[sdTip.length] = vgs[i];
  1376. sdPaiZhi = sdPaiZhi.concat(vgs[i]);
  1377. }
  1378. }
  1379. }
  1380. // console.warn("出牌提示 四带 "+JSON.stringify(sdTip)+" 四带牌值 "+JSON.stringify(sdPaiZhi) );
  1381. if(sdTip.length > 0){
  1382. let sdeTip = [];
  1383. let kedais = [];
  1384. for (var i = 0; i < handCards.length; i++) {
  1385. if(sdPaiZhi.indexOf(handCards[i]) == -1) kedais[kedais.length] = handCards[i];
  1386. if(kedais.length >= 3) break
  1387. }
  1388. if(this.isCanSiDaiEr){
  1389. if(spCount >= 6){
  1390. let dd = [kedais[0],kedais[1]]
  1391. for (var i = 0; i < sdTip.length; i++) {
  1392. sdeTip[i] = sdTip[i].concat(dd);
  1393. }
  1394. }
  1395. else{
  1396. if(isblFirst){
  1397. for (var i = 0; i < sdTip.length; i++) {
  1398. sdeTip[i] = sdTip[i].concat(kedais);
  1399. }
  1400. }
  1401. }
  1402. // console.warn("出牌提示 四带2 "+JSON.stringify(sdeTip) );
  1403. tipAllKind[tipAllKind.length] = {
  1404. type: STYLE.SIDAIER,
  1405. tipCards: sdeTip
  1406. };
  1407. }
  1408. if(this.isSiCanDaiSan){
  1409. let sdsTip = [];
  1410. if(spCount >= 7){
  1411. for (var i = 0; i < sdTip.length; i++) {
  1412. sdsTip[i] = sdTip[i].concat(kedais);
  1413. }
  1414. }
  1415. else{
  1416. if(isblFirst){
  1417. for (var i = 0; i < sdTip.length; i++) {
  1418. sdsTip[i] = sdTip[i].concat(kedais);
  1419. }
  1420. }
  1421. }
  1422. // console.warn("出牌提示 四带3 "+JSON.stringify(sdsTip) );
  1423. tipAllKind[tipAllKind.length] = {
  1424. type: STYLE.SIDAISAN,
  1425. tipCards: sdsTip
  1426. };
  1427. }
  1428. // console.warn("出牌提示 四带22 "+JSON.stringify(sdTip)+" 四带牌值 "+JSON.stringify(sdPaiZhi) );
  1429. }
  1430. }
  1431. if(pzfbqk.indexOf(3) != -1 || (!this.isZDBKC && pzfbqk.indexOf(4) != -1)){
  1432. let sidPaiZhi = [];//手上的炸弹牌,炸弹不可拆时带牌不能带炸弹
  1433. if(this.isZDBKC && pzfbqk.indexOf(4) != -1){
  1434. for (var i = 0; i < vgs.length; i++) {
  1435. if(vgs[i].length == 4){
  1436. sidPaiZhi = sidPaiZhi.concat(vgs[i]);
  1437. }
  1438. }
  1439. }
  1440. //可三带
  1441. let sdTip = [];
  1442. let sdPaiZhi = [];
  1443. // let ydz = [];
  1444. for (var i = 0; i < vgs.length; i++) {
  1445. // if(vgs[i].length == 2){
  1446. // ydz[ydz.length] = vgs[i];
  1447. // }
  1448. if(vgs[i].length == 3){
  1449. sdTip[sdTip.length] = vgs[i];
  1450. sdPaiZhi = sdPaiZhi.concat([this.getValuepx(vgs[i][0])]);
  1451. // ydz[ydz.length] = [vgs[0],vgs[1]];
  1452. }
  1453. if(!this.isZDBKC && vgs[i].length == 4){
  1454. sdTip[sdTip.length] = [vgs[i][0],vgs[i][1],vgs[i][2]];
  1455. sdPaiZhi = sdPaiZhi.concat([this.getValuepx(vgs[i][0])]);
  1456. // ydz[ydz.length] = [vgs[0],vgs[1]];
  1457. }
  1458. }
  1459. // console.warn("出牌提示 三带 "+JSON.stringify(sdTip)+" 三带牌值 "+JSON.stringify(sdPaiZhi)+" 四带牌值 "+JSON.stringify(sidPaiZhi) );
  1460. if(sdTip.length > 0){
  1461. let sdeTip = [];
  1462. let kedais = [];
  1463. for (var i = 0; i < handCards.length; i++) {
  1464. // console.warn("出牌提示 ?? "+handCards[i]+ " v "+this.getValuepx(handCards[i])+" 三带牌值 "+JSON.stringify(sdPaiZhi) );
  1465. // if(sdPaiZhi.indexOf(this.getValuepx(handCards[i])) == -1) kedais[kedais.length] = handCards[i];
  1466. let iskd = true;
  1467. for (var j = 0; j < sdTip.length; j++) {
  1468. // console.warn("出牌提示 三带 j "+j+" 三带牌值 "+JSON.stringify(sdTip)+" 四带牌值 "+JSON.stringify(sidPaiZhi)+" handCards[i] "+handCards[i] );
  1469. if(sdTip[j].indexOf(handCards[i]) != -1){
  1470. iskd = false;
  1471. break;
  1472. }
  1473. if(this.isZDBKC && sidPaiZhi.indexOf(handCards[i]) != -1){
  1474. // 炸弹不可拆时带牌不能带炸弹
  1475. iskd = false;
  1476. break;
  1477. }
  1478. }
  1479. if(iskd) kedais[kedais.length] = handCards[i];
  1480. if(kedais.length >= 2) break;
  1481. }
  1482. // console.warn("出牌提示 三带可带牌 "+JSON.stringify(kedais))
  1483. if(spCount == 3){
  1484. if(lastOut.type == -1 && lastOut.cards.length == 0){
  1485. if(sdTip.length == 1){
  1486. // 打到最后剩3张牌的时候,才可以3不带;
  1487. let sdyTip = [];
  1488. sdyTip[0] = sdTip[0].concat(kedais);
  1489. tipAllKind[tipAllKind.length] = {
  1490. type: STYLE.SANDAIYI,
  1491. tipCards: sdyTip
  1492. };
  1493. }
  1494. }
  1495. }
  1496. else if(spCount == 4){
  1497. if(lastOut.type == -1 && lastOut.cards.length == 0){
  1498. // 打到最后剩4张牌的时候,才可以3带1;
  1499. if(sdTip.length == 1){
  1500. let sdyTip = [];
  1501. for (var i = 0; i < handCards.length; i++) {
  1502. if(sdTip[0].indexOf(handCards[i]) == -1){
  1503. kedais = [handCards[i]];
  1504. break;
  1505. }
  1506. }
  1507. sdyTip[0] = sdTip[0].concat(kedais);
  1508. tipAllKind[tipAllKind.length] = {
  1509. type: STYLE.SANDAIYI,
  1510. tipCards: sdyTip
  1511. };
  1512. }
  1513. }
  1514. }
  1515. else if(spCount > 4){
  1516. // console.warn("出牌提示 牌够 三带可带牌 "+JSON.stringify(kedais))
  1517. if(kedais.length == 2){
  1518. sdeTip = [];
  1519. for (var i = 0; i < sdTip.length; i++) {
  1520. sdeTip[i] = sdTip[i].concat(kedais);
  1521. }
  1522. tipAllKind[tipAllKind.length] = {
  1523. type: STYLE.SANDAIER,
  1524. tipCards: sdeTip
  1525. };
  1526. // console.warn("出牌提示 牌够 三带1 "+JSON.stringify(sdeTip)+" 三带2 "+JSON.stringify(sdeTip) );
  1527. }
  1528. else if(kedais.length == 1){
  1529. for (var i = 0; i < sdTip.length; i++) {
  1530. for (var j = 0; j < handCards.length; j++) {
  1531. if(sdTip[i].indexOf(handCards[j]) == -1){
  1532. if(kedais.indexOf(handCards[j]) == -1) kedais[1] = handCards[j];
  1533. if(kedais.length >= 2) break;
  1534. }
  1535. }
  1536. if(kedais.length == 2) {
  1537. sdeTip[i] = sdTip[i].concat(kedais);
  1538. }
  1539. }
  1540. tipAllKind[tipAllKind.length] = {
  1541. type: STYLE.SANDAIER,
  1542. tipCards: sdeTip
  1543. };
  1544. }
  1545. else if(kedais.length == 0){
  1546. sdeTip = [];
  1547. for (var i = 0; i < sdTip.length; i++) {
  1548. kedais = [];
  1549. for (var j = 0; j < handCards.length; j++) {
  1550. if(sdTip[i].indexOf(handCards[j]) == -1){
  1551. kedais[kedais.length] = handCards[j];
  1552. if(kedais.length >= 2) break;
  1553. }
  1554. }
  1555. if(kedais.length == 2) sdeTip[i] = sdTip[i].concat(kedais);
  1556. }
  1557. tipAllKind[tipAllKind.length] = {
  1558. type: STYLE.SANDAIER,
  1559. tipCards: sdeTip
  1560. };
  1561. // console.warn("出牌提示 牌够 三带1 "+JSON.stringify(sdeTip)+" 三带2 "+JSON.stringify(sdeTip) );
  1562. }
  1563. }
  1564. }
  1565. }
  1566. let duiziList = [];
  1567. for (var i = 0; i < vgs.length; i++) {
  1568. if(vgs[i].length == 2 || vgs[i].length == 3) duiziList[duiziList.length] = [vgs[i][0],vgs[i][1]];
  1569. if(!this.isZDBKC && vgs[i].length == 4) duiziList[duiziList.length] = [vgs[i][0],vgs[i][1]];
  1570. }
  1571. // console.warn("出牌提示 对子list "+JSON.stringify(duiziList));
  1572. if(duiziList.length >= 2){
  1573. let lianduiList = [];
  1574. let pdz = this.getValuepx(duiziList[0][0]);
  1575. let pdIndex = 0;
  1576. lianduiList[0] = [duiziList[0]];
  1577. // console.warn("出牌提示 连对list "+JSON.stringify(lianduiList));
  1578. for (var i = 1; i < duiziList.length; i++) {
  1579. if((pdz+i-pdIndex) == this.getValuepx(duiziList[i][0])){
  1580. let lianduiListLastItemIndex = lianduiList.length-1;
  1581. let lianduiListLastItemLastIndex = lianduiList[lianduiList.length-1].length;
  1582. lianduiList[lianduiListLastItemIndex][lianduiListLastItemLastIndex] = duiziList[i];
  1583. }
  1584. else{
  1585. // console.warn("出牌提示 连对到这里了嘛222 "+JSON.stringify(duiziList[i]));
  1586. lianduiList[lianduiList.length] = [];
  1587. lianduiList[lianduiList.length-1] = [duiziList[i]];
  1588. pdz = this.getValuepx(duiziList[i][0]);
  1589. pdIndex = i;
  1590. }
  1591. }
  1592. // console.warn("出牌提示 连对list "+JSON.stringify(lianduiList));
  1593. let lianduiTip = [];
  1594. for (var i = 0; i < lianduiList.length; i++) {
  1595. if(lianduiList[i].length >= 2){
  1596. let lds = [];
  1597. for (var j = 0; j < lianduiList[i].length; j++) {
  1598. lds = lds.concat(lianduiList[i][j])
  1599. }
  1600. lianduiTip[lianduiTip.length] = lds;
  1601. }
  1602. }
  1603. // console.warn("出牌提示 连对结果 "+JSON.stringify(lianduiTip));
  1604. if(lastOut.type == STYLE.LIANDUI ){
  1605. //上家出连对的话把自己手上能大过的连对加入提示数组
  1606. let isExitBiger = false;//是否存在更大的
  1607. for (var i = 0; i < lianduiTip.length; i++) {
  1608. if(lianduiTip[i].length == lastOut.cards.length){
  1609. if(this.getValuepx(lianduiTip[i][0]) > this.getValuepx(lastOut.cards[0])){
  1610. isExitBiger = true;
  1611. break;
  1612. }
  1613. }
  1614. }
  1615. if(!isExitBiger){
  1616. for (var i = 0; i < lianduiTip.length; i++) {
  1617. if(this.getValuepx(lianduiTip[i][lianduiTip[i].length-1]) > this.getValuepx(lastOut.cards[lastOut.cards.length-1])){
  1618. isExitBiger = true;
  1619. break;
  1620. }
  1621. }
  1622. if(isExitBiger){
  1623. let add3 = [];
  1624. for (var i = 0; i < lianduiTip.length; i++) {
  1625. let add2 = [];
  1626. for (var j = 0; j < lianduiTip[i].length; j++) {
  1627. // console.warn("上家出连对的话??? "+JSON.stringify(lianduiTip)+" "+JSON.stringify(add3)+" "+JSON.stringify(add2)+" "+add2[add2.length-1] +" "+ lianduiTip[i][j]);
  1628. if(add2.length > 0 && this.getValuepx(add2[add2.length-1]) > this.getValuepx(lianduiTip[i][j])) continue;
  1629. if(this.getValuepx(lianduiTip[i][j]) > this.getValuepx(lastOut.cards[0])){
  1630. let isslg = (lianduiTip[i].length - j) >= lastOut.cards.length;//张数够不够
  1631. // console.warn("数量够不够 "+lianduiTip[i].length+" "+lastOut.cards.length+" i "+i+" j "+j);
  1632. if(isslg){
  1633. let add = [];
  1634. for (var z = 0; z < lastOut.cards.length; z++) {
  1635. add[add.length] = lianduiTip[i][j+z]
  1636. }
  1637. // console.warn("上家出连对的话把自己手上能大过的连对加入提示数组 "+JSON.stringify(add));
  1638. add3[add3.length] = add;
  1639. add2 = add;
  1640. }
  1641. else{
  1642. break;
  1643. }
  1644. }
  1645. }
  1646. }
  1647. let add4 = [];
  1648. for (var i = 0; i < add3.length; i++) {
  1649. if(this.getIsHanBaozi(add3[i],vgs)) add4[add4.length] = add3[i];
  1650. else lianduiTip[lianduiTip.length] = add3[i];
  1651. }
  1652. for (var i = 0; i < add4.length; i++) {
  1653. lianduiTip[lianduiTip.length] = add4[i];
  1654. }
  1655. }
  1656. }
  1657. }
  1658. // console.warn("上家出连对的话 lianduiTip "+JSON.stringify(lianduiTip));
  1659. if(lianduiTip.length > 0){
  1660. tipAllKind[tipAllKind.length] = {
  1661. type: STYLE.LIANDUI,
  1662. tipCards: lianduiTip
  1663. };
  1664. }
  1665. }
  1666. if(pzfbqk.indexOf(4) != -1){
  1667. let zhadanTip = [];
  1668. for (var i = 0; i < vgs.length; i++) {
  1669. if(vgs[i].length == 4){
  1670. zhadanTip[zhadanTip.length] = vgs[i];
  1671. }
  1672. }
  1673. // console.warn("出牌提示 炸弹结果 "+JSON.stringify(zhadanTip));
  1674. if(zhadanTip.length > 0){
  1675. tipAllKind[tipAllKind.length] = {
  1676. type: STYLE.ZHADAN,
  1677. tipCards: zhadanTip
  1678. };
  1679. }
  1680. }
  1681. if(duiziList.length > 0){
  1682. let duiziTip = [];
  1683. let add4 = [];
  1684. for (var i = 0; i < duiziList.length; i++) {
  1685. if(this.getIsHanBaozi(duiziList[i],vgs)) add4[add4.length] = duiziList[i];
  1686. else duiziTip[duiziTip.length] = duiziList[i];
  1687. }
  1688. for (var i = 0; i < add4.length; i++) {
  1689. duiziTip[duiziTip.length] = add4[i];
  1690. }
  1691. if(duiziTip.length > 0){
  1692. tipAllKind[tipAllKind.length] = {
  1693. type: STYLE.YIDUI,
  1694. tipCards: duiziTip
  1695. };
  1696. }
  1697. }
  1698. let danTip = [];
  1699. let hsisExit = false;
  1700. for (var i = 0; i < vgs.length; i++) {
  1701. if(vgs[i].length == 1){
  1702. danTip[danTip.length] = vgs[i];
  1703. if(vgs[i][0] == 103) hsisExit = true;
  1704. }
  1705. }
  1706. if(isHTSSC && (!hsisExit)){
  1707. if(handCards.indexOf(103) != -1){//加这个判断是为了防止在首局黑桃三出牌之后判断第二家能否要起的时候把103添加给第二家的出牌提示
  1708. danTip[danTip.length] = [103];
  1709. }
  1710. }
  1711. if(lastOut.cards.length == 1){
  1712. if(danTip[danTip.length-1] != handCards[handCards.length-1]){
  1713. danTip[danTip.length] = [handCards[handCards.length-1]];
  1714. }
  1715. }
  1716. if(isXJZSYZ){
  1717. //下家只剩一张牌了
  1718. let maxDanList = this.getMaxDanList(handCards);
  1719. danTip = [];
  1720. danTip[danTip.length] = [maxDanList[0]];
  1721. }
  1722. // console.warn("出牌提示 单牌结果 "+JSON.stringify(danTip));
  1723. if(danTip.length > 0){
  1724. tipAllKind[tipAllKind.length] = {
  1725. type: STYLE.DAN,
  1726. tipCards: danTip
  1727. };
  1728. }
  1729. // console.warn("出牌提示 所有结果111 "+JSON.stringify(tipAllKind));
  1730. this.getKeDaisSort2(handCards,tipAllKind,vgs,isHTSSC);
  1731. // console.warn("出牌提示 所有结果优化之后 "+JSON.stringify(tipAllKind));
  1732. let tipAllKindtip = [];
  1733. for (var i = 0; i < tipAllKind.length; i++) {
  1734. for (var j = 0; j < tipAllKind[i].tipCards.length; j++) {
  1735. tipAllKindtip[tipAllKindtip.length] = tipAllKind[i].tipCards[j];
  1736. }
  1737. }
  1738. // console.warn("出牌提示 所有结果2 "+JSON.stringify(tipAllKindtip));
  1739. let glzh = [];
  1740. for (var i = 16; i >= 0; i--) {
  1741. glzh[i] = [];
  1742. }
  1743. // console.warn("出牌提示 所有结果3 "+JSON.stringify(glzh));
  1744. for (var i = 0; i < tipAllKindtip.length; i++) {
  1745. let index1 = tipAllKindtip[i].length;
  1746. let index2 = glzh[index1].length;
  1747. glzh[index1][index2] = tipAllKindtip[i];
  1748. }
  1749. // console.warn("出牌提示 所有结果4 "+JSON.stringify(glzh));
  1750. let tipAllKindSorted = [];
  1751. for (var i = 16; i >= 0; i--) {
  1752. if(glzh[i].length > 0){
  1753. for (var j = 0; j < glzh[i].length; j++) {
  1754. tipAllKindSorted[tipAllKindSorted.length] = glzh[i][j];
  1755. }
  1756. }
  1757. }
  1758. // console.warn("出牌提示 所有结果222 "+JSON.stringify(tipAllKind));
  1759. // console.warn("出牌提示 所有结果333 "+JSON.stringify(tipAllKindSorted));
  1760. // tipRes = tipAllKindSorted;
  1761. if(isHTSSC){
  1762. //黑桃三首出,出牌必须有黑桃三
  1763. for (var i = 0; i < tipAllKindSorted.length; i++) {
  1764. if(tipAllKindSorted[i].indexOf(103) != -1){
  1765. tipRes[tipRes.length] = tipAllKindSorted[i];
  1766. }
  1767. }
  1768. }
  1769. else{
  1770. if(lastOut.type == -1 && lastOut.cards.length == 0){
  1771. //本轮第一个出牌的玩家
  1772. tipRes = tipAllKindSorted;
  1773. }
  1774. else{
  1775. let needCompareList = [];
  1776. for (var i = 0; i < tipAllKind.length; i++) {
  1777. if(tipAllKind[i].type == lastOut.type){
  1778. needCompareList = needCompareList.concat(tipAllKind[i].tipCards);
  1779. }
  1780. }
  1781. for (var i = 0; i < tipAllKind.length; i++) {
  1782. if(tipAllKind[i].type == STYLE.ZHADAN){
  1783. needCompareList = needCompareList.concat(tipAllKind[i].tipCards);
  1784. }
  1785. }
  1786. // console.warn("出牌提示 去掉大不过上家的提示出牌 "+JSON.stringify(needCompareList));
  1787. for (var i = 0; i < needCompareList.length; i++) {
  1788. let outType = this.getCardsType(needCompareList[i],lastOut,handCards,isHTSSC,[]);
  1789. // console.warn("出牌提示 是否能大过 ",JSON.stringify(needCompareList[i]),outType,lastOut.type,STYLE.ZHADAN)
  1790. if(outType == lastOut.type || outType == STYLE.ZHADAN){
  1791. // console.warn("能大过 ",JSON.stringify(needCompareList[i]))
  1792. tipRes[tipRes.length] = needCompareList[i];
  1793. }
  1794. }
  1795. }
  1796. }
  1797. // console.error("出牌提示 最终的返回结果 "+JSON.stringify(tipRes));
  1798. let tipRes22 = [];////最终返回结果
  1799. for (var i = 0; i < tipRes.length; i++) {
  1800. if(!this.checkZhaDan(tipRes[i])) tipRes22.push(tipRes[i]);
  1801. // else console.warn("这个被剔除了",tipRes[i]);
  1802. }
  1803. return tipRes22;
  1804. };
  1805. //得到一组牌里面是否有炸弹,为了解决炸弹+单牌这五张牌当三带2提示出去
  1806. proto.checkZhaDan = function (cards) {
  1807. if(cards.length != 5) return null;
  1808. let tipItem = _.clone(cards);
  1809. tipItem = this.sort(tipItem);
  1810. for (var i = 0; i < tipItem.length; i++) {
  1811. tipItem[i] = this.getValue(tipItem[i])
  1812. }
  1813. if(tipItem[0] == tipItem[1] && tipItem[0] == tipItem[2] && tipItem[0] == tipItem[3]) return true;
  1814. else if(tipItem[1] == tipItem[2] && tipItem[1] == tipItem[3] && tipItem[1] == tipItem[4]) return true;
  1815. return false;
  1816. }
  1817. //得到能否一把出完的牌,如果能出完返回出牌李彪,如果不能一把出完返回[]
  1818. proto.getCanOutOverList = function (currentId,_handCards,tipInfo,lastOut) {
  1819. // console.warn("得到能否一把出完的牌 "+currentId+" "+JSON.stringify(_handCards)+" "+JSON.stringify(tipInfo)+" "+JSON.stringify(lastOut));
  1820. if(currentId != tipInfo.chairId || tipInfo.chairId < 0) return [];
  1821. let handCards = this.deepCloneTL(_handCards);
  1822. let pzfbqk = this.getPokeValueArr(handCards);//牌值分布情况
  1823. // console.warn("得到能否一把出完的牌 牌值分布情况 "+ JSON.stringify(pzfbqk))
  1824. if(pzfbqk.indexOf(4) != -1){
  1825. if(handCards.length > 4) return [];//手上有炸弹的话不能自动打出,需要玩家选择
  1826. else if(handCards.length == 4) return handCards;//手上只剩一个炸弹了让他自己打出去
  1827. }
  1828. let res = [];
  1829. for (var i = 0; i < tipInfo.tipCards.length; i++) {
  1830. if(tipInfo.tipCards[i].length == handCards.length){
  1831. let lygdys = _.difference(tipInfo.tipCards[i],handCards);////另一个队员的人数
  1832. let lygdys2 = _.difference(handCards,tipInfo.tipCards[i]);////另一个队员的人数
  1833. if(lygdys.length == 0 && lygdys2.length == 0){
  1834. res = tipInfo.tipCards[i];
  1835. // console.warn("得到能否一把出完的牌 找到了 "+JSON.stringify(res));
  1836. break;
  1837. }
  1838. }
  1839. }
  1840. // console.warn("得到能否一把出完的牌 返回值 "+JSON.stringify(res));
  1841. return res;
  1842. }
  1843. //得到出牌是否合法和所出牌的牌型 出牌数组 上家出牌 自己手牌 是否是黑桃三首出
  1844. proto.getCardsType = function (_outCards,lastOut,_sp,isHTSSC,tips) {
  1845. // console.error("得到出牌是否合法和所出牌的牌型 出牌数组 "+_outCards+" 上家出牌数组 "+JSON.stringify(lastOut) +" 自己手牌"+JSON.stringify(_sp));
  1846. let outCards = this.deepCloneTL(_outCards)
  1847. outCards = this.sort(outCards)
  1848. let sp = this.deepCloneTL(_sp)
  1849. let spCount = sp.length;
  1850. let type = -1;
  1851. for (var i = 0; i < outCards.length; i++) {
  1852. if(!this.aCardIsHefa(outCards[i])) return -1;//出牌中包含非法牌
  1853. }
  1854. //至此出牌数组中每张牌都是合法的
  1855. let outLength = outCards.length;
  1856. if(outLength == 0){
  1857. //要不起
  1858. if(lastOut.type == -1 && lastOut.cards.length == 0) return STYLE.ERROR;//本轮第一个出牌的玩家不能不出牌(出[])
  1859. else{
  1860. if(this.isYPBC && tips.length > 0) return -2;
  1861. }
  1862. type = STYLE.YAOBUQI;
  1863. }
  1864. else if(outLength > 0){
  1865. if(isHTSSC && outCards.indexOf(103) == -1) return -3;//黑桃三首出所出的牌没有黑桃三
  1866. let pzfbqk = this.getPokeValueArr(outCards);//牌值分布情况
  1867. // console.warn("牌值分布情况 "+JSON.stringify(pzfbqk)+" 炸弹是否不可拆 "+this.isZDBKC);
  1868. if(this.isZDBKC){
  1869. if(this.isZhaDan(outCards,pzfbqk,lastOut,spCount) == STYLE.ZHADAN) return STYLE.ZHADAN;
  1870. var ng = _.groupBy(sp, function (n) {
  1871. let value = n % 100;
  1872. if(value == 1) value = 14;
  1873. if(value == 2) value = 15;
  1874. return value;
  1875. });
  1876. // console.warn("222出牌提示 ",JSON.stringify(ng));
  1877. var kgs = Object.keys(ng);
  1878. // console.warn("出牌提示根据牌返回牌值的个数333 kgs "+JSON.stringify(kgs));
  1879. let vgs = _.sortBy(ng, function(o) {
  1880. let value = o[0] % 100;
  1881. if(value == 1) value = 14;
  1882. if(value == 2) value = 15;
  1883. return value;
  1884. });
  1885. let bkcxdpz = [];//炸弹不可拆时出牌里不能出现的牌值
  1886. for (var i = 0; i < vgs.length; i++) {
  1887. if(vgs[i].length == 4 ) bkcxdpz[bkcxdpz.length] = this.getValuepx(vgs[i][0]);
  1888. }
  1889. // console.warn("下面是判断牌型 炸弹不可拆时出牌里不能出现的牌值 "+JSON.stringify(bkcxdpz) )
  1890. for (var i = 0; i < outCards.length; i++) {
  1891. // console.warn("下面是判断牌型 炸弹不可拆时出牌里不能出现的牌值 "+outCards[i]+" "+this.getValuepx(outCards[i]) )
  1892. if( bkcxdpz.indexOf(this.getValuepx(outCards[i])) != -1){
  1893. // console.warn("走到这里了????? ");
  1894. return -4;//炸弹不可拆时出的牌不能带炸弹
  1895. }
  1896. }
  1897. }
  1898. // console.warn("下面是判断牌型 出牌牌值 "+JSON.stringify(outCards) +" 分布情况 "+JSON.stringify(pzfbqk)+" last "+JSON.stringify(lastOut)+" spCount "+JSON.stringify(spCount));
  1899. // 出牌牌值 103,403,104,404,105,106,107,108 分布情况 1,1,1,1,2,2
  1900. for (var i = 0; i < this.dahuTypeTL.length; i++) {
  1901. // console.warn("判断type ==== === i "+i+" type "+type);
  1902. if( i == 3 && type < 3){
  1903. type = this.isDan(outCards,pzfbqk,lastOut,spCount);
  1904. }
  1905. else if( i == 4 && type < 3){
  1906. type = this.isYiDui(outCards,pzfbqk,lastOut,spCount);
  1907. }
  1908. else if( i == 5 && type < 3){
  1909. type = this.isLianDui(outCards,pzfbqk,lastOut,spCount);
  1910. }
  1911. else if( i == 6 && type < 3){
  1912. type = this.isSanDaiYi(outCards,pzfbqk,lastOut,spCount);
  1913. }
  1914. else if( i == 7 && type < 3){
  1915. type = this.isSanDaiEr(outCards,pzfbqk,lastOut,spCount);
  1916. }
  1917. else if( i == 8 && type < 3){
  1918. type = this.isSiDaiEr(outCards,pzfbqk,lastOut,spCount);
  1919. }
  1920. else if( i == 9 && type < 3){
  1921. type = this.isSiDaiSan(outCards,pzfbqk,lastOut,spCount);
  1922. }
  1923. else if( i == 10 && type < 3){
  1924. type = this.isFeiJi(outCards,pzfbqk,lastOut,spCount);
  1925. }
  1926. else if( i == 11 && type < 3){
  1927. type = this.isShunZi(outCards,pzfbqk,lastOut,spCount);
  1928. }
  1929. else if( i == 12 && type < 3){
  1930. type = this.isZhaDan(outCards,pzfbqk,lastOut,spCount);
  1931. }
  1932. }
  1933. }
  1934. // console.error("得到出牌是否合法和所出牌的牌型 结束 " + type);
  1935. return type
  1936. }
  1937. // 是否单牌 出的牌,牌值分布情况,上家有效出牌,手牌个数
  1938. proto.isDan = function (outCards,pzfbqk,lastOut,spCount) {
  1939. if(lastOut.cards.length > 0 && lastOut.type != STYLE.DAN) return STYLE.NULL;//别人出的不是单牌自己不能出单牌
  1940. if(outCards.length != 1) return STYLE.ERROR;
  1941. if(lastOut.cards.length > 0){
  1942. if(this.getValuepx(outCards[0]) > this.getValuepx(lastOut.cards[0])) return STYLE.DAN;
  1943. else return STYLE.NULL;
  1944. }
  1945. return STYLE.DAN;
  1946. }
  1947. // 是否一对子 出的牌,牌值分布情况,上家有效出牌,手牌个数
  1948. proto.isYiDui = function (outCards,pzfbqk,lastOut,spCount) {
  1949. if(lastOut.cards.length > 0 && lastOut.type != STYLE.YIDUI) return STYLE.NULL;//别人出的不是一对子自己不能出一对子
  1950. if(outCards.length != 2) return STYLE.ERROR;
  1951. if(this.getValuepx(outCards[0]) == this.getValuepx(outCards[1])){
  1952. if(lastOut.cards.length > 0){
  1953. if(this.getValuepx(outCards[0]) > this.getValuepx(lastOut.cards[0])) return STYLE.YIDUI;
  1954. else return STYLE.NULL;
  1955. }
  1956. }
  1957. else return STYLE.ERROR;
  1958. return STYLE.YIDUI;
  1959. }
  1960. // 是否连对 出的牌,牌值分布情况,上家有效出牌,手牌个数
  1961. proto.isLianDui = function (outCards,pzfbqk,lastOut,spCount) {
  1962. if(lastOut.cards.length > 0 && lastOut.type != STYLE.LIANDUI) return STYLE.NULL;//别人出的不是连对自己不能出连对
  1963. if(outCards.length < 4) return STYLE.ERROR;
  1964. if(outCards.length % 2 != 0) return STYLE.ERROR;//出的张数不是偶数
  1965. if(pzfbqk.length != outCards.length / 2) return STYLE.ERROR;//出的不全是对子
  1966. let isAllDuizi = true;
  1967. for (var i = 0; i < pzfbqk.length; i++) {
  1968. if(pzfbqk[i] != 2){
  1969. isAllDuizi = false;
  1970. break;
  1971. }
  1972. }
  1973. if(isAllDuizi){
  1974. let qc = [];
  1975. for (var i = 0; i < outCards.length; i++) {
  1976. qc[qc.length] = outCards[i];
  1977. i++
  1978. }
  1979. // console.warn("连对判断 111 "+JSON.stringify(outCards)+" "+JSON.stringify(lastOut.cards));
  1980. // console.warn("连对判断 222 "+JSON.stringify(qc));
  1981. for (var i = 1; i < qc.length; i++) {
  1982. if(this.getValuepx(qc[i]) == 15) return STYLE.ERROR;//牌面数值2(逻辑牌值15)不能去做顺子
  1983. if(this.getValuepx(qc[i]) != this.getValuepx(qc[0])+i){
  1984. return STYLE.ERROR;
  1985. }
  1986. }
  1987. }
  1988. else return STYLE.ERROR;
  1989. // console.warn("连对判断 至此出的牌是个合法的连对了 "+JSON.stringify(outCards)+" "+JSON.stringify(lastOut.cards));
  1990. //至此出的牌是个合法的连对了
  1991. if(lastOut.cards.length > 0){
  1992. if(outCards.length != lastOut.cards.length){
  1993. //本次出牌牌数和上次出牌数不一样,不能压
  1994. return STYLE.NULL;
  1995. }
  1996. else{
  1997. if(this.getValuepx(outCards[0]) <= this.getValuepx(lastOut.cards[0])){
  1998. //张数一样点数不够大的连对压不住
  1999. return STYLE.NULL;
  2000. }
  2001. }
  2002. }
  2003. return STYLE.LIANDUI;
  2004. }
  2005. //按照牌面值出现个数对手牌数组进行排序
  2006. proto.sortOut = function (_outs) {
  2007. let outs = this.deepCloneTL(_outs);
  2008. // return _.sortBy(handCards);///降序排序
  2009. // console.warn("111按照牌面值出现个数对除牌数组进行排序",JSON.stringify(outs));
  2010. // 111手牌排序 [101,102,103,104,105,106,107,108,109,110,111,112,113,403,404,201]
  2011. var ng = _.groupBy(outs, function (n) {
  2012. let value = n % 100;
  2013. if(value == 1) value = 14;
  2014. if(value == 2) value = 15;
  2015. return value;
  2016. });
  2017. // console.warn("222按照牌面值出现个数对除牌数组进行排序",JSON.stringify(ng));
  2018. // 222手牌排序 {"3":[103,403],"4":[104,404],"5":[105],"6":[106],"7":[107],"8":[108],"9":[109],"10":[110],"11":[111],"12":[112],"13":[113],"14":[101,201],"15":[102]}
  2019. let xxc = _.sortBy(ng, function(o) { return o.length; });
  2020. // 333手牌排序 [[105],[106],[107],[108],[109],[110],[111],[112],[113],[102],[103,403],[104,404],[101,201]]
  2021. // 333手牌排序 [[103,403],[104,404],[105],[106],[107],[108],[109],[110],[111],[112],[113],[101,201],[102]]
  2022. // console.warn("333手牌排序",JSON.stringify(xxc));
  2023. let res = [];
  2024. for (var i = 0; i < xxc.length; i++) {
  2025. res = res.concat(_.sortBy(xxc[i]))
  2026. }
  2027. //下面是验证排序过程中是否出错(改变原数组)了
  2028. let lygdys = _.difference(outs,res);////另一个队员的人数
  2029. let lygdys2 = _.difference(res,outs);////另一个队员的人数
  2030. if(lygdys.length > 0 || lygdys2.length > 0 || outs.length != res.length){
  2031. console.error("111===============这把排序出错了 =======",outs);
  2032. console.error("222===============这把排序出错了 =======",res);
  2033. return outs;
  2034. }
  2035. // console.warn("1010手牌排序",JSON.stringify(res));
  2036. // 555手牌排序 [105,106,107,108,109,110,111,112,113,102,103,403,104,404,101,201]
  2037. // 1010手牌排序 [103,403,104,404,105,106,107,108,109,110,111,112,113,101,201,102]
  2038. return res;
  2039. };
  2040. // 是否三带一 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2041. proto.isSanDaiYi = function (outCards,pzfbqk,lastOut,spCount) {
  2042. if(lastOut.cards.length > 0) return STYLE.ERROR;
  2043. if(lastOut.type > -1 && lastOut.type != STYLE.SANDAIYI) return STYLE.NULL;//别人出的不是三带一自己不能出三带一
  2044. if(spCount > 4) return STYLE.ERROR;//只有手牌不够三带二的时候才能出三带一
  2045. if(lastOut.cards.length > 0){
  2046. if(outCards.length != 4) return STYLE.NULL;//别人出3带一的时候自己牌数不够压不住
  2047. if(pzfbqk.length != 2 || pzfbqk[0] != 1 || pzfbqk[1] != 3) return STYLE.ERROR;
  2048. if(lastOut.cards.length > 0){
  2049. let sortedOuts = this.sortOut(outCards);
  2050. let sortedlasts = this.sortOut(lastOut.cards);
  2051. // console.warn("是否三带一 sortedOuts "+JSON.stringify(sortedOuts)+" sortedlasts "+JSON.stringify(sortedlasts))
  2052. if(this.getValuepx(sortedOuts[1]) <= this.getValuepx(sortedlasts[1])){
  2053. //点数不够大的三带一压不住
  2054. return STYLE.NULL;
  2055. }
  2056. }
  2057. }
  2058. else{
  2059. //自己是本轮第一个出牌的玩家,手牌只剩555这种3张一样的虽然牌数不够组成三带一(只有3的牌没有带的牌)是可以打出去的
  2060. if(pzfbqk.length == 1 && outCards.length == 3) return STYLE.SANDAIYI;
  2061. if(pzfbqk.length != 2 || pzfbqk[0] != 1 || pzfbqk[1] != 3) return STYLE.ERROR;
  2062. else if(spCount > outCards.length) return STYLE.ERROR;
  2063. }
  2064. return STYLE.SANDAIYI;
  2065. }
  2066. // 是否三带二 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2067. proto.isSanDaiEr = function (outCards,pzfbqk,lastOut,spCount) {
  2068. // console.warn("是否三带二 出的牌 "+JSON.stringify(outCards)+" 牌值分布情况 "+JSON.stringify(pzfbqk)+" 上家有效出牌 "+JSON.stringify(lastOut)+" 手牌个数"+spCount);
  2069. // console.warn("是否三带二 222 "+lastOut.cards.length);
  2070. if(lastOut.cards.length > 0 && lastOut.type != STYLE.SANDAIER) return STYLE.NULL;//别人出的不是三带二自己不能出三带二
  2071. // console.warn("是否三带二 333 "+lastOut.cards.length);
  2072. if(lastOut.cards.length > 0 || spCount >= 5){
  2073. if(outCards.length != 5) return STYLE.ERROR;
  2074. if(pzfbqk.length != 2 && pzfbqk.length != 3) return STYLE.ERROR;//既不是3带一对也不是三带2单
  2075. if(pzfbqk.length == 2) {
  2076. if(pzfbqk[0] != 2 || pzfbqk[1] != 3){
  2077. // 不是3带一对
  2078. if(pzfbqk[0] != 1 || pzfbqk[1] != 4){
  2079. // 不是炸弹带一单
  2080. return STYLE.ERROR;
  2081. }
  2082. }
  2083. else{
  2084. //至此是3带1对了
  2085. }
  2086. }
  2087. if(pzfbqk.length == 3) {
  2088. if(pzfbqk[0] != 1 || pzfbqk[1] != 1 || pzfbqk[2] != 3){
  2089. // 不是3带2单
  2090. return STYLE.ERROR;
  2091. }
  2092. else{
  2093. //至此是3带2单了
  2094. }
  2095. }
  2096. if(lastOut.cards.length > 0){
  2097. // let lastOutCards = this.deepCloneTL(lastOut.cards);
  2098. // let lastfbqk = this.getPokeValueArr(lastOutCards);//牌值分布情况
  2099. //下面这个if是控制3带2单可不可以压三带一对
  2100. // if(lastfbqk.length < pzfbqk.length){
  2101. // //自己的三带2单压不住别人的三带1对
  2102. // return STYLE.NULL;
  2103. // }
  2104. let sortedOuts = this.sortOut(outCards);
  2105. let sortedlasts = this.sortOut(lastOut.cards);
  2106. if(this.getValuepx(sortedOuts[2]) <= this.getValuepx(sortedlasts[2])){
  2107. //点数不够大的连对压不住
  2108. return STYLE.NULL;
  2109. }
  2110. }
  2111. }
  2112. else{
  2113. //自己是本轮第一个出牌的玩家,手牌只剩555这种3张一样的虽然牌数不够组成三带一(只有3的牌没有带的牌)是可以打出去的
  2114. if(pzfbqk.indexOf(3) == -1) return STYLE.ERROR;
  2115. else if(spCount > outCards.length) return STYLE.ERROR;
  2116. }
  2117. // console.warn("是否三带二")
  2118. return STYLE.SANDAIER;
  2119. }
  2120. // 是否四带二 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2121. proto.isSiDaiEr = function (outCards,pzfbqk,lastOut,spCount) {
  2122. if(this.isZDBKC) return STYLE.ERROR;//炸弹不可拆时四带2不能出四带2
  2123. if(!this.isCanSiDaiEr) return STYLE.ERROR;//没有勾选四带2不能出四带2
  2124. if(lastOut.cards.length > 0 && lastOut.type != STYLE.SIDAIER) return STYLE.NULL;//别人出的不是四带二自己不能出四带二
  2125. if(lastOut.cards.length > 0 || spCount >= 6){
  2126. if(outCards.length != 6) return STYLE.ERROR;
  2127. if(pzfbqk.length != 2 && pzfbqk.length != 3) return STYLE.ERROR;//既不是4带一对也不是4带2单
  2128. if(pzfbqk.length == 2) {
  2129. if(pzfbqk[0] != 2 || pzfbqk[1] != 4){
  2130. // 不是4带一对
  2131. return STYLE.ERROR;
  2132. }
  2133. else{
  2134. //至此是4带1对了
  2135. }
  2136. }
  2137. if(pzfbqk.length == 3) {
  2138. if(pzfbqk[0] != 1 || pzfbqk[1] != 1 || pzfbqk[2] != 4){
  2139. // 不是4带2单
  2140. return STYLE.ERROR;
  2141. }
  2142. else{
  2143. //至此是3带2单了
  2144. }
  2145. }
  2146. if(lastOut.cards.length > 0){
  2147. // let lastOutCards = this.deepCloneTL(lastOut.cards);
  2148. // let lastfbqk = this.getPokeValueArr(lastOutCards);//牌值分布情况
  2149. // if(lastfbqk.length < pzfbqk.length){
  2150. // //自己的四带2单压不住别人的四带1对
  2151. // return STYLE.NULL;
  2152. // }
  2153. let sortedOuts = this.sortOut(outCards);
  2154. let sortedlasts = this.sortOut(lastOut.cards);
  2155. if(this.getValuepx(sortedOuts[2]) <= this.getValuepx(sortedlasts[2])){
  2156. //点数不够大的连对压不住
  2157. return STYLE.NULL;
  2158. }
  2159. }
  2160. }
  2161. else{
  2162. //自己是本轮第一个出牌的玩家,手牌只剩55556这种5张虽然牌数不够组成是否四带二(只有4的牌没有带的牌)是可以打出去的
  2163. if(pzfbqk.indexOf(4) == -1) return STYLE.ERROR;
  2164. else{
  2165. if(pzfbqk.length == 1) return STYLE.ZHADAN;//只出了个4个一样的算是炸弹
  2166. else{
  2167. //手上剩333345出33334的话手牌没有出完不能算是4带2打下去
  2168. if(spCount > outCards.length) return STYLE.ERROR;
  2169. }
  2170. }
  2171. }
  2172. return STYLE.SIDAIER;
  2173. }
  2174. // 是否四带三 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2175. proto.isSiDaiSan = function (outCards,pzfbqk,lastOut,spCount) {
  2176. if(this.isZDBKC) return STYLE.ERROR;//炸弹不可拆时四带2不能出四带2
  2177. if(!this.isSiCanDaiSan) return STYLE.ERROR;//没有勾选四带3不能出四带3
  2178. if(lastOut.cards.length > 0 && lastOut.type != STYLE.SIDAISAN) return STYLE.NULL;//别人出的不是四带三自己不能出四带三
  2179. if(lastOut.cards.length > 0 || spCount >= 7){
  2180. if(outCards.length != 7) return STYLE.ERROR;
  2181. if(pzfbqk.length != 2 && pzfbqk.length != 3 && pzfbqk.length != 4) return STYLE.ERROR;//既不是4带一豹也不是4带1对1单也不是四带3单
  2182. if(pzfbqk.length == 2) {
  2183. if(pzfbqk[0] != 3 || pzfbqk[1] != 4){
  2184. // 不是4带一豹子
  2185. return STYLE.ERROR;
  2186. }
  2187. else{
  2188. //至此是4带1对了
  2189. }
  2190. }
  2191. if(pzfbqk.length == 3) {
  2192. if(pzfbqk[0] != 1 || pzfbqk[1] != 2 || pzfbqk[2] != 4){
  2193. // 不是4带1对1单
  2194. return STYLE.ERROR;
  2195. }
  2196. else{
  2197. //至此是3带2单了
  2198. }
  2199. }
  2200. if(pzfbqk.length == 4) {
  2201. if(pzfbqk[0] != 1 || pzfbqk[1] != 1 || pzfbqk[2] != 1 || pzfbqk[3] != 4){
  2202. // 不是4带3单
  2203. return STYLE.ERROR;
  2204. }
  2205. else{
  2206. //至此是3带2单了
  2207. }
  2208. }
  2209. if(lastOut.cards.length > 0){
  2210. // let lastOutCards = this.deepCloneTL(lastOut.cards);
  2211. // let lastfbqk = this.getPokeValueArr(lastOutCards);//牌值分布情况
  2212. // if(lastfbqk.length < pzfbqk.length){
  2213. // //自己的四带3单(四带1对1单)压不住别人的四带1对1单(四带1豹子)
  2214. // console.warn("走到这里了吗????");
  2215. // return STYLE.NULL;
  2216. // }
  2217. let sortedOuts = this.sortOut(outCards);
  2218. let sortedlasts = this.sortOut(lastOut.cards);
  2219. if(this.getValuepx(sortedOuts[3]) <= this.getValuepx(sortedlasts[3])){
  2220. //点数不够大的连对压不住
  2221. return STYLE.NULL;
  2222. }
  2223. }
  2224. }
  2225. else{
  2226. //自己是本轮第一个出牌的玩家,手牌只剩555567这种5张虽然牌数不够组成是否四带三(只有4的牌没有带的牌)是可以打出去的
  2227. if(pzfbqk.indexOf(4) == -1) return STYLE.ERROR;
  2228. else{
  2229. if(pzfbqk.length == 1) return STYLE.ZHADAN;//只出了个4个一样的算是炸弹
  2230. else{
  2231. //手上剩333345出33334的话手牌没有出完不能算是4带2打下去
  2232. if(spCount > outCards.length) return STYLE.ERROR;
  2233. }
  2234. }
  2235. }
  2236. return STYLE.SIDAISAN;
  2237. }
  2238. // 是否飞机 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2239. proto.isFeiJi = function (outCards,pzfbqk,lastOut,spCount) {
  2240. // console.warn("是否飞机 出的牌 "+JSON.stringify(outCards)+" 牌值分布情况 "+JSON.stringify(pzfbqk)+" 上家有效出牌 "+JSON.stringify(lastOut)+" 手牌个数"+spCount);
  2241. if(lastOut.cards.length > 0 && lastOut.type != STYLE.FEIJI) return STYLE.NULL;//别人出的不是飞机自己不能出飞机
  2242. let keCount = 0;
  2243. for (var i = 0; i < pzfbqk.length; i++) {
  2244. if(pzfbqk[i] == 3) keCount++
  2245. }
  2246. // console.warn("是否飞机 keCount "+keCount+" pzfbqk "+JSON.stringify(pzfbqk))
  2247. if(keCount < 2) return STYLE.ERROR;//豹子个数不够飞机
  2248. let sortedOuts = this.sortOut(outCards);
  2249. let sortedlasts = this.sortOut(lastOut.cards);
  2250. // console.warn("是否飞机 sortedOuts "+JSON.stringify(sortedOuts)+" sortedlasts "+JSON.stringify(sortedlasts))
  2251. let yxKeCount = 0;//飞机里有效的豹子个数
  2252. let ofjz = 0;
  2253. var ng = _.groupBy(outCards, function (n) {
  2254. let value = n % 100;
  2255. if(value == 1) value = 14;
  2256. if(value == 2) value = 15;
  2257. return value;
  2258. });
  2259. let xxc = _.sortBy(ng, function(o) { return o.length; });
  2260. let bzpzfb = [];
  2261. for (var i = 0; i < xxc.length; i++) {
  2262. if(xxc[i].length == 3) bzpzfb[bzpzfb.length] = this.getValuepx(xxc[i][0])
  2263. }
  2264. // console.warn("是否飞机 xxc "+JSON.stringify(xxc)+" bzpzfb "+JSON.stringify(bzpzfb))
  2265. if(bzpzfb[3] && bzpzfb[2]+1 == bzpzfb[3] && bzpzfb[3]+1 == bzpzfb[4]){
  2266. yxKeCount = 3;
  2267. ofjz = bzpzfb[4];
  2268. }
  2269. else if(bzpzfb[2] && bzpzfb[1]+1 == bzpzfb[2] && bzpzfb[2]+1 == bzpzfb[3]){
  2270. yxKeCount = 3;
  2271. ofjz = bzpzfb[3];
  2272. }
  2273. else if(bzpzfb[0]+1 == bzpzfb[1] && bzpzfb[1]+1 == bzpzfb[2]){
  2274. yxKeCount = 3;
  2275. ofjz = bzpzfb[2];
  2276. }
  2277. else if(bzpzfb[0]+1 == bzpzfb[1] || bzpzfb[1]+1 == bzpzfb[2]){
  2278. if(bzpzfb[0]+1 == bzpzfb[1]) ofjz = bzpzfb[1];
  2279. else if(bzpzfb[1]+1 == bzpzfb[2]) ofjz = bzpzfb[2];
  2280. yxKeCount = 2;
  2281. }
  2282. if(outCards.length > 15 && keCount >= 4){
  2283. if(bzpzfb[1]+1 == bzpzfb[2] && bzpzfb[2]+1 == bzpzfb[3] && bzpzfb[3]+1 == bzpzfb[4]){
  2284. yxKeCount = 4;
  2285. ofjz = bzpzfb[4];
  2286. }
  2287. else if(bzpzfb[0]+1 == bzpzfb[1] && bzpzfb[1]+1 == bzpzfb[2] && bzpzfb[2]+1 == bzpzfb[3]){
  2288. yxKeCount = 4;
  2289. ofjz = bzpzfb[3];
  2290. }
  2291. }
  2292. // console.warn("是否飞机 keCount "+keCount+" yxKeCount "+yxKeCount)
  2293. if(yxKeCount == 0) return STYLE.ERROR;//飞机里有效的豹子个数不够(飞机里两个豹子点数未相邻)
  2294. // console.warn("走到这里了000 spCount "+spCount +" outCards.length "+outCards.length);
  2295. if(spCount > outCards.length){
  2296. if(outCards.length%5 == 0){
  2297. // console.warn("走到这里了111 yxKeCount "+yxKeCount)
  2298. yxKeCount = outCards.length/5;
  2299. }
  2300. else{
  2301. // console.warn("走到这里了222 张数不对")
  2302. return STYLE.ERROR;//张数不对
  2303. }
  2304. }
  2305. let fjNeedCount = yxKeCount*5;//飞机需要的牌总张数
  2306. // console.warn("走到这里了333 yxKeCount "+yxKeCount+" fjNeedCount "+fjNeedCount)
  2307. if(lastOut.cards.length > 0 && outCards.length != lastOut.cards.length) return STYLE.ERROR;//张数不对
  2308. if(lastOut.cards.length > 0 || spCount >= fjNeedCount){
  2309. if(outCards.length != fjNeedCount) {
  2310. // console.warn("走到这里了,所以报错222 outCards.length "+outCards.length);
  2311. return STYLE.ERROR;//张数不对
  2312. }
  2313. let lpzfbqk = this.getPokeValueArr(lastOut.cards);//上次有效出牌牌值分布情况
  2314. let lofjz = 0;
  2315. var lng = _.groupBy(lastOut.cards, function (n) {
  2316. let value = n % 100;
  2317. if(value == 1) value = 14;
  2318. if(value == 2) value = 15;
  2319. return value;
  2320. });
  2321. let lxxc = _.sortBy(lng, function(o) { return o.length; });
  2322. let lbzpzfb = [];
  2323. for (var i = 0; i < lxxc.length; i++) {
  2324. if(lxxc[i].length == 3) lbzpzfb[lbzpzfb.length] = this.getValuepx(lxxc[i][0])
  2325. }
  2326. // console.warn("是否飞机 lxxc "+JSON.stringify(lxxc)+" lbzpzfb "+JSON.stringify(lbzpzfb))
  2327. if(lbzpzfb[0]+1 == lbzpzfb[1] && lbzpzfb[1]+1 == lbzpzfb[2]){
  2328. lofjz = lbzpzfb[2];
  2329. }
  2330. else if(lbzpzfb[0]+1 == lbzpzfb[1] || lbzpzfb[1]+1 == lbzpzfb[2]){
  2331. if(lbzpzfb[0]+1 == lbzpzfb[1]) lofjz = lbzpzfb[1];
  2332. else if(lbzpzfb[1]+1 == lbzpzfb[2]) lofjz = lbzpzfb[2];
  2333. }
  2334. // console.warn("点数不够大的飞机压不住 ",ofjz , lofjz);
  2335. if(ofjz <= lofjz){
  2336. //点数不够大的飞机压不住
  2337. return STYLE.NULL;
  2338. }
  2339. }
  2340. else{
  2341. //自己是本轮第一个出牌的玩家,手牌只剩55566678这种8张虽然牌数不够组成飞机(只有飞机豹子的牌没有带的牌)是可以打出去的
  2342. // console.warn("是否飞机 死在这里了??? outCards.length "+outCards.length+" fjNeedCount "+fjNeedCount)
  2343. if(outCards.length > fjNeedCount) return STYLE.ERROR;//张数不对
  2344. }
  2345. return STYLE.FEIJI;
  2346. }
  2347. // 是否顺子 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2348. proto.isShunZi = function (outCards,pzfbqk,lastOut,spCount) {
  2349. // console.warn("顺子判断 至此出的牌是个合法的顺子了 "+JSON.stringify(outCards)+" "+JSON.stringify(lastOut.cards));
  2350. if(lastOut.cards.length > 0 && lastOut.type != STYLE.SHUNZI) return STYLE.NULL;//别人出的不是飞机自己不能出飞机
  2351. if(outCards.length != pzfbqk.length || outCards.length < 5) return STYLE.ERROR;//出的牌不全是单牌
  2352. for (var i = 1; i < outCards.length; i++) {
  2353. if(this.getValuepx(outCards[i]) != this.getValuepx(outCards[0])+i){
  2354. return STYLE.ERROR;
  2355. }
  2356. else{
  2357. //牌面数值2(逻辑牌值15)不能去做顺子
  2358. if(this.getValuepx(outCards[i]) == 15) return STYLE.ERROR;
  2359. }
  2360. }
  2361. //至此出的牌是个合法的顺子了
  2362. if(lastOut.cards.length > 0){
  2363. if(outCards.length != lastOut.cards.length){
  2364. //本次出牌牌数和上次出牌数不一样,不能压
  2365. return STYLE.NULL;
  2366. }
  2367. else{
  2368. if(this.getValuepx(outCards[0]) <= this.getValuepx(lastOut.cards[0])){
  2369. //张数一样点数不够大的顺子压不住
  2370. return STYLE.NULL;
  2371. }
  2372. }
  2373. }
  2374. return STYLE.SHUNZI;
  2375. }
  2376. // 是否炸弹 出的牌,牌值分布情况,上家有效出牌,手牌个数
  2377. proto.isZhaDan = function (outCards,pzfbqk,lastOut,spCount) {
  2378. if(outCards.length != 4) return STYLE.ERROR;
  2379. for (var i = 1; i < outCards.length; i++) {
  2380. if(this.getValuepx(outCards[i]) != this.getValuepx(outCards[0])){
  2381. return STYLE.ERROR;
  2382. }
  2383. }
  2384. // console.warn("至此是个正确的炸弹");
  2385. //至此是个正确的炸弹
  2386. if(lastOut.cards.length > 0){
  2387. // console.warn("炸弹压不住 ",this.getValuepx(outCards[0]) , this.getValuepx(lastOut.cards[0]));
  2388. if(lastOut.type == STYLE.ZHADAN){
  2389. if(this.getValuepx(outCards[0]) <= this.getValuepx(lastOut.cards[0])) {
  2390. return STYLE.NULL;//点数不够大的炸弹压不住
  2391. }
  2392. }
  2393. }
  2394. // console.warn("判断炸弹成功 ");
  2395. return STYLE.ZHADAN;
  2396. }
  2397. ////TL++得到一张牌的剩余张数 用于胡牌提示提示该张的剩余张数
  2398. proto.getACardSYZS = function (card,_handCards,allhuCards,outCards) {
  2399. ////下面这段是适合胡牌提示里用的剩余牌数统计
  2400. let yjcxdzs = 0;////该牌已经出现的张数
  2401. for (var i = 0; i < _handCards.length; i++) {
  2402. if(card == _handCards[i]) yjcxdzs++;////该牌已经出现在自己手牌里的张数
  2403. }
  2404. for (var i = 0; i < outCards.length; i++) {
  2405. if(outCards[i].length == 0) continue;////该玩家没有碰杠牌
  2406. // console.warn("2得到一张牌的剩余张数 打出去的牌",card,yjcxdzs,i,JSON.stringify(_.clone(outCards[i])));
  2407. for (var k = 0; k < outCards[i].length; k++) {
  2408. if(card == outCards[i][k]) yjcxdzs++;////该牌已经出现在所有打出去牌里的张数;
  2409. }
  2410. }
  2411. let zs = 4
  2412. let syzs = zs - yjcxdzs;////剩余张数 = 总张数 - 已经出现的张数
  2413. // console.warn("333得到一张牌的剩余张数",card,syzs);
  2414. return syzs;
  2415. };