cardlogic.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. package gamelogic
  2. import (
  3. "math/rand"
  4. "os"
  5. "path/filepath"
  6. "sort"
  7. "strconv"
  8. "bet24.com/log"
  9. cardlibrary "bet24.com/servers/micros/cardlibrary/proto"
  10. "bet24.com/utils"
  11. "github.com/360EntSecGroup-Skylar/excelize"
  12. )
  13. type cardlogic struct {
  14. cards []int
  15. trumpType int
  16. suit int
  17. currentCardIndex int
  18. isFirstOutCardClose bool
  19. }
  20. func newCardLogic() *cardlogic {
  21. ret := new(cardlogic)
  22. ret.initData()
  23. return ret
  24. }
  25. func (cl *cardlogic) initData() {
  26. cl.trumpType = CardType_Invalid
  27. cl.suit = Suit_Invalid
  28. cl.shuffle(false, -1, -1, -1, false)
  29. }
  30. func (cl *cardlogic) readBalootCards() bool {
  31. fileName := "balootcards.xlsx"
  32. sheetName := "Sheet1"
  33. readFile, err := excelize.OpenFile(filepath.Join("./baloot_excel/", fileName))
  34. if err != nil {
  35. return false
  36. }
  37. cards := []int{}
  38. for rowIndex, readRow := range readFile.GetRows(sheetName) {
  39. if rowIndex > 0 {
  40. break
  41. }
  42. for _, colCell := range readRow {
  43. value, _ := strconv.Atoi(colCell)
  44. if isValidCard(value) {
  45. cards = append(cards, value)
  46. }
  47. }
  48. }
  49. if len(cards) == 0 || len(cards) > CARD_COUNT {
  50. return false
  51. }
  52. for d := 0; d < CARD_COUNT; d++ {
  53. cl.cards[d] = d
  54. }
  55. for i := CARD_COUNT - 1; i > 1; i-- {
  56. place := rand.Intn(i)
  57. tmp := cl.cards[place]
  58. cl.cards[place] = cl.cards[i]
  59. cl.cards[i] = tmp
  60. }
  61. for n := 0; n < len(cards); n++ {
  62. pos := -1
  63. for j := 0; j < CARD_COUNT; j++ {
  64. if cards[n] == cl.cards[j] {
  65. pos = j
  66. break
  67. }
  68. }
  69. if pos == -1 {
  70. continue
  71. }
  72. tmp := cl.cards[pos]
  73. cl.cards[n] = cards[n]
  74. cl.cards[pos] = tmp
  75. }
  76. return true
  77. }
  78. func (cl *cardlogic) shuffle(test bool, controlChair, firstOutCard, doubling int, isNewUser bool) {
  79. cl.trumpType = CardType_Invalid
  80. cl.currentCardIndex = 0
  81. cl.isFirstOutCardClose = false
  82. cl.cards = make([]int, CARD_COUNT)
  83. if test {
  84. ret := cl.readBalootCards()
  85. if ret {
  86. return
  87. }
  88. }
  89. if isValidChair(controlChair) {
  90. libraryType := cardlibrary.Baloot_LibraryType_Scenario
  91. r := rand.Intn(100)
  92. if r >= 80 && r < 90 {
  93. libraryType = cardlibrary.Baloot_LibraryType_Invincible
  94. } else if r >= 90 {
  95. libraryType = cardlibrary.Baloot_LibraryType_HighScore
  96. }
  97. if doubling >= 0 {
  98. libraryType = cardlibrary.Baloot_LibraryType_Doubling
  99. if r >= 50 {
  100. libraryType = cardlibrary.Baloot_LibraryType_Doubling_Scenario
  101. }
  102. }
  103. if isNewUser {
  104. libraryType = cardlibrary.Baloot_LibraryType_NewUser
  105. }
  106. success, cardList := cardlibrary.GetControlCards(libraryType, controlChair, firstOutCard, doubling)
  107. if success {
  108. cl.cards = cardList
  109. return
  110. }
  111. }
  112. for d := 0; d < CARD_COUNT; d++ {
  113. cl.cards[d] = d
  114. }
  115. for i := CARD_COUNT - 1; i > 1; i-- {
  116. place := rand.Intn(i)
  117. tmp := cl.cards[place]
  118. cl.cards[place] = cl.cards[i]
  119. cl.cards[i] = tmp
  120. }
  121. }
  122. func (cl *cardlogic) getCardsByProjectDesc(project cardlibrary.ProjectConf, startIndex int) []int {
  123. cards := []int{}
  124. cardList := []int{}
  125. for n := cl.currentCardIndex + startIndex; n < CARD_COUNT; n++ {
  126. cardList = append(cardList, cl.cards[n])
  127. }
  128. switch project.ProjectDesc {
  129. case "三联顺":
  130. value, bHaveSerial := haveSerial(3, cardList)
  131. if bHaveSerial {
  132. for n := value - 2; n <= value; n++ {
  133. cards = append(cards, n)
  134. }
  135. }
  136. case "四联顺":
  137. value, bHaveSerial := haveSerial(4, cardList)
  138. if bHaveSerial {
  139. for n := value - 3; n <= value; n++ {
  140. cards = append(cards, n)
  141. }
  142. }
  143. case "五联顺":
  144. value, bHaveSerial := haveSerial(5, cardList)
  145. if bHaveSerial {
  146. for n := value - 4; n <= value; n++ {
  147. cards = append(cards, n)
  148. }
  149. }
  150. case "四张相同":
  151. value, bHaveFour := 0, false
  152. for i := CardValue10; i <= CardValueA; i++ {
  153. count := 0
  154. for n := 0; n < len(cardList); n++ {
  155. if cardList[n]%8 == i {
  156. count++
  157. }
  158. }
  159. if count == 4 {
  160. value = i
  161. bHaveFour = true
  162. break
  163. }
  164. }
  165. if bHaveFour {
  166. for i := 0; i < 4; i++ {
  167. card := value + i*8
  168. cards = append(cards, card)
  169. }
  170. }
  171. }
  172. return cards
  173. }
  174. func (cl *cardlogic) getNormalCardsInControl(userId int) []int {
  175. maxCount := BUY_PHRSE_HOLD_CARD
  176. ret := make([]int, maxCount)
  177. success, librarys := cardlibrary.GetUserControlCards(userId)
  178. if success {
  179. getCount := 0
  180. for l := 0; l < len(librarys); l++ {
  181. library := librarys[l]
  182. for n := 0; n < len(library.Cards); n++ {
  183. if getCount >= 6 {
  184. break
  185. }
  186. for m := 0; m < library.Cards[n].Count; m++ {
  187. if getCount >= 6 {
  188. break
  189. }
  190. pos := -1
  191. for j := cl.currentCardIndex + getCount; j < CARD_COUNT; j++ {
  192. if getCardValueByDesc(library.Cards[n].ValueDesc) == getCardValue(cl.cards[j]) {
  193. pos = j
  194. break
  195. }
  196. }
  197. if pos == -1 {
  198. continue
  199. }
  200. if getCount >= 6 {
  201. tmp := cl.cards[pos]
  202. cl.cards[pos] = cl.cards[PUBLIC_CARD_POS]
  203. cl.cards[PUBLIC_CARD_POS] = tmp
  204. break
  205. }
  206. tmp := cl.cards[pos]
  207. cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount]
  208. cl.cards[cl.currentCardIndex+getCount] = tmp
  209. getCount++
  210. }
  211. }
  212. if getCount < 6 {
  213. for i := 0; i < len(library.Projects); i++ {
  214. if getCount >= 6 {
  215. break
  216. }
  217. if library.Projects[i].Count == 0 {
  218. continue
  219. }
  220. for m := 0; m < library.Projects[i].Count; m++ {
  221. if getCount >= 6 {
  222. break
  223. }
  224. startIndex := getCount
  225. cardList := cl.getCardsByProjectDesc(library.Projects[i], startIndex)
  226. for n := 0; n < len(cardList); n++ {
  227. if getCount >= 6 {
  228. break
  229. }
  230. pos := -1
  231. for j := cl.currentCardIndex + startIndex; j < CARD_COUNT; j++ {
  232. if cardList[n] == cl.cards[j] {
  233. pos = j
  234. break
  235. }
  236. }
  237. if pos == -1 {
  238. continue
  239. }
  240. if getCount >= 6 {
  241. tmp := cl.cards[pos]
  242. cl.cards[pos] = cl.cards[PUBLIC_CARD_POS]
  243. cl.cards[PUBLIC_CARD_POS] = tmp
  244. break
  245. }
  246. tmp := cl.cards[pos]
  247. cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount]
  248. cl.cards[cl.currentCardIndex+getCount] = tmp
  249. getCount++
  250. }
  251. }
  252. }
  253. }
  254. if getCount < 6 {
  255. startIndex := getCount
  256. rType := rand.Intn(4)
  257. for n := 0; n < library.SameTypeCount; n++ {
  258. if getCount >= 6 {
  259. break
  260. }
  261. pos := -1
  262. for j := cl.currentCardIndex + startIndex; j < CARD_COUNT; j++ {
  263. if rType == getCardType(cl.cards[j]) {
  264. pos = j
  265. break
  266. }
  267. }
  268. if pos == -1 {
  269. continue
  270. }
  271. if getCount >= 6 {
  272. tmp := cl.cards[pos]
  273. cl.cards[pos] = cl.cards[PUBLIC_CARD_POS]
  274. cl.cards[PUBLIC_CARD_POS] = tmp
  275. break
  276. }
  277. tmp := cl.cards[pos]
  278. cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount]
  279. cl.cards[cl.currentCardIndex+getCount] = tmp
  280. getCount++
  281. }
  282. }
  283. pos := -1
  284. for j := cl.currentCardIndex + getCount; j < CARD_COUNT; j++ {
  285. if getCardValueByDesc(library.PublicCard) == getCardValue(cl.cards[j]) {
  286. pos = j
  287. break
  288. }
  289. }
  290. if pos != -1 {
  291. tmp := cl.cards[pos]
  292. cl.cards[pos] = cl.cards[PUBLIC_CARD_POS]
  293. cl.cards[PUBLIC_CARD_POS] = tmp
  294. }
  295. if getCount > 0 {
  296. break
  297. }
  298. }
  299. }
  300. for i := 0; i < maxCount; i++ {
  301. ret[i] = cl.getOneCard()
  302. }
  303. sort.Slice(ret, func(i, j int) bool {
  304. return getCardSortValue(ret[i], CardType_Invalid) < getCardSortValue(ret[j], CardType_Invalid)
  305. })
  306. return ret
  307. }
  308. func (cl *cardlogic) getNormalCards() []int {
  309. maxCount := BUY_PHRSE_HOLD_CARD
  310. ret := make([]int, maxCount)
  311. for i := 0; i < maxCount; i++ {
  312. ret[i] = cl.getOneCard()
  313. }
  314. sort.Slice(ret, func(i, j int) bool {
  315. return getCardSortValue(ret[i], CardType_Invalid) < getCardSortValue(ret[j], CardType_Invalid)
  316. })
  317. return ret
  318. }
  319. func (cl *cardlogic) getOneCard() int {
  320. ret := cl.cards[cl.currentCardIndex]
  321. cl.currentCardIndex++
  322. return ret
  323. }
  324. func (cl *cardlogic) getLeftCards(bBuyChiar bool) []int {
  325. maxCount := SURPLUS_SEND_CARD
  326. if bBuyChiar {
  327. maxCount--
  328. }
  329. ret := make([]int, maxCount)
  330. for i := 0; i < maxCount; i++ {
  331. ret[i] = cl.getOneCard()
  332. }
  333. return ret
  334. }
  335. func (cl *cardlogic) setTrumpAndSuit(t, s int) {
  336. cl.trumpType = t
  337. cl.suit = s
  338. }
  339. func (cl *cardlogic) setIsFirstOutCardClose(isClose bool) {
  340. cl.isFirstOutCardClose = isClose
  341. }
  342. // 能否出这张牌
  343. func (cl *cardlogic) canOut(card int, cardType int, handCards []int) bool {
  344. found := false
  345. for _, v := range handCards {
  346. if v == card {
  347. found = true
  348. }
  349. }
  350. if !found {
  351. log.Release("cardlogic.canOut %d not exist in [%v]", card, handCards)
  352. return false
  353. }
  354. if cardType == CardType_Invalid {
  355. return true
  356. }
  357. t := getCardType(card)
  358. if t == cardType {
  359. return true
  360. }
  361. foundSameType := false
  362. for _, v := range handCards {
  363. if cardType == getCardType(v) {
  364. foundSameType = true
  365. }
  366. }
  367. return !foundSameType
  368. }
  369. func (cl *cardlogic) getCardRank(card int, referType int) int {
  370. if !isValidCard(card) {
  371. return -2
  372. }
  373. cardType := getCardType(card)
  374. cardScore := 0
  375. if cardType == cl.trumpType {
  376. cardScore += 100
  377. } else if cardType != referType {
  378. return -1
  379. }
  380. value := getCardCompareValue(card, cl.trumpType)
  381. return cardScore + value
  382. }
  383. // outCards 按椅子顺序的出牌
  384. func (cl *cardlogic) getWinner(outCards []int, referType int) int {
  385. ranks := make([]int, CHAIR_COUNT)
  386. winner := -1
  387. bestRank := -2
  388. for i := 0; i < CHAIR_COUNT; i++ {
  389. ranks[i] = cl.getCardRank(outCards[i], referType)
  390. if ranks[i] > bestRank {
  391. bestRank = ranks[i]
  392. winner = i
  393. }
  394. }
  395. return winner
  396. }
  397. func (cl *cardlogic) worstCard(cards []int, cardType int) int {
  398. if len(cards) == 0 {
  399. return CARD_COUNT
  400. }
  401. if len(cards) == 1 {
  402. return cards[0]
  403. }
  404. // 先按花色存储
  405. sortedCards := sortCards(cards)
  406. if cardType != CardType_Invalid && len(sortedCards[cardType]) > 0 {
  407. return sortedCards[cardType][0]
  408. }
  409. typeCounts := make([]int, 4)
  410. minIndex := -1
  411. minCount := 8
  412. maxIndex := -1
  413. maxCount := 0
  414. for i := 0; i < len(typeCounts); i++ {
  415. typeCounts[i] = len(sortedCards[i])
  416. if i == cl.trumpType || typeCounts[i] == 0 {
  417. continue
  418. }
  419. if typeCounts[i] < minCount {
  420. minCount = typeCounts[i]
  421. minIndex = i
  422. }
  423. if typeCounts[i] > maxCount {
  424. maxCount = typeCounts[i]
  425. maxIndex = i
  426. }
  427. }
  428. // 如果我有主,则丢一张最少花色的牌 否则丢最多花色的牌
  429. if cl.trumpType == CardType_Invalid {
  430. if maxIndex > 0 {
  431. return sortedCards[maxIndex][0]
  432. }
  433. return cards[0]
  434. }
  435. if typeCounts[cl.trumpType] == 0 {
  436. if maxIndex > 0 {
  437. return sortedCards[maxIndex][0]
  438. }
  439. } else {
  440. if minIndex >= 0 {
  441. if cl.isFirstOutCardClose &&
  442. minIndex == cl.trumpType &&
  443. cardType == CardType_Invalid {
  444. for i := 0; i < len(cards); i++ {
  445. if getCardType(cards[i]) != cl.trumpType {
  446. return cards[i]
  447. }
  448. }
  449. } else {
  450. return sortedCards[minIndex][0]
  451. }
  452. }
  453. }
  454. return cards[0]
  455. }
  456. func (cl *cardlogic) getBestProject(cardList []int) []int {
  457. ret := make([]int, 4)
  458. for i := PROJECT_FOURHUNDRED; i >= PROJECT_SIRA; i-- {
  459. if cl.suit == Suit_Hokum && i == PROJECT_FOURHUNDRED {
  460. continue
  461. }
  462. for n := 0; n < 2; n++ {
  463. cards, bInclude := isIncludeTheProject(cardList, i, cl.suit)
  464. if bInclude {
  465. cardList = removeCards(cardList, cards)
  466. ret[i]++
  467. }
  468. }
  469. }
  470. return ret
  471. }
  472. func (cl *cardlogic) test() bool {
  473. if len(os.Args) < 2 {
  474. return false
  475. }
  476. defer utils.TimeCost("cardlogic.test")()
  477. return true
  478. }