package gamelogic import ( "math/rand" "os" "path/filepath" "sort" "strconv" "bet24.com/log" cardlibrary "bet24.com/servers/micros/cardlibrary/proto" "bet24.com/utils" "github.com/360EntSecGroup-Skylar/excelize" ) type cardlogic struct { cards []int trumpType int suit int currentCardIndex int isFirstOutCardClose bool } func newCardLogic() *cardlogic { ret := new(cardlogic) ret.initData() return ret } func (cl *cardlogic) initData() { cl.trumpType = CardType_Invalid cl.suit = Suit_Invalid cl.shuffle(false, -1, -1, -1, false) } func (cl *cardlogic) readBalootCards() bool { fileName := "balootcards.xlsx" sheetName := "Sheet1" readFile, err := excelize.OpenFile(filepath.Join("./baloot_excel/", fileName)) if err != nil { return false } cards := []int{} for rowIndex, readRow := range readFile.GetRows(sheetName) { if rowIndex > 0 { break } for _, colCell := range readRow { value, _ := strconv.Atoi(colCell) if isValidCard(value) { cards = append(cards, value) } } } if len(cards) == 0 || len(cards) > CARD_COUNT { return false } for d := 0; d < CARD_COUNT; d++ { cl.cards[d] = d } for i := CARD_COUNT - 1; i > 1; i-- { place := rand.Intn(i) tmp := cl.cards[place] cl.cards[place] = cl.cards[i] cl.cards[i] = tmp } for n := 0; n < len(cards); n++ { pos := -1 for j := 0; j < CARD_COUNT; j++ { if cards[n] == cl.cards[j] { pos = j break } } if pos == -1 { continue } tmp := cl.cards[pos] cl.cards[n] = cards[n] cl.cards[pos] = tmp } return true } func (cl *cardlogic) shuffle(test bool, controlChair, firstOutCard, doubling int, isNewUser bool) { cl.trumpType = CardType_Invalid cl.currentCardIndex = 0 cl.isFirstOutCardClose = false cl.cards = make([]int, CARD_COUNT) if test { ret := cl.readBalootCards() if ret { return } } if isValidChair(controlChair) { libraryType := cardlibrary.Baloot_LibraryType_Scenario r := rand.Intn(100) if r >= 80 && r < 90 { libraryType = cardlibrary.Baloot_LibraryType_Invincible } else if r >= 90 { libraryType = cardlibrary.Baloot_LibraryType_HighScore } if doubling >= 0 { libraryType = cardlibrary.Baloot_LibraryType_Doubling if r >= 50 { libraryType = cardlibrary.Baloot_LibraryType_Doubling_Scenario } } if isNewUser { libraryType = cardlibrary.Baloot_LibraryType_NewUser } success, cardList := cardlibrary.GetControlCards(libraryType, controlChair, firstOutCard, doubling) if success { cl.cards = cardList return } } for d := 0; d < CARD_COUNT; d++ { cl.cards[d] = d } for i := CARD_COUNT - 1; i > 1; i-- { place := rand.Intn(i) tmp := cl.cards[place] cl.cards[place] = cl.cards[i] cl.cards[i] = tmp } } func (cl *cardlogic) getCardsByProjectDesc(project cardlibrary.ProjectConf, startIndex int) []int { cards := []int{} cardList := []int{} for n := cl.currentCardIndex + startIndex; n < CARD_COUNT; n++ { cardList = append(cardList, cl.cards[n]) } switch project.ProjectDesc { case "三联顺": value, bHaveSerial := haveSerial(3, cardList) if bHaveSerial { for n := value - 2; n <= value; n++ { cards = append(cards, n) } } case "四联顺": value, bHaveSerial := haveSerial(4, cardList) if bHaveSerial { for n := value - 3; n <= value; n++ { cards = append(cards, n) } } case "五联顺": value, bHaveSerial := haveSerial(5, cardList) if bHaveSerial { for n := value - 4; n <= value; n++ { cards = append(cards, n) } } case "四张相同": value, bHaveFour := 0, false for i := CardValue10; i <= CardValueA; i++ { count := 0 for n := 0; n < len(cardList); n++ { if cardList[n]%8 == i { count++ } } if count == 4 { value = i bHaveFour = true break } } if bHaveFour { for i := 0; i < 4; i++ { card := value + i*8 cards = append(cards, card) } } } return cards } func (cl *cardlogic) getNormalCardsInControl(userId int) []int { maxCount := BUY_PHRSE_HOLD_CARD ret := make([]int, maxCount) success, librarys := cardlibrary.GetUserControlCards(userId) if success { getCount := 0 for l := 0; l < len(librarys); l++ { library := librarys[l] for n := 0; n < len(library.Cards); n++ { if getCount >= 6 { break } for m := 0; m < library.Cards[n].Count; m++ { if getCount >= 6 { break } pos := -1 for j := cl.currentCardIndex + getCount; j < CARD_COUNT; j++ { if getCardValueByDesc(library.Cards[n].ValueDesc) == getCardValue(cl.cards[j]) { pos = j break } } if pos == -1 { continue } if getCount >= 6 { tmp := cl.cards[pos] cl.cards[pos] = cl.cards[PUBLIC_CARD_POS] cl.cards[PUBLIC_CARD_POS] = tmp break } tmp := cl.cards[pos] cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount] cl.cards[cl.currentCardIndex+getCount] = tmp getCount++ } } if getCount < 6 { for i := 0; i < len(library.Projects); i++ { if getCount >= 6 { break } if library.Projects[i].Count == 0 { continue } for m := 0; m < library.Projects[i].Count; m++ { if getCount >= 6 { break } startIndex := getCount cardList := cl.getCardsByProjectDesc(library.Projects[i], startIndex) for n := 0; n < len(cardList); n++ { if getCount >= 6 { break } pos := -1 for j := cl.currentCardIndex + startIndex; j < CARD_COUNT; j++ { if cardList[n] == cl.cards[j] { pos = j break } } if pos == -1 { continue } if getCount >= 6 { tmp := cl.cards[pos] cl.cards[pos] = cl.cards[PUBLIC_CARD_POS] cl.cards[PUBLIC_CARD_POS] = tmp break } tmp := cl.cards[pos] cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount] cl.cards[cl.currentCardIndex+getCount] = tmp getCount++ } } } } if getCount < 6 { startIndex := getCount rType := rand.Intn(4) for n := 0; n < library.SameTypeCount; n++ { if getCount >= 6 { break } pos := -1 for j := cl.currentCardIndex + startIndex; j < CARD_COUNT; j++ { if rType == getCardType(cl.cards[j]) { pos = j break } } if pos == -1 { continue } if getCount >= 6 { tmp := cl.cards[pos] cl.cards[pos] = cl.cards[PUBLIC_CARD_POS] cl.cards[PUBLIC_CARD_POS] = tmp break } tmp := cl.cards[pos] cl.cards[pos] = cl.cards[cl.currentCardIndex+getCount] cl.cards[cl.currentCardIndex+getCount] = tmp getCount++ } } pos := -1 for j := cl.currentCardIndex + getCount; j < CARD_COUNT; j++ { if getCardValueByDesc(library.PublicCard) == getCardValue(cl.cards[j]) { pos = j break } } if pos != -1 { tmp := cl.cards[pos] cl.cards[pos] = cl.cards[PUBLIC_CARD_POS] cl.cards[PUBLIC_CARD_POS] = tmp } if getCount > 0 { break } } } for i := 0; i < maxCount; i++ { ret[i] = cl.getOneCard() } sort.Slice(ret, func(i, j int) bool { return getCardSortValue(ret[i], CardType_Invalid) < getCardSortValue(ret[j], CardType_Invalid) }) return ret } func (cl *cardlogic) getNormalCards() []int { maxCount := BUY_PHRSE_HOLD_CARD ret := make([]int, maxCount) for i := 0; i < maxCount; i++ { ret[i] = cl.getOneCard() } sort.Slice(ret, func(i, j int) bool { return getCardSortValue(ret[i], CardType_Invalid) < getCardSortValue(ret[j], CardType_Invalid) }) return ret } func (cl *cardlogic) getOneCard() int { ret := cl.cards[cl.currentCardIndex] cl.currentCardIndex++ return ret } func (cl *cardlogic) getLeftCards(bBuyChiar bool) []int { maxCount := SURPLUS_SEND_CARD if bBuyChiar { maxCount-- } ret := make([]int, maxCount) for i := 0; i < maxCount; i++ { ret[i] = cl.getOneCard() } return ret } func (cl *cardlogic) setTrumpAndSuit(t, s int) { cl.trumpType = t cl.suit = s } func (cl *cardlogic) setIsFirstOutCardClose(isClose bool) { cl.isFirstOutCardClose = isClose } // 能否出这张牌 func (cl *cardlogic) canOut(card int, cardType int, handCards []int) bool { found := false for _, v := range handCards { if v == card { found = true } } if !found { log.Release("cardlogic.canOut %d not exist in [%v]", card, handCards) return false } if cardType == CardType_Invalid { return true } t := getCardType(card) if t == cardType { return true } foundSameType := false for _, v := range handCards { if cardType == getCardType(v) { foundSameType = true } } return !foundSameType } func (cl *cardlogic) getCardRank(card int, referType int) int { if !isValidCard(card) { return -2 } cardType := getCardType(card) cardScore := 0 if cardType == cl.trumpType { cardScore += 100 } else if cardType != referType { return -1 } value := getCardCompareValue(card, cl.trumpType) return cardScore + value } // outCards 按椅子顺序的出牌 func (cl *cardlogic) getWinner(outCards []int, referType int) int { ranks := make([]int, CHAIR_COUNT) winner := -1 bestRank := -2 for i := 0; i < CHAIR_COUNT; i++ { ranks[i] = cl.getCardRank(outCards[i], referType) if ranks[i] > bestRank { bestRank = ranks[i] winner = i } } return winner } func (cl *cardlogic) worstCard(cards []int, cardType int) int { if len(cards) == 0 { return CARD_COUNT } if len(cards) == 1 { return cards[0] } // 先按花色存储 sortedCards := sortCards(cards) if cardType != CardType_Invalid && len(sortedCards[cardType]) > 0 { return sortedCards[cardType][0] } typeCounts := make([]int, 4) minIndex := -1 minCount := 8 maxIndex := -1 maxCount := 0 for i := 0; i < len(typeCounts); i++ { typeCounts[i] = len(sortedCards[i]) if i == cl.trumpType || typeCounts[i] == 0 { continue } if typeCounts[i] < minCount { minCount = typeCounts[i] minIndex = i } if typeCounts[i] > maxCount { maxCount = typeCounts[i] maxIndex = i } } // 如果我有主,则丢一张最少花色的牌 否则丢最多花色的牌 if cl.trumpType == CardType_Invalid { if maxIndex > 0 { return sortedCards[maxIndex][0] } return cards[0] } if typeCounts[cl.trumpType] == 0 { if maxIndex > 0 { return sortedCards[maxIndex][0] } } else { if minIndex >= 0 { if cl.isFirstOutCardClose && minIndex == cl.trumpType && cardType == CardType_Invalid { for i := 0; i < len(cards); i++ { if getCardType(cards[i]) != cl.trumpType { return cards[i] } } } else { return sortedCards[minIndex][0] } } } return cards[0] } func (cl *cardlogic) getBestProject(cardList []int) []int { ret := make([]int, 4) for i := PROJECT_FOURHUNDRED; i >= PROJECT_SIRA; i-- { if cl.suit == Suit_Hokum && i == PROJECT_FOURHUNDRED { continue } for n := 0; n < 2; n++ { cards, bInclude := isIncludeTheProject(cardList, i, cl.suit) if bInclude { cardList = removeCards(cardList, cards) ret[i]++ } } } return ret } func (cl *cardlogic) test() bool { if len(os.Args) < 2 { return false } defer utils.TimeCost("cardlogic.test")() return true }