cardcommon.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. package gamelogic
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math/rand"
  6. "runtime/debug"
  7. "sort"
  8. "bet24.com/log"
  9. "bet24.com/servers/games/masharie_table/common"
  10. )
  11. var type_desc = []string{"♦", "♣", "♥", "♠", ""}
  12. var value_desc = []string{"7", "8", "9", "10", "J", "Q", "K", "A"}
  13. var type_html_desc = []string{"d", "c", "h", "s", ""}
  14. // var type_html_desc = []string{"♦", "♣", "♥", "♠", ""}
  15. // 非主花色排序从大到小 A 10 K Q J 9 8 7
  16. var score_regular = []int{0, 0, 0, 10, 2, 3, 4, 11}
  17. // 主花色排序从大到小 J 9 A 10 K Q 8 7
  18. var score_trump = []int{0, 0, 18, 10, 20, 3, 4, 11} //9的牌值跟baloot游戏的不同,这里为了排序方便,牌值从14为28
  19. const (
  20. CARD_COUNT = 32 // 牌数量
  21. HAND_CARD_COUNT = 5 // 手牌数量
  22. CARD_DECK_COUNT = 5 // 牌组数量
  23. )
  24. /*
  25. 牌的排列顺序为
  26. 方块 梅花 红心 黑桃
  27. */
  28. const (
  29. CardType_Diamond = iota
  30. CardType_Club
  31. CardType_Heart
  32. CardType_Spade
  33. CardType_Invalid
  34. )
  35. const (
  36. CardValue7 = iota
  37. CardValue8
  38. CardValue9
  39. CardValue10
  40. CardValueJ
  41. CardValueQ
  42. CardValueK
  43. CardValueA
  44. )
  45. type RankingMode int
  46. const (
  47. Max RankingMode = iota
  48. Min
  49. Random
  50. )
  51. func getCardHex(card int, isHtml bool) string {
  52. if !isValidCard(card) {
  53. return "n/a"
  54. }
  55. if isHtml {
  56. return fmt.Sprintf("%s%s", type_html_desc[GetCardType(card)], value_desc[GetCardValue(card)])
  57. }
  58. return fmt.Sprintf("%s%s", type_desc[GetCardType(card)], value_desc[GetCardValue(card)])
  59. }
  60. func getCardsHex(cards []int, isHtml bool) string {
  61. ret := "["
  62. for _, v := range cards {
  63. ret += " "
  64. ret += getCardHex(v, isHtml)
  65. ret += " "
  66. }
  67. ret += "]"
  68. return ret
  69. }
  70. func isValidCard(card int) bool {
  71. return card >= 0 && card < CARD_COUNT
  72. }
  73. func GetCardType(card int) int {
  74. if !isValidCard(card) {
  75. log.Debug("getCardType invalid Card %d", card)
  76. log.Debug("%s", debug.Stack())
  77. return CardType_Invalid
  78. }
  79. return card / 8
  80. }
  81. func GetCardValue(card int) int {
  82. if !isValidCard(card) {
  83. log.Debug("getCardValue invalid Card %d", card)
  84. log.Debug("%s", debug.Stack())
  85. return -1
  86. }
  87. return card % 8
  88. }
  89. // 是否为主花色牌
  90. func IsTrump(card, trumpType int) bool {
  91. return CardType_Invalid != trumpType && GetCardType(card) == trumpType
  92. }
  93. // 按牌分值排序
  94. func SortCardsByScore(cards []int, trumpType int) {
  95. sort.Slice(cards, func(i, j int) bool {
  96. //主花色 比其他的花色大 就算分值低也比其他花色大
  97. if IsTrump(cards[i], trumpType) != IsTrump(cards[j], trumpType) {
  98. return !IsTrump(cards[i], trumpType)
  99. }
  100. return calculateCardScore(cards[i], trumpType) < calculateCardScore(cards[j], trumpType)
  101. })
  102. }
  103. // 计算花色权重 为了花色逆时针排序
  104. func getCardTypeWeight(cardTypeOrder []int, card int) int {
  105. weight := 0 // 初始化为-1,表示没有找到
  106. cardType := GetCardType(card)
  107. for i := 0; i < len(cardTypeOrder); i++ {
  108. if cardTypeOrder[i] == cardType {
  109. weight = i
  110. break
  111. }
  112. }
  113. return weight * 100
  114. }
  115. // 按花色加分值排序
  116. func SortCardsByType(cards, cardTypeOrder []int, trumpType int) {
  117. sort.Slice(cards, func(i, j int) bool {
  118. return getCardTypeWeight(cardTypeOrder, cards[i])+calculateCardScore(cards[i], trumpType) < getCardTypeWeight(cardTypeOrder, cards[j])+calculateCardScore(cards[j], trumpType)
  119. })
  120. }
  121. // 计算卡片牌值
  122. func calculateCardScore(card, trumpType int) int {
  123. value := GetCardValue(card)
  124. t := GetCardType(card)
  125. if trumpType != CardType_Invalid && t == trumpType {
  126. return (value + score_trump[value])
  127. }
  128. return (value + score_regular[value])
  129. }
  130. // 比较两张牌的大小
  131. func calculateRankings(card1, card2 int, trumpType int) int {
  132. //如果是主花色则更大,都是主花色 或者都不是时才比较牌值
  133. if IsTrump(card1, trumpType) != IsTrump(card2, trumpType) {
  134. //有一组是主花色的牌
  135. if IsTrump(card1, trumpType) {
  136. return 1
  137. } else {
  138. return 2
  139. }
  140. }
  141. score1 := calculateCardScore(card1, trumpType)
  142. score2 := calculateCardScore(card2, trumpType)
  143. if score1 > score2 {
  144. return 1
  145. } else if score1 < score2 {
  146. return 2
  147. } else {
  148. return 0
  149. }
  150. }
  151. func getCopy(cards []int) []int {
  152. var ret []int
  153. d, _ := json.Marshal(cards)
  154. json.Unmarshal(d, &ret)
  155. return ret
  156. }
  157. // 计算卡牌分数
  158. func calculateCardsScore(cards1, cards2 []int, trumpType int) int {
  159. cards1Copy := getCopy(cards1)
  160. cards2Copy := getCopy(cards2)
  161. SortCardsByScore(cards1Copy, trumpType) //排序
  162. SortCardsByScore(cards2Copy, trumpType) //排序
  163. for i := len(cards1Copy) - 1; i >= 0; i-- {
  164. ranking := calculateRankings(cards1Copy[i], cards2Copy[i], trumpType)
  165. if ranking == 1 {
  166. return 1
  167. } else if ranking == 2 {
  168. return 2
  169. }
  170. }
  171. return 0
  172. }
  173. // 计算项目分数(有项目需要特殊处理)
  174. func calculateProjectScore(cards1, cards2 []int) int {
  175. lastCards1 := cards1[len(cards1)-1]
  176. lastCards2 := cards2[len(cards2)-1]
  177. trumpType := CardType_Invalid
  178. //只比较最后一张牌
  179. ranking := calculateRankings(lastCards1, lastCards2, trumpType)
  180. if ranking == 1 {
  181. return 1
  182. } else if ranking == 2 {
  183. return 2
  184. }
  185. return 0
  186. }
  187. // 排序卡牌
  188. func SortHandCards(cards []int, trumpType int) ([]int, common.CardProject, int, int) {
  189. project := common.Project_Base
  190. projectLength := 0
  191. maxCard := CARD_COUNT //最大牌
  192. // 剩余项目牌
  193. var mainCards []int
  194. // 项目牌
  195. var projectCards []int
  196. mainCardType := trumpType //主要卡牌花色用于排序 默认为主花色
  197. haveProject := false //是否有项目
  198. haveStraightFlush := false
  199. haveFourOfAKind := false
  200. fourOfAKindValue := -1
  201. haveFifty := false
  202. var fiftyCard []int
  203. haveBaloot := false
  204. haveSira := false
  205. var siraCard []int
  206. //先初步排序便于检查同花顺
  207. sort.Slice(cards, func(i, j int) bool {
  208. if GetCardType(cards[i]) != GetCardType(cards[j]) {
  209. return GetCardType(cards[i]) < GetCardType(cards[j])
  210. }
  211. return GetCardValue(cards[i]) < GetCardValue(cards[j])
  212. })
  213. if !haveProject {
  214. haveStraightFlush, _ = isStraightFlush(cards, HAND_CARD_COUNT)
  215. if haveStraightFlush {
  216. haveProject = haveStraightFlush
  217. project = common.Project_StraightFlush
  218. projectLength = 5
  219. }
  220. }
  221. if !haveProject {
  222. fourOfAKindValue = getFourOfAKind(cards)
  223. haveFourOfAKind = fourOfAKindValue != -1
  224. if haveFourOfAKind {
  225. haveProject = haveFourOfAKind
  226. project = common.Project_Hundred
  227. projectLength = 4
  228. mainCardType = CardType_Spade
  229. }
  230. }
  231. if !haveProject {
  232. fiftyCard = isFifty(cards)
  233. haveFifty = len(fiftyCard) > 0
  234. if haveFifty {
  235. haveProject = haveFifty
  236. project = common.Project_Fifty
  237. projectLength = len(fiftyCard)
  238. mainCardType = GetCardType(fiftyCard[0])
  239. }
  240. }
  241. if !haveProject {
  242. haveBaloot = isBaloot(cards, trumpType)
  243. if haveBaloot {
  244. haveProject = haveBaloot
  245. project = common.Project_Baloot
  246. projectLength = 2
  247. }
  248. }
  249. if !haveProject {
  250. siraCard = isSira(cards)
  251. haveSira = len(siraCard) > 0
  252. if haveSira {
  253. haveProject = haveSira
  254. project = common.Project_Sira
  255. projectLength = len(siraCard)
  256. mainCardType = GetCardType(siraCard[0])
  257. }
  258. }
  259. // log.Release("是否有项目%v ,同花顺%v,炸弹[%v:%v] 4同花顺[%v:%v] Baloot[%v] Sira[%v:%v]", haveProject, haveStraightFlush,
  260. // haveFourOfAKind, fourOfAKindValue,
  261. // haveFifty, fiftyCard,
  262. // haveBaloot,
  263. // haveSira, siraCard)
  264. if haveProject {
  265. for _, card := range cards {
  266. if haveStraightFlush {
  267. projectCards = append(projectCards, card)
  268. continue
  269. } else if haveFourOfAKind && GetCardValue(card) == fourOfAKindValue {
  270. projectCards = append(projectCards, card)
  271. continue
  272. } else if haveFifty && IsContainInt(fiftyCard, card) {
  273. projectCards = append(projectCards, card)
  274. continue
  275. } else if haveBaloot && (GetCardValue(card) == 5 || GetCardValue(card) == 6) && IsTrump(card, trumpType) {
  276. //检查是否有主花色的Baloot
  277. projectCards = append(projectCards, card)
  278. continue
  279. } else if haveSira && IsContainInt(siraCard, card) {
  280. projectCards = append(projectCards, card)
  281. continue
  282. }
  283. mainCards = append(mainCards, card)
  284. }
  285. //有项目的情况下其他牌按大小排序
  286. // sort.Slice(mainCards, func(i, j int) bool {
  287. // if IsTrump(mainCards[i], trumpType) != IsTrump(mainCards[j], trumpType) {
  288. // return !IsTrump(mainCards[i], trumpType)
  289. // }
  290. // if GetCardType(mainCards[i]) != GetCardType(mainCards[j]) {
  291. // return GetCardType(mainCards[i]) < GetCardType(mainCards[j])
  292. // }
  293. // return GetCardValue(mainCards[i]) < GetCardValue(mainCards[j])
  294. // })
  295. // sort.Slice(projectCards, func(i, j int) bool {
  296. // if IsTrump(projectCards[i], trumpType) != IsTrump(projectCards[j], trumpType) {
  297. // return !IsTrump(projectCards[i], trumpType)
  298. // }
  299. // if GetCardType(projectCards[i]) != GetCardType(projectCards[j]) {
  300. // return GetCardType(projectCards[i]) < GetCardType(projectCards[j])
  301. // }
  302. // return GetCardValue(projectCards[i]) < GetCardValue(projectCards[j])
  303. // })
  304. //cardTypeOrder := sortCardType(mainCardType)
  305. //SortCardsByType(mainCards, cardTypeOrder, trumpType)
  306. //SortCardsByType(projectCards, cardTypeOrder, trumpType)
  307. } else {
  308. mainCards = append(mainCards, cards...)
  309. //没有项目的情况 和主牌一个花色的牌按照value_trump牌值排序 其他花色的牌按照value_regular牌值排序
  310. SortCardsByScore(mainCards, trumpType)
  311. maxCard = mainCards[len(mainCards)-1]
  312. }
  313. cardTypeOrder := sortCardType(mainCardType)
  314. SortCardsByType(mainCards, cardTypeOrder, trumpType)
  315. if haveProject {
  316. SortCardsByType(projectCards, cardTypeOrder, trumpType)
  317. mainCards = append(mainCards, projectCards...)
  318. }
  319. return mainCards, project, projectLength, maxCard
  320. }
  321. // 是否为Baloot
  322. func isBaloot(cards []int, trumpType int) bool {
  323. haveTrumpQ := false
  324. haveTrumpK := false
  325. for i := 0; i < len(cards); i++ {
  326. if cards[i] == trumpType*8+CardValueQ {
  327. haveTrumpQ = true
  328. }
  329. if cards[i] == trumpType*8+CardValueK {
  330. haveTrumpK = true
  331. }
  332. }
  333. return haveTrumpQ && haveTrumpK
  334. }
  335. // 得到炸弹牌值,如果为-1则表示没有炸弹 7,8,9不算炸弹
  336. func getFourOfAKind(cards []int) int {
  337. counts := make(map[int]int)
  338. for _, card := range cards {
  339. value := GetCardValue(card)
  340. if value != CardValue7 && value != CardValue8 && value != CardValue9 {
  341. counts[value]++
  342. }
  343. }
  344. for v, count := range counts {
  345. if count == 4 {
  346. return v
  347. }
  348. }
  349. return -1
  350. }
  351. // 检查是否为同花顺
  352. func isStraightFlush(cards []int, minLength int) (bool, []int) {
  353. if len(cards) < minLength {
  354. return false, nil
  355. }
  356. // sort.Ints(cards)
  357. for i := 0; i <= len(cards)-minLength; i++ {
  358. cardType := GetCardType(cards[i])
  359. isStraightFlush := true
  360. for j := i + 1; j < i+minLength; j++ {
  361. if GetCardType(cards[j]) != cardType || GetCardValue(cards[j])-GetCardValue(cards[j-1]) != 1 {
  362. isStraightFlush = false
  363. break
  364. }
  365. }
  366. if isStraightFlush {
  367. return true, cards[i : i+minLength]
  368. }
  369. }
  370. return false, nil
  371. }
  372. // 检查是否有4张同花顺
  373. func isFifty(cards []int) []int {
  374. if len(cards) != 5 {
  375. return nil
  376. }
  377. _, result := isStraightFlush(cards, 4)
  378. return result
  379. }
  380. // 检查是否有3张同花顺
  381. func isSira(cards []int) []int {
  382. if len(cards) != 5 {
  383. return nil
  384. }
  385. _, result := isStraightFlush(cards, 3)
  386. return result
  387. }
  388. func IsContainInt(items []int, item int) bool {
  389. for _, eachItem := range items {
  390. if eachItem == item {
  391. return true
  392. }
  393. }
  394. return false
  395. }
  396. func getRanking(ranking []int, rankingMode RankingMode) (int, []int) {
  397. if len(ranking) == 0 {
  398. return -1, ranking
  399. }
  400. if len(ranking) == 1 {
  401. return ranking[0], []int{}
  402. }
  403. var randomRank int
  404. if rankingMode == Random {
  405. randomIndex := rand.Intn(len(ranking))
  406. randomRank = ranking[randomIndex]
  407. } else {
  408. maxRanking := ranking[0]
  409. minRanking := ranking[0]
  410. for _, f := range ranking {
  411. if f < maxRanking {
  412. maxRanking = f
  413. }
  414. if f > minRanking {
  415. minRanking = f
  416. }
  417. }
  418. if rankingMode == Max {
  419. randomRank = maxRanking
  420. } else if rankingMode == Min {
  421. randomRank = minRanking
  422. }
  423. }
  424. newRanking := make([]int, 0)
  425. removed := false
  426. for _, f := range ranking {
  427. if f == randomRank && !removed {
  428. removed = true
  429. continue
  430. }
  431. newRanking = append(newRanking, f)
  432. }
  433. return randomRank, newRanking
  434. }
  435. // 根据类型排序卡牌花色顺序 主花色在最后 其他花色逆时针排序
  436. func sortCardType(cardType int) []int {
  437. if cardType < CardType_Diamond || cardType > CardType_Spade {
  438. return []int{}
  439. }
  440. order := make([]int, 4)
  441. for i := 0; i < 4; i++ {
  442. offset := (i - (cardType + 1) + 4) % 4 // 加4避免越界
  443. order[offset] = i
  444. }
  445. return order
  446. }