您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

1136 行
31 KiB

  1. --[[
  2. 3~KA2(从小到大)
  3. tip: 假设有个梅花3, 具体牌值则是为1,标准牌值是0x11
  4. ]]
  5. local defs = require("pk_doudizhu.luaScript.Def_28")
  6. local PokerUtil = class("PokerUtil")
  7. -- 值
  8. local Value_2 = 0x0d -- 2的具体牌值
  9. local Value_Joker_Little = 0x0e -- 小鬼的具体牌值
  10. local Value_Joker_Big = 0x0f -- 大鬼的具体牌值
  11. -- 从小到大排序
  12. function PokerUtil.sortOrder(a, b)
  13. return a < b
  14. end
  15. -- 从大到小排序
  16. function PokerUtil.sortDesc(a, b)
  17. return a > b
  18. end
  19. -- 从小到大排序(根据扑克值) v指value, t指type
  20. function PokerUtil.sortOrder_By_PokerValue(a, b)
  21. local v_a = PokerUtil:getCardValue(a)
  22. local v_b = PokerUtil:getCardValue(b)
  23. if v_a ~= v_b then
  24. return v_a < v_b
  25. else
  26. local t_a = PokerUtil:getCardType(a)
  27. local t_b = PokerUtil:getCardType(b)
  28. return t_a < t_b
  29. end
  30. end
  31. function PokerUtil:ctor(param)
  32. self:initFunction()
  33. end
  34. -- 获得牌类型 0方块 1梅花 2红桃 3黑桃
  35. function PokerUtil:getCardType(card)
  36. return toint(getNumBand(card, 0xf0) / 0x0f)
  37. end
  38. -- 获得牌的具体牌值
  39. function PokerUtil:getCardValue(card)
  40. return getNumBand(card, 0x0f)
  41. end
  42. function PokerUtil:initFunction()
  43. self:initTypeMap()
  44. -- self:initTipMap()
  45. end
  46. -- 定义数组,key是手牌的长度,value则是可能组成长度为key的牌型判断方法
  47. function PokerUtil:initTypeMap()
  48. for i = 1, PokerUtil.Card_Max_Length do
  49. PokerUtil.Card_Type_Map[i] = {}
  50. end
  51. -- 单张
  52. table.insert(PokerUtil.Card_Type_Map[1], self.isSingle)
  53. -- 对子
  54. table.insert(PokerUtil.Card_Type_Map[2], self.isDouble)
  55. -- 三张
  56. table.insert(PokerUtil.Card_Type_Map[3], self.isThree)
  57. -- 顺子
  58. for i = PokerUtil.Less_Line, PokerUtil.Max_Line do
  59. table.insert(PokerUtil.Card_Type_Map[i], self.isLine)
  60. end
  61. -- 连对
  62. for i = PokerUtil.Less_Lian_Dui, PokerUtil.Card_Max_Length do
  63. if i % 2 == 0 then
  64. table.insert(PokerUtil.Card_Type_Map[i], self.isDoubleLine)
  65. end
  66. end
  67. -- 三带一
  68. table.insert(PokerUtil.Card_Type_Map[4], self.isThreeTakeOne)
  69. -- 三带二
  70. table.insert(PokerUtil.Card_Type_Map[5], self.isThreeTakeTwo)
  71. -- 四带一张
  72. table.insert(PokerUtil.Card_Type_Map[5], self.isFourTakeOneSinle)
  73. -- 四带一对
  74. table.insert(PokerUtil.Card_Type_Map[6], self.isFourTakeOneDouble)
  75. -- 四带二张单排
  76. table.insert(PokerUtil.Card_Type_Map[6], self.isFourTakeTwoSinle)
  77. -- 四带二对子
  78. table.insert(PokerUtil.Card_Type_Map[8], self.isFourTakeTwoDouble)
  79. -- 飞机不带
  80. for i = PokerUtil.Less_Plane, PokerUtil.Card_Max_Length do
  81. if i % 3 == 0 then
  82. table.insert(PokerUtil.Card_Type_Map[i], self.isPlaneNoTake)
  83. end
  84. end
  85. -- 飞机带单
  86. for i = PokerUtil.Less_Plane + 2, PokerUtil.Card_Max_Length do
  87. if i % 4 == 0 then
  88. table.insert(PokerUtil.Card_Type_Map[i], self.isPlaneTakeSinle)
  89. end
  90. end
  91. -- 飞机带对子
  92. for i = PokerUtil.Less_Plane + 4, PokerUtil.Card_Max_Length do
  93. if i % 5 == 0 then
  94. table.insert(PokerUtil.Card_Type_Map[i], self.isPlanetakeDouble)
  95. end
  96. end
  97. -- 炸弹
  98. table.insert(PokerUtil.Card_Type_Map[4], self.isBomb)
  99. -- 王炸
  100. table.insert(PokerUtil.Card_Type_Map[2], self.isKingBomb)
  101. end
  102. -- 获得提示(cards是userdata)
  103. function PokerUtil:getTip(cards, lastData)
  104. print('jxjx 进入getTip')
  105. dump(cards, 'cards')
  106. dump(lastData, 'lastData')
  107. local tipResult = {}
  108. local lastCardInfo = self:getCardsType(lastData)
  109. if lastCardInfo.cardType < defs.CARD_TYPE.BOMB then
  110. local f = PokerUtil.Card_Tip_Map[lastCardInfo.cardType]
  111. if f then
  112. print(string.format('jxjx..牌型提示..%s', defs.CARD_TYPE_NAME[lastCardInfo.cardType]))
  113. -- tipResult = PokerUtil.Card_Tip_Map[lastCardInfo.cardType](self, cards, lastData) -- f是方法 启用initTipMap
  114. tipResult = self[f](self, cards, lastData) -- f是str
  115. end
  116. end
  117. -- 添加炸弹
  118. if lastCardInfo.cardType <= defs.CARD_TYPE.BOMB then
  119. print('jxjx..炸弹')
  120. local result = self:getBombTip(cards, lastData)
  121. if table.nums(result) > 0 then
  122. for _, bomb in ipairs(result) do
  123. table.insert(tipResult, bomb)
  124. end
  125. end
  126. end
  127. --王炸
  128. if lastCardInfo.cardType <= defs.CARD_TYPE.BOMB_KING then
  129. print('jxjx..王炸')
  130. local result = self:getBombKingTip(cards, lastData)
  131. if table.nums(result) > 0 then
  132. for _, bomb in ipairs(result) do -- 王炸只有1个,虽然多此一举用了循环...
  133. table.insert(tipResult, bomb)
  134. end
  135. end
  136. end
  137. dump(tipResult, 'jxjx gettip 结果')
  138. return tipResult
  139. end
  140. -- 解析牌值,将牌值分成牌值数量表和牌表
  141. --[[
  142. valueList: key具体牌值, value数量
  143. valueCard: key具体牌值, value标准牌值(16进制转10进制的)
  144. ]]
  145. function PokerUtil:parseCard(cards)
  146. local valueList = {}
  147. local valueCard = {}
  148. for k,v in ipairs(cards) do
  149. local value = self:getCardValue(v)
  150. if not valueList[value] then
  151. valueList[value] = 0
  152. end
  153. if not valueCard[value] then
  154. valueCard[value] = {}
  155. end
  156. valueList[value] = valueList[value] + 1
  157. table.insert(valueCard[value], v)
  158. end
  159. return valueList, valueCard
  160. end
  161. -- 解析牌值,将牌值分成牌值数量表和牌表(扩展版)
  162. --[[
  163. valueCard: key有序, value标准牌值(16进制转10进制的)
  164. ]]
  165. function PokerUtil:parseCardEx(cards)
  166. local temp = {}
  167. for k,v in ipairs(cards) do
  168. local value = self:getCardValue(v)
  169. if not temp[value] then
  170. temp[value] = {}
  171. end
  172. table.insert(temp[value], v)
  173. end
  174. local valueCard = {}
  175. for _,v in pairs(temp) do
  176. table.insert(valueCard, v)
  177. end
  178. return valueCard
  179. end
  180. -- 反解析牌值,返回key为数量,value为具体牌值的表
  181. --[[
  182. result: key数量, value具体牌值
  183. ]]
  184. function PokerUtil:reParseCard(cards)
  185. local valueList = self:parseCard(cards)
  186. local result = {{}, {}, {}, {}} -- 一副牌,最多4张
  187. for k,v in pairs(valueList) do
  188. table.insert(result[v], k)
  189. end
  190. return result
  191. end
  192. -- 通过牌的标准值,转换为具体值
  193. function PokerUtil:changeCardValue_Standard_To_Specific(cards)
  194. if type(cards) == 'number' then
  195. return self:getCardValue(cards)
  196. elseif type(cards) == 'table' then
  197. local result = {}
  198. for i, v in ipairs(cards) do
  199. table.insert(result, self:getCardValue(v))
  200. end
  201. return result
  202. end
  203. return
  204. end
  205. -- 判断牌组中是否包含炸弹
  206. function PokerUtil:getIsHaveBomb(cards)
  207. -- 4张
  208. local reValueList = self:reParseCard(cards)
  209. if #reValueList[4] > 0 then
  210. return true
  211. end
  212. -- 王炸
  213. local valueList = self:parseCard(cards)
  214. if (valueList[Value_Joker_Little] or 0) > 0 and (valueList[Value_Joker_Big] or 0) > 0 then
  215. return true
  216. end
  217. return false
  218. end
  219. -- 获得牌类型(返回类型和最小值)
  220. function PokerUtil:getCardsType(cards)
  221. local result = {min = -1, cardType = defs.CARD_TYPE.NULL}
  222. local maxLen = table.nums(cards)
  223. if maxLen == 0 then
  224. print('jxjx 牌长度错误,获得牌类型,牌长度是0,返回')
  225. return result
  226. end
  227. local tt = {}
  228. for k,v in ipairs(cards) do
  229. table.insert(tt, self:getCardValue(v))
  230. end
  231. table.sort(tt, function(a, b)
  232. return a < b
  233. end)
  234. print('jxjx 获得牌提示,长度是', maxLen)
  235. if PokerUtil.Card_Type_Map[maxLen] then
  236. print(string.format('jxjx 判断方法共有%d个', #PokerUtil.Card_Type_Map[maxLen]))
  237. end
  238. for i, fun in ipairs(PokerUtil.Card_Type_Map[maxLen]) do
  239. local isType, ct, min = fun(self, tt)
  240. if isType then
  241. result = {min = min, cardType = ct}
  242. print('jxjx 获得牌提示,牌的类型是', defs.CARD_TYPE_NAME[ct])
  243. break
  244. end
  245. end
  246. return result
  247. end
  248. -- 是否一手出完所有牌
  249. function PokerUtil:checkIsCanOneOutCard(cards, lastData)
  250. print('jxjx 是否一手出完所有牌')
  251. dump(cards, 'cards>>')
  252. dump(lastData, 'lastData>>')
  253. -- 压牌(如果有提示牌,并且只有1种)
  254. if lastData and table.nums(lastData) > 0 then
  255. local tips = self:getTip(cards, lastData)
  256. if tips and table.nums(tips) == 1 and #tips[1] == #cards then
  257. print('压牌,可以出完一手牌')
  258. return true
  259. end
  260. end
  261. -- 自己出牌(判断手中的所有牌是否可以组成某个牌型,并且没有炸弹)
  262. if not lastData or table.nums(lastData) <= 0 then
  263. local handCardType = self:getCardsType(cards)
  264. if handCardType.cardType > defs.CARD_TYPE.NULL and not self:getIsHaveBomb(cards) then
  265. print('自己出牌,可以出完一手牌')
  266. return true
  267. end
  268. end
  269. print('jxjx 不可一手出完所有牌')
  270. return false
  271. end
  272. -- 是否可以3带1
  273. function PokerUtil:can31()
  274. if not app.room then
  275. return true
  276. end
  277. local gameInfo = json.decode(app.room.roomInfo.strGameInfo)
  278. return getNumBand(0x01, (gameInfo.sanDai or 0x1)) > 0
  279. end
  280. -- 是否可以3带2
  281. function PokerUtil:can32()
  282. if not app.room then
  283. return true
  284. end
  285. local gameInfo = json.decode(app.room.roomInfo.strGameInfo)
  286. return getNumBand(0x02, (gameInfo.sanDai or 0x2)) > 0
  287. end
  288. -- 是否可以4带1
  289. function PokerUtil:can41()
  290. return false
  291. end
  292. -- 是否可以4带2(4带1对子)
  293. function PokerUtil:can42()
  294. return true
  295. end
  296. -- 是否可以4带单单(2个单张)
  297. function PokerUtil:can411()
  298. if not app.room then
  299. return true
  300. end
  301. local gameInfo = json.decode(app.room.roomInfo.strGameInfo)
  302. return getNumBand(0x02, (gameInfo.siDai or 0x02)) > 0
  303. end
  304. -- 是否可以4带双双(2个对子)
  305. function PokerUtil:can422()
  306. if not app.room then
  307. return true
  308. end
  309. local gameInfo = json.decode(app.room.roomInfo.strGameInfo)
  310. return getNumBand(0x08, (gameInfo.siDai or 0x08)) > 0
  311. end
  312. -----------------------------------------------------------------------------------------------------------------
  313. -------------------------------------- 以下是牌型提示 ------------------------------------------------------
  314. -----------------------------------------------------------------------------------------------------------------
  315. -- 获得单张提示
  316. -- tip: 先从1张按顺序获取,在从2张,最后到4张
  317. function PokerUtil:getSingleTip(cards, lastData)
  318. local valueList, valueCard = self:parseCard(cards)
  319. local lastCardInfo = self:getCardsType(lastData)
  320. local result = {}
  321. local a = {{}, {}, {}, {}}
  322. for k,v in pairs(valueList) do
  323. table.insert(a[v], k)
  324. end
  325. for i = 1, 4 do
  326. for k2,v2 in pairs(a[i]) do
  327. if v2 > lastCardInfo.min then
  328. table.insert(result, { valueCard[v2][1] })
  329. end
  330. end
  331. end
  332. return result
  333. end
  334. -- 获得对子提示
  335. -- tip:直接就是从小到大,直接在2,3,4张中获取,不按是否有3张还是4张的
  336. function PokerUtil:getDuiZiTip(cards, lastData)
  337. local valueList, valueCard = self:parseCard(cards)
  338. local lastCardInfo = self:getCardsType(lastData)
  339. local result = {}
  340. for i = lastCardInfo.min + 1, 13 do
  341. local tpReplace = {}
  342. if (valueList[i] or 0) >= 2 then
  343. for j = 1, 2 do
  344. table.insert(tpReplace, valueCard[i][j])
  345. end
  346. table.insert(result, tpReplace)
  347. end
  348. end
  349. return result
  350. end
  351. -- 获得三张提示
  352. -- tip:直接就是从小到大,直接在3,4张中获取,不按是否有3张还是4张的
  353. function PokerUtil:getSanZhangTip(cards, lastData)
  354. local valueList, valueCard = self:parseCard(cards)
  355. local lastCardInfo = self:getCardsType(lastData)
  356. local result = {}
  357. for i = lastCardInfo.min + 1, 13 do
  358. local tpReplace = {}
  359. if (valueList[i] or 0) >= 3 then
  360. for j = 1, 3 do
  361. table.insert(tpReplace, valueCard[i][j])
  362. end
  363. table.insert(result, tpReplace)
  364. end
  365. end
  366. return result
  367. end
  368. -- 获得顺子提示
  369. -- tips:先for循环最小值+1,直到13-长度(为了减少复杂度);然后在while循环中判断是否有当前出牌的长度的个数
  370. function PokerUtil:getShunZiTip(cards, lastData)
  371. local valueList, valueCard = self:parseCard(cards)
  372. local lastCardInfo = self:getCardsType(lastData)
  373. local nowCardsLen = table.nums(cards)
  374. local lastCardsLen = table.nums(lastData)
  375. local result = {}
  376. for i = lastCardInfo.min + 1, 13 - lastCardsLen do
  377. local tpIdx = i
  378. local tpCount = 0
  379. local tpReplace = {}
  380. while tpCount < nowCardsLen and tpCount < lastCardsLen and tpIdx <= 12 do
  381. valueList[tpIdx] = valueList[tpIdx] or 0
  382. if valueList[tpIdx] <= 0 then
  383. break
  384. end
  385. table.insert(tpReplace, valueCard[tpIdx][1])
  386. tpCount = tpCount + 1
  387. tpIdx = tpIdx + 1
  388. end
  389. if tpCount == lastCardsLen then
  390. table.insert(result, tpReplace)
  391. end
  392. end
  393. return result
  394. end
  395. -- 获得连对提示
  396. -- tip:先for循环最小值+1,直到13-长度/2(为了减少复杂度,这里/2是因为连对中是一半一半相对的);然后在while循环中判断是否有当前出牌的长度的个数
  397. function PokerUtil:getLianDuiTip(cards, lastData)
  398. local valueList, valueCard = self:parseCard(cards)
  399. local lastCardInfo = self:getCardsType(lastData)
  400. local nowCardsLen = table.nums(cards)
  401. local lastCardsLen = table.nums(lastData)
  402. local result = {}
  403. for i = lastCardInfo.min + 1, 13 - lastCardsLen / 2 do
  404. local tpIdx = i
  405. local tpCount = 0
  406. local tpReplace = {}
  407. while tpCount < nowCardsLen and tpCount < lastCardsLen and tpIdx <= 12 do
  408. valueList[tpIdx] = valueList[tpIdx] or 0
  409. if valueList[tpIdx] <= 1 then
  410. break
  411. end
  412. for j = 1, 2 do
  413. table.insert(tpReplace, valueCard[tpIdx][j])
  414. end
  415. tpCount = tpCount + 2
  416. tpIdx = tpIdx + 1
  417. end
  418. if tpCount == lastCardsLen then
  419. table.insert(result, tpReplace)
  420. end
  421. end
  422. return result
  423. end
  424. -- 获得三顺提示(飞机不带翅膀)
  425. -- tip:先for循环最小值+1,直到13-长度/3(为了减少复杂度,这里/3是因为连对中是每3分之1相对的);然后在while循环中判断是否有当前出牌的长度的个数
  426. function PokerUtil:getSanShunTip(cards, lastData)
  427. local valueList, valueCard = self:parseCard(cards)
  428. local lastCardInfo = self:getCardsType(lastData)
  429. local nowCardsLen = table.nums(cards)
  430. local lastCardsLen = table.nums(lastData)
  431. local result = {}
  432. for i = lastCardInfo.min + 1, 13 - lastCardsLen / 3 do
  433. local tpIdx = i
  434. local tpCount = 0
  435. local tpReplace = {}
  436. while tpCount < nowCardsLen and tpCount < lastCardsLen and tpIdx <= 12 do
  437. valueList[tpIdx] = valueList[tpIdx] or 0
  438. if valueList[tpIdx] <= 2 then
  439. break
  440. end
  441. for j = 1, 3 do
  442. table.insert(tpReplace, valueCard[tpIdx][j])
  443. end
  444. tpCount = tpCount + 3
  445. tpIdx = tpIdx + 1
  446. end
  447. if tpCount == lastCardsLen then
  448. table.insert(result, tpReplace)
  449. end
  450. end
  451. return result
  452. end
  453. -- 获得3带1提示
  454. -- tips:直接获取判断是否有大于等于3张的牌值
  455. function PokerUtil:getSanDaiYiTip(cards, lastData)
  456. local valueList, valueCard = self:parseCard(cards)
  457. local lastCardInfo = self:getCardsType(lastData)
  458. local nowCardsLen = table.nums(cards)
  459. local result = {}
  460. for i = lastCardInfo.min + 1, 13 do
  461. local tpReplace = {}
  462. if ((valueList[i] or 0) == 3 and nowCardsLen > 3) or ((valueList[i] or 0) > 3 and nowCardsLen > 4) then
  463. for j = 1, 3 do
  464. table.insert(tpReplace, valueCard[i][j])
  465. end
  466. table.insert(result, tpReplace)
  467. end
  468. end
  469. return result
  470. end
  471. -- 获得3带1对提示(3带2)
  472. -- tip:在for循环前,会判断是否有对子
  473. function PokerUtil:getSanDaiYiDuiTip(cards, lastData)
  474. local valueList, valueCard = self:parseCard(cards)
  475. local lastCardInfo = self:getCardsType(lastData)
  476. local reValueList = self:reParseCard(cards)
  477. local result = {}
  478. if table.nums(reValueList[2]) > 0 then
  479. for i = lastCardInfo.min + 1, 13 do
  480. local tpReplace = {}
  481. if (valueList[i] or 0) >= 3 then
  482. for j = 1, 3 do
  483. table.insert(tpReplace, valueCard[i][j])
  484. end
  485. table.insert(result, tpReplace)
  486. end
  487. end
  488. end
  489. return result
  490. end
  491. -- 获得飞机带单提示
  492. -- tip:根据当前循环for的i值,往后延长最长的,如果一个111222,手中有333444555,则会提示444555
  493. function PokerUtil:getAirPlaneSingleTip(cards, lastData)
  494. local valueList, valueCard = self:parseCard(cards)
  495. local lastCardInfo = self:getCardsType(lastData)
  496. local nowCardsLen = table.nums(cards)
  497. local lastCardsLen = table.nums(lastData)
  498. local result = {}
  499. if table.nums(valueList) > lastCardsLen / 4 then
  500. for i = lastCardInfo.min + 1, 13 - lastCardsLen / 4 do
  501. local tpIdx = i
  502. local tpCount = 0
  503. local tpReplace = {}
  504. while tpCount < nowCardsLen and tpIdx <= 12 do
  505. valueList[tpIdx] = valueList[tpIdx] or 0
  506. if valueList[tpIdx] < 3 then
  507. break
  508. end
  509. for j = 1, 3 do
  510. table.insert(tpReplace, valueCard[tpIdx][j])
  511. end
  512. tpCount = tpCount + 4
  513. tpIdx = tpIdx + 1
  514. end
  515. if tpCount == lastCardsLen then
  516. table.insert(result, tpReplace)
  517. end
  518. end
  519. end
  520. return result
  521. end
  522. -- 获得飞机带对提示
  523. -- tips:会先判断手牌中2张是否大于等于2个数量,jxtd 这里有bug,因为只会从对子中判断,不会冲超过2张中判断
  524. function PokerUtil:getAirPlaneDuiTip(cards, lastData)
  525. local valueList, valueCard = self:parseCard(cards)
  526. local lastCardInfo = self:getCardsType(lastData)
  527. local nowCardsLen = table.nums(cards)
  528. local lastCardsLen = table.nums(lastData)
  529. local reValueList = self:reParseCard(cards)
  530. local result = {}
  531. if table.nums(reValueList[2]) >= lastCardsLen / 5 then
  532. for i = lastCardInfo.min + 1, 13 - lastCardsLen / 5 do
  533. local tpIdx = i
  534. local tpCount = 0
  535. local tpReplace = {}
  536. while tpCount < nowCardsLen and tpIdx <= 12 do
  537. valueList[tpIdx] = valueList[tpIdx] or 0
  538. if valueList[tpIdx] < 3 then
  539. break
  540. end
  541. for j = 1, 3 do
  542. table.insert(tpReplace, valueCard[tpIdx][j])
  543. end
  544. tpCount = tpCount + 5
  545. tpIdx = tpIdx + 1
  546. end
  547. if tpCount == lastCardsLen then
  548. table.insert(result, tpReplace)
  549. end
  550. end
  551. end
  552. return result
  553. end
  554. -- 获得4带2单提示
  555. -- tips:先判断手牌是否大于等于6张,然后寻找4个
  556. function PokerUtil:getSiDaiErSingleTip(cards, lastData)
  557. local valueList, valueCard = self:parseCard(cards)
  558. local lastCardInfo = self:getCardsType(lastData)
  559. local nowCardsLen = table.nums(cards)
  560. local result = {}
  561. if nowCardsLen >= 6 then
  562. for i = lastCardInfo.min + 1, 13 do
  563. local tpReplace = {}
  564. if (valueList[i] or 0) >= 4 and nowCardsLen > 4 then
  565. for j = 1, 4 do
  566. table.insert(tpReplace, valueCard[i][j])
  567. end
  568. table.insert(result, tpReplace)
  569. end
  570. end
  571. end
  572. return result
  573. end
  574. -- 获得4带2对提示
  575. -- tips:会先判断手牌中2张是否大于等于2个数量,jxtd 这里有bug,因为只会从对子中判断,不会冲超过2张中判断
  576. function PokerUtil:getSiDaiErDuiTip(cards, lastData)
  577. local valueList, valueCard = self:parseCard(cards)
  578. local lastCardInfo = self:getCardsType(lastData)
  579. local nowCardsLen = table.nums(cards)
  580. local reValueList = self:reParseCard(cards)
  581. local result = {}
  582. if table.nums(reValueList[2]) >= 2 then
  583. for i = lastCardInfo.min + 1, 13 do
  584. local tpReplace = {}
  585. if (valueList[i] or 0) >= 4 and nowCardsLen > 4 then
  586. for j = 1, 4 do
  587. table.insert(tpReplace, valueCard[i][j])
  588. end
  589. table.insert(result, tpReplace)
  590. end
  591. end
  592. end
  593. return result
  594. end
  595. -- 获得炸弹提示
  596. function PokerUtil:getBombTip(cards, lastData)
  597. local valueList, valueCard = self:parseCard(cards)
  598. local lastCardInfo = self:getCardsType(lastData)
  599. local result = {}
  600. local tpIndex = lastCardInfo.cardType < defs.CARD_TYPE.BOMB and 1 or lastCardInfo.min + 1
  601. for i = tpIndex, 13 do
  602. local tpReplace = {}
  603. if (valueList[i] or 0) >= 4 then
  604. for j = 1, 4 do
  605. table.insert(tpReplace, valueCard[i][j])
  606. end
  607. table.insert(result, tpReplace)
  608. end
  609. end
  610. return result
  611. end
  612. -- 获得王炸提示
  613. function PokerUtil:getBombKingTip(cards, lastData)
  614. local valueList, valueCard = self:parseCard(cards)
  615. local result = {}
  616. if (valueList[Value_Joker_Little] or 0) > 0 and (valueList[Value_Joker_Big] or 0) > 0 then
  617. local tpReplace = {}
  618. table.insert(tpReplace, 0x4e)
  619. table.insert(tpReplace, 0x4f)
  620. table.insert(result, tpReplace)
  621. end
  622. return result
  623. end
  624. -----------------------------------------------------------------------------------------------------------------
  625. -------------------------------------- 以下是检查牌型 ------------------------------------------------------
  626. -----------------------------------------------------------------------------------------------------------------
  627. --[[
  628. cards 是具体牌值,即1~K,从小到大排序
  629. ]]
  630. -- 是否是单张
  631. function PokerUtil:isSingle(cards)
  632. return true, defs.CARD_TYPE.SINGLE, cards[1]
  633. end
  634. -- 是否是对子
  635. function PokerUtil:isDouble(cards)
  636. if cards[1] == cards[2] then
  637. return true, defs.CARD_TYPE.DUIZI,cards[1]
  638. end
  639. return false
  640. end
  641. -- 是否是三张(不带)
  642. function PokerUtil:isThree(cards)
  643. if cards[1] == cards[2] and cards[2] == cards[3] then
  644. return true, defs.CARD_TYPE.SANZHANG, cards[1]
  645. end
  646. return false
  647. end
  648. -- 是否是顺子
  649. function PokerUtil:isLine(cards)
  650. local isHaveKindOr2 = false
  651. for i, val in ipairs(cards) do
  652. if val == Value_Joker_Little or val == Value_Joker_Big or val == Value_2 then
  653. isHaveKindOr2 = true
  654. break
  655. end
  656. end
  657. -- 顺子中不允许包括2,大王,小王
  658. if isHaveKindOr2 then
  659. return false
  660. end
  661. -- 检查单张总长度是否与传入相同,因为顺子是必须都是单个值
  662. local reValueList = self:reParseCard(cards)
  663. if table.nums(reValueList[1]) ~= #(cards) then
  664. return false
  665. end
  666. -- 判断是否为顺子,计算最大值与最小值的差的绝对值是否与总长度-1相同
  667. if math.abs(cards[1] - cards[#cards]) == #cards - 1 then
  668. return true, defs.CARD_TYPE.SHUNZI, cards[1]
  669. end
  670. return false
  671. end
  672. -- 是否是双顺(连对)
  673. function PokerUtil:isDoubleLine(cards)
  674. local isHaveKindOr2 = false
  675. for i, val in ipairs(cards) do
  676. if val == Value_Joker_Little or val == Value_Joker_Big or val == Value_2 then
  677. isHaveKindOr2 = true
  678. break
  679. end
  680. end
  681. -- 顺子中不允许包括2,大王,小王
  682. if isHaveKindOr2 then
  683. return false
  684. end
  685. -- 检查2张的个数是否与总长度的一半相同,因为连对是必须都是对子值
  686. local reValueList = self:reParseCard(cards)
  687. if table.nums(reValueList[2]) ~= #(cards) / 2 then
  688. return false
  689. end
  690. -- 判断是否为对子,计算最大值与最小值的差的绝对值是否与总长度/2-1相同
  691. if math.abs(cards[1] - cards[#cards]) == #cards/2 - 1 then
  692. return true, defs.CARD_TYPE.SHUANGSHUN, cards[1]
  693. end
  694. return false
  695. end
  696. -- 是否是三带一(单张)
  697. function PokerUtil:isThreeTakeOne(cards)
  698. if not self:can31() then
  699. return false
  700. end
  701. local reValueList = self:reParseCard(cards)
  702. if table.nums(reValueList[3]) == 1 then
  703. return true, defs.CARD_TYPE.SANDAIYI, reValueList[3][1]
  704. end
  705. return false
  706. end
  707. -- 是否是三带二(对子)
  708. function PokerUtil:isThreeTakeTwo(cards)
  709. if not self:can32() then
  710. return false
  711. end
  712. local reValueList = self:reParseCard(cards)
  713. if table.nums(reValueList[3]) == 1 and table.nums(reValueList[2]) == 1 then
  714. return true, defs.CARD_TYPE.SANDAIDUI, reValueList[3][1]
  715. end
  716. return false
  717. end
  718. -- 是否是四带一(单)
  719. function PokerUtil:isFourTakeOneSinle(cards)
  720. if not self:can41() then
  721. return false
  722. end
  723. local reValueList = self:reParseCard(cards)
  724. if table.nums(reValueList[4]) == 1 then
  725. return true, defs.CARD_TYPE.SIDAIYI, reValueList[4][1]
  726. end
  727. return false
  728. end
  729. -- 是否是四带一对(对子)
  730. function PokerUtil:isFourTakeOneDouble(cards)
  731. if not self:can42() then
  732. return false
  733. end
  734. local reValueList = self:reParseCard(cards)
  735. if table.nums(reValueList[4]) == 1 and table.nums(reValueList[2]) == 1 then
  736. return true, defs.CARD_TYPE.SIDAIYIDUI, reValueList[4][1]
  737. end
  738. return false
  739. end
  740. -- 是否是四带二单张
  741. function PokerUtil:isFourTakeTwoSinle(cards)
  742. if not self:can411() then
  743. return false
  744. end
  745. local reValueList = self:reParseCard(cards)
  746. if table.nums(reValueList[4]) == 1 then
  747. return true, defs.CARD_TYPE.SIDAIER, reValueList[4][1]
  748. end
  749. return false
  750. end
  751. -- 是否是四带二对子
  752. function PokerUtil:isFourTakeTwoDouble(cards)
  753. if not self:can422() then
  754. return false
  755. end
  756. local reValueList = self:reParseCard(cards)
  757. if table.nums(reValueList[4]) == 1 and table.nums(reValueList[2]) == 2 then
  758. return true, defs.CARD_TYPE.SIDAIERDUI, reValueList[4][1]
  759. end
  760. return false
  761. end
  762. -- 是否是三顺(飞机不带333444)
  763. function PokerUtil:isPlaneNoTake(cards)
  764. local isHaveKindOr2 = false
  765. for i, val in ipairs(cards) do
  766. if val == Value_Joker_Little or val == Value_Joker_Big or val == Value_2 then
  767. isHaveKindOr2 = true
  768. break
  769. end
  770. end
  771. -- 三顺中不允许包括2,大王,小王
  772. if isHaveKindOr2 then
  773. return false
  774. end
  775. -- 检查3张的个数是否与总长度的/3相同,因为三顺是必须都是三个个值
  776. local reValueList = self:reParseCard(cards)
  777. if table.nums(reValueList[3]) ~= #(cards) / 3 then
  778. return false
  779. end
  780. -- 判断是否为对子,计算最大值与最小值的差的绝对值是否与总长度/2-1相同
  781. if math.abs(cards[1] - cards[#cards]) == #cards/3 - 1 then
  782. return true, defs.CARD_TYPE.SANSHUN, cards[1]
  783. end
  784. return false
  785. end
  786. -- 是否是飞机带单
  787. function PokerUtil:isPlaneTakeSinle(cards)
  788. -- if not self:can31() then
  789. -- return false
  790. -- end
  791. local reValueList = self:reParseCard(cards)
  792. local t3 = reValueList[3]
  793. local t4 = reValueList[4]
  794. for i = #t3, 1, -1 do -- 移除三张中带2的值
  795. if t3[i] == Value_2 then
  796. table.remove(t3, i)
  797. end
  798. end
  799. for i = #t4, 1, -1 do -- 移除四张中带2的值
  800. if t4[i] == Value_2 then
  801. table.remove(t4, i)
  802. end
  803. end
  804. local tpLianMin = self:tpLian(t3, t4, #cards/4)
  805. if tpLianMin then
  806. return true, defs.CARD_TYPE.AIRPLANE_SINGLE, tpLianMin.min
  807. end
  808. return false
  809. end
  810. -- 是否是飞机带对子
  811. function PokerUtil:isPlanetakeDouble(cards)
  812. -- if not self:can32() then
  813. -- return false
  814. -- end
  815. local reValueList = self:reParseCard(cards)
  816. local t2 = reValueList[2]
  817. local t3 = reValueList[3]
  818. local t4 = reValueList[4]
  819. for i = #t3, 1, -1 do -- 移除三张中带2的值
  820. if t3[i] == Value_2 then
  821. table.remove(t3, i)
  822. end
  823. end
  824. for i = #t4, 1, -1 do -- 移除四张中带2的值
  825. if t4[i] == Value_2 then
  826. table.remove(t4, i)
  827. end
  828. end
  829. local tpLianMin = self:tpLian(t3, t4, #cards/5)
  830. if tpLianMin then
  831. -- 判断除飞机长度外,组成对子的是否能超过飞机的个数
  832. local canBeDuiZiCount = #t2 + #t3 + #t4 * 2 -- 炸弹算2个对子,所以t4要*2
  833. print(string.format('%d可组成对子,飞机长度是%d', canBeDuiZiCount, tpLianMin.feiLen))
  834. local isMoreThan_2DuiZi = (canBeDuiZiCount - tpLianMin.feiLen) >= tpLianMin.feiLen
  835. if not isMoreThan_2DuiZi then
  836. return false
  837. end
  838. return true, defs.CARD_TYPE.AIRPLANE_DUAD, tpLianMin.min
  839. end
  840. return false
  841. end
  842. -- 飞机的判断
  843. -- tip:主要是根据3张,4张中,通过while循环获取与传入的飞机长度feiLen相同长度的值
  844. function PokerUtil:tpLian(la3, la4, feiLen)
  845. local feiLen = feiLen or 0
  846. local lc = {}
  847. for _,v in ipairs(la3) do
  848. table.insert(lc, v)
  849. end
  850. for _,v in ipairs(la4) do
  851. table.insert(lc, v)
  852. end
  853. if table.nums(lc) <= 0 then
  854. return nil
  855. end
  856. table.sort(lc, function (a, b)
  857. return a < b
  858. end)
  859. local lenEx = 1
  860. local feiji = {}
  861. local lcLen = table.nums(lc)
  862. for k,v in ipairs(lc) do
  863. lenEx = 1
  864. local j = k + 1
  865. while j <= lcLen and (feiLen == 0 or lenEx < feiLen) do
  866. if lc[j] ~= lc[j-1] + 1 then -- 判断是否是连续的
  867. break
  868. end
  869. j = j + 1
  870. lenEx = lenEx + 1
  871. end
  872. if lenEx == feiLen then
  873. table.insert(feiji, {
  874. feiLen = lenEx,
  875. min = lc[k],
  876. })
  877. end
  878. end
  879. if table.nums(feiji) > 0 then
  880. table.sort(feiji, function (a, b)
  881. return b.feiLen ~= a.feiLen and b.feiLen - a.feiLen or b.min - a.min
  882. end)
  883. return feiji[1]
  884. else
  885. return nil
  886. end
  887. end
  888. -- 是否是炸弹
  889. function PokerUtil:isBomb(cards)
  890. local tag = true
  891. local v = cards[1]
  892. for i, val in ipairs(cards) do
  893. if v ~= val then
  894. tag = false
  895. break
  896. end
  897. end
  898. if tag then
  899. return true, defs.CARD_TYPE.BOMB, cards[1]
  900. end
  901. return false
  902. end
  903. -- 是否是王炸
  904. function PokerUtil:isKingBomb(cards)
  905. if cards[1] == Value_Joker_Little and cards[2] == Value_Joker_Big then
  906. return true, defs.CARD_TYPE.BOMB_KING, cards[1]
  907. end
  908. return false
  909. end
  910. -----------------------------------------------------------------------------------------------------------------
  911. ---------------------------------------- 以下是配置 --------------------------------------------------------
  912. -----------------------------------------------------------------------------------------------------------------
  913. -- 配置
  914. PokerUtil.Card_Max_Length = 20 -- 手牌最多的个数
  915. PokerUtil.Less_Line = 5 -- 顺子最小长度
  916. PokerUtil.Max_Line = 12 -- 顺子最大长度(3~A)
  917. PokerUtil.Less_Lian_Dui = 6 -- 最小组成的连对长度
  918. PokerUtil.Less_Plane = 6 -- 最小组成的飞机长度
  919. PokerUtil.Card_Type_Map = {} -- 牌类型方法表
  920. PokerUtil.Card_Tip_Map = {} -- 牌提示方法表
  921. -- 牌型提示对应的方法(后面对应的是方法)
  922. PokerUtil.Card_Tip_Map = {
  923. [defs.CARD_TYPE.NULL] = nil,
  924. [defs.CARD_TYPE.SINGLE] = 'getSingleTip',
  925. [defs.CARD_TYPE.DUIZI] = 'getDuiZiTip',
  926. [defs.CARD_TYPE.SANZHANG] = 'getSanZhangTip',
  927. [defs.CARD_TYPE.SHUNZI] = 'getShunZiTip',
  928. [defs.CARD_TYPE.SHUANGSHUN] = 'getLianDuiTip',
  929. [defs.CARD_TYPE.SANSHUN] = 'getSanShunTip',
  930. [defs.CARD_TYPE.SANDAIYI] = 'getSanDaiYiTip',
  931. [defs.CARD_TYPE.SANDAIDUI] = 'getSanDaiYiDuiTip',
  932. [defs.CARD_TYPE.SIDAIYI] = nil,
  933. [defs.CARD_TYPE.SIDAIYIDUI] = nil,
  934. [defs.CARD_TYPE.SIDAIER] = 'getSiDaiErSingleTip',
  935. [defs.CARD_TYPE.SIDAIERDUI] = 'getSiDaiErDuiTip',
  936. [defs.CARD_TYPE.AIRPLANE_SINGLE] = 'getAirPlaneSingleTip',
  937. [defs.CARD_TYPE.AIRPLANE_DUAD] = 'getAirPlaneDuiTip',
  938. [defs.CARD_TYPE.BOMB] = 'getBombTip',
  939. [defs.CARD_TYPE.BOMB_KING] = 'getBombKingTip',
  940. }
  941. -- 初始化牌提示方法,不能用表驱动,因为子类重写时,调用的话,还是用的父类方法
  942. -- function PokerUtil:initTipMap()
  943. -- PokerUtil.Card_Tip_Map = {
  944. -- [defs.CARD_TYPE.NULL] = nil,
  945. -- [defs.CARD_TYPE.SINGLE] = self.getSingleTip,
  946. -- [defs.CARD_TYPE.DUIZI] = self.getDuiZiTip,
  947. -- [defs.CARD_TYPE.SANZHANG] = self.getSanZhangTip,
  948. -- [defs.CARD_TYPE.SHUNZI] = self.getShunZiTip,
  949. -- [defs.CARD_TYPE.SHUANGSHUN] = self.getLianDuiTip,
  950. -- [defs.CARD_TYPE.SANSHUN] = self.getSanShunTip,
  951. -- [defs.CARD_TYPE.SANDAIYI] = self.getSanDaiYiTip,
  952. -- [defs.CARD_TYPE.SANDAIDUI] = self.getSanDaiYiDuiTip,
  953. -- [defs.CARD_TYPE.SIDAIYI] = nil,
  954. -- [defs.CARD_TYPE.SIDAIYIDUI] = nil,
  955. -- [defs.CARD_TYPE.SIDAIER] = self.getSiDaiErSingleTip,
  956. -- [defs.CARD_TYPE.SIDAIERDUI] = self.getSiDaiErDuiTip,
  957. -- [defs.CARD_TYPE.AIRPLANE_SINGLE] = self.getAirPlaneSingleTip,
  958. -- [defs.CARD_TYPE.AIRPLANE_DUAD] = self.getAirPlaneDuiTip,
  959. -- [defs.CARD_TYPE.BOMB] = self.getBombTip,
  960. -- [defs.CARD_TYPE.BOMB_KING] = self.getBombKingTip,
  961. -- }
  962. -- end
  963. return PokerUtil