package samloc import ( "sort" ) const ( Pass int = iota //0 nil Single //1 单张 Twin //2 对子 Triple //3 三张 Straight //4 顺子 Four //5 四张 TwinFour //6 两组四张 StraightFiveTriple //7 五连对 ThreeTriple //8 三个三张 ColorSame //9 同色 Four2 //10 四张二 TenStraight //11 一条龙 ) const ( POKER_3 int32 = iota // 0 POKER_4 // 1 POKER_5 // 2 POKER_6 // 3 POKER_7 // 4 POKER_8 // 5 POKER_9 // 6 POKER_10 // 7 POKER_J // 8 POKER_Q // 9 POKER_K // 10 POKER_A // 11 POKER_2 // 12 ) const ( Club int = iota //0,黑桃 Spade //1,梅花 Diamond //2,方块 Heart //3,红桃 ) const ( Score2 int32 = 15 //4张 压2 ScoreFour int32 = 20 //4张 压4张 ScoreBaoSam int32 = 20 //baosam ScoreLore int32 = 20 // 通杀 Baopei2 int32 = 10 // 包赔 Treo int32 = 15 // 结束游戏后而不打出任何牌 ) const ( BaosamNot int = 1 // 0 非baosam 正常结算 BaosamWin int = 2 // 1 baosam赢 BaosamLose int = 4 // 2 baosam输 SamLore int = 8 // 2 通杀 ) // KindOfCard 牌型 type KindOfCard struct { kind int //牌型 // cards []int32 //出牌 min int32 //最小牌 max int32 //最大牌 len int32 //牌的长度 same int32 //同牌数量 33 -> 2 num int32 //牌的数量 ktype int //牌的权重 } func (this *KindOfCard) GetKind() int { return this.kind } func (this *KindOfCard) GetLen() int32 { return this.len } func (this *KindOfCard) GetMin() int32 { return this.min } func (this *KindOfCard) GetSame() int32 { return this.same } func (this *KindOfCard) GetNum() int32 { return this.num } type Kds struct { kd []*KindOfCard } func (this *Kds) Len() int { return len(this.kd) } func (this *Kds) Swap(i, j int) { this.kd[i], this.kd[j] = this.kd[j], this.kd[i] } func (this *Kds) Less(i, j int) bool { if this.kd[i].ktype > this.kd[j].ktype { // 大到小 return true } else if this.kd[i].ktype < this.kd[j].ktype { return false } if this.kd[i].len > this.kd[j].len { return true } if this.kd[i].min < this.kd[j].min { if this.kd[i].min < 0 { // A 2做连 往后放 return false } return true } return false // 小到大 } //func (this *KindOfCard) GetCards() []int32 { return this.cards } func (this *KindOfCard) OutPokers(poker []int32) []int32 { pok := make([]int32, len(poker)) copy(pok, poker) var ret []int32 if this != nil && this.num != 0 { for i := this.min; i <= this.max; { va := i if va < 0 { va = va + POKER_2 + 1 } for j := 0; j != int(this.same); j++ { for k, v := range pok { if Value32(v) == va { ret = append(ret, v) pok = append(pok[:k], pok[k+1:]...) // del break } } } if this.same > 3 && i != this.max { i = this.max } else { i++ } } } return ret } // SortInt32 []int32 type SortInt32 []int32 func (a SortInt32) Len() int { return len(a) } func (a SortInt32) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a SortInt32) Less(i, j int) bool { b := Value(a[i]) c := Value(a[j]) if b == c { return b < c } return b < c } // Color 黑桃0 梅花1 方片2 紅桃3 func Color(c int32) int { return int(c) / PER_CARD_COLOR_MAX } func RedColor(c int32) int { // Heart 红色 Club 黑色 if (int(c) / PER_CARD_COLOR_MAX) > Spade { return Heart } return Club } func Value(c int32) int { return int(c) % PER_CARD_COLOR_MAX } func Value32(c int32) int32 { return c % PER_CARD_COLOR_MAX } func ValueStr(c int32) int { if int(c+3)%PER_CARD_COLOR_MAX == 0 { return PER_CARD_COLOR_MAX } return int(c+3) % PER_CARD_COLOR_MAX } func IsSingle(cards []int32) bool { //单张 if len(cards) == 1 { return true } return false } func IsContainPOKER2(cards []int32) bool { //全是2 for _, v := range cards { if Value32(v) == POKER_2 { return true } } return false } func IsHavePOKER2(cards []int32) bool { //全是2 for _, v := range cards { if v == InvalideCard { continue } if Value32(v) != POKER_2 { return false } } return true } func DelOtherPOKER2(cards []int32, del []int32) bool { //全是2 cpcards := append([]int32{}, cards...) for _, v := range del { for i, k := range cpcards { if v == k { cpcards[i] = InvalideCard } } } num := 0 for _, v := range cpcards { if v == InvalideCard { num++ continue } if Value32(v) != POKER_2 { return false } } if num == Hand_CardNum { return false } return true } func GetMaxCard(cards []int32) int32 { //单张 max := int32(0) for _, v := range cards { if v != InvalideCard { vv := Value32(v) if vv > max { max = vv } } } return max } func IsTwin(cards []int32) bool { //对子 if len(cards) == 2 { if Value(cards[0]) == Value(cards[1]) { return true } } return false } func IsValueStraight(tmpCards []int32) bool { //顺子 if IsContainPOKER2(tmpCards) { // 包含2 单连要 for i := range tmpCards { if tmpCards[i] > POKER_K { tmpCards[i] = tmpCards[i] - POKER_2 - 1 } } sort.Sort(SortInt32(tmpCards)) } if len(tmpCards) < 3 || len(tmpCards) > 12 { return false } for i := 0; i < len(tmpCards)-1; i++ { card := tmpCards[i] nextCard := tmpCards[i+1] if nextCard-card != 1 { // 不相邻 return false } } return true } func IsTriple(cards []int32) bool { //三张 if len(cards)%3 != 0 { return false } if Value(cards[0]) != Value(cards[1]) { return false } if Value(cards[1]) != Value(cards[2]) { return false } return true } func IsFour(cards []int32) bool { //四张 if len(cards) != 4 { return false } if Value(cards[0]) != Value(cards[1]) { return false } if Value(cards[1]) != Value(cards[2]) { return false } if Value(cards[2]) != Value(cards[3]) { return false } return true } func IsDouFour(cards []int32) bool { //两 四张 if len(cards) != 8 { return false } tmpCards := []int32{} for _, card := range cards { tmpCards = append(tmpCards, int32(Value(card))) } sort.Sort(SortInt32(tmpCards)) // fmt.Println(tmpCards[:4], tmpCards[4:], IsFour(tmpCards[:4]), IsFour(tmpCards[4:])) if IsFour(tmpCards[:4]) && IsFour(tmpCards[4:]) { return true } return false } func IsColorSame(cards []int32) bool { // 同色 c := RedColor(cards[0]) for _, card := range cards { if c != RedColor(card) { return false } } return true } func pt32m(cards []int32) map[int32]int32 { m := make(map[int32]int32) for _, v := range cards { m[Value32(v)]++ } return m } func ptstr32m(cards []int32) map[int32]int32 { m := make(map[int32]int32) for _, v := range cards { vl := Value32(v) m[vl]++ } if m[POKER_2] != 0 { m[POKER_2-POKER_2-1] = m[POKER_2] m[POKER_A-POKER_2-1] = m[POKER_A] } return m } /*func findcardCommon(m map[int]int32, n int32) (res [][]int32) { max := int(POKER_2) for i := 0; i <= max; i++ { if m[i] >= n { res = append(res, []int32{}...) } } return }*/ // 通杀 func CardLore(cards []int32) (int, int32) { if int32(len(cards)) != HandCardNum { return Pass, -3 } for _, v := range cards { if v == -1 { return Pass, -3 } } max := POKER_2 smap := pt32m(cards) tmpCards := []int32{} for _, card := range cards { tmpCards = append(tmpCards, int32(Value(card))) } sort.Sort(SortInt32(tmpCards)) // 一条龙>四张2>10张颜色相同>三个三张>五连对 if IsValueStraight(tmpCards) { // 一条龙 return TenStraight, tmpCards[HandCardNum-1] } if smap[POKER_2] == 4 { // 四张 return Four2, tmpCards[HandCardNum-1] } if IsColorSame(cards) { // 同色 return ColorSame, tmpCards[HandCardNum-1] } threenum := 0 for i := int32(0); i <= max; i++ { v, _ := smap[i] if v > 2 { threenum++ } if threenum == 3 { return ThreeTriple, int32(i) } } freenum := 0 for i := int32(0); i <= max; i++ { v, _ := smap[i] if v == 0 && freenum == 0 { continue } if v != 2 { return Pass, -3 } if i == POKER_2 { return Pass, -3 } freenum += 1 if freenum == 5 { return StraightFiveTriple, int32(i) } } return Pass, -3 } func GetCardKind(cards []int32) *KindOfCard { // cardType 类型 // 最小 count := int32(len(cards)) ret := &KindOfCard{ num: count, kind: Pass, //cards: append([]int32{}, cards...), } if count <= 0 { return ret } tmpCards := []int32{} for _, card := range cards { tmpCards = append(tmpCards, int32(Value(card))) } sort.Sort(SortInt32(tmpCards)) // fmt.Printf("GetCardKind %x %x\n", cards, tmpCards) switch count { case 1: //单牌 ret.min = tmpCards[0] ret.max = tmpCards[0] ret.len = 1 ret.same = 1 ret.kind = Single ret.ktype = GetCardType(ret) return ret case 2: //对牌 if IsTwin(cards) { ret.min = tmpCards[0] ret.max = tmpCards[0] ret.kind = Twin ret.len = 1 ret.same = 2 ret.ktype = GetCardType(ret) } return ret } return analysCardKind(cards, tmpCards, ret, count) } func analysCardKind(cards []int32, tmpCards []int32, ret *KindOfCard, count int32) *KindOfCard { // cardType 类型 // 最小 switch count { case 3: if (tmpCards[0] == tmpCards[1]) && IsTriple(tmpCards) { ret.min = tmpCards[0] ret.max = tmpCards[0] ret.kind = Triple ret.len = 1 ret.same = 3 ret.ktype = GetCardType(ret) return ret // 三张 } case 4: if (tmpCards[0] == tmpCards[1]) && IsFour(tmpCards) { ret.min = tmpCards[0] ret.max = tmpCards[0] ret.kind = Four ret.len = 1 ret.same = 4 ret.ktype = GetCardType(ret) return ret // 四张 } case 8: if (tmpCards[0] == tmpCards[1]) && IsDouFour(tmpCards) { ret.min = tmpCards[0] ret.max = tmpCards[7] ret.kind = TwinFour ret.len = 2 ret.same = 4 ret.ktype = GetCardType(ret) return ret //6 两组四张 } } if IsValueStraight(tmpCards) { ret.min = tmpCards[0] ret.max = tmpCards[len(tmpCards)-1] ret.kind = Straight ret.len = int32(len(tmpCards)) ret.same = 1 ret.ktype = GetCardType(ret) return ret // 顺子 } return ret } // 首出提示 func HeadHintOut(card []int32) [][]int32 { // 按照单 双 三张 四张 顺子 双四出~ return nil } // 压牌 func PressOut(beforeKind *KindOfCard, cards []int32, f bool) (retkind *KindOfCard) { p := pt32m(cards) var kds []*KindOfCard switch beforeKind.kind { case Single: //1 单张 retkind = GetSingle(cards, beforeKind, f) if beforeKind.min == POKER_2 { kds = findKindCommon(p, 4) for _, kd := range kds { if CompareCardKind(beforeKind, kd) { retkind = kd break } } } case Twin: //2 对子 kds = findKindCommon(p, 2) if beforeKind.min == POKER_2 { kds = findKindTwinFour(p, 4) } for _, kd := range kds { if CompareCardKind(beforeKind, kd) { retkind = kd break } } case Straight: //4 顺子 kds := findStraight(p, 1, beforeKind.num) for _, kd := range kds { if CompareCardKind(beforeKind, kd) { retkind = kd break } } case Triple: //3 三张 kds := findKindCommon(p, 3) for _, kd := range kds { if CompareCardKind(beforeKind, kd) { retkind = kd break } } case Four: //5 四张 kds := findKindCommon(p, 4) for _, kd := range kds { if CompareCardKind(beforeKind, kd) { retkind = kd break } } case TwinFour: //6 两组四张 } return } // CompareCardKind 对比 func CompareCardKind(beforeKind *KindOfCard, kind *KindOfCard) bool { if beforeKind.kind == kind.kind && beforeKind.num == kind.num && beforeKind.kind != TwinFour { return beforeKind.min < kind.min } if beforeKind.min == POKER_2 { if beforeKind.kind == Single && kind.kind == Four { return true } else if beforeKind.kind == Twin && kind.kind == TwinFour { return true } } return false } // CompareCard 对比 func CompareCard(beforeKind *KindOfCard, cards []int32) bool { // cards 大 返回true cnum := int32(len(cards)) tmpCards := []int32{} for _, card := range cards { tmpCards = append(tmpCards, int32(Value(card))) } sort.Sort(SortInt32(tmpCards)) switch beforeKind.kind { case Single: //1 单张 if cnum == 1 { if beforeKind.min < tmpCards[0] { return true } } else if beforeKind.min == POKER_2 && IsFour(tmpCards) { // 能压一个2 return true } case Twin: //2 对子 if cnum == 2 { if IsTwin(tmpCards) && beforeKind.min < tmpCards[0] { return true } } else if beforeKind.min == POKER_2 && IsDouFour(tmpCards) { // 能压一对2 return true } case Straight: //4 顺子 //fmt.Println("IsValueStraight(tmpCards)", IsValueStraight(tmpCards), beforeKind.len, cnum, beforeKind.min, tmpCards[0]) if beforeKind.len == cnum && IsValueStraight(tmpCards) && (beforeKind.min < tmpCards[0]) { return true } case Triple: //3 三张 if IsTriple(tmpCards) && (beforeKind.min < tmpCards[0]) { return true } case Four: //5 四张 if IsFour(tmpCards) && (beforeKind.min < tmpCards[0]) { return true } case TwinFour: //6 两组四张 } return false } // RemoveCard 删除扑克 func RemoveCard(removePoker []int32, cardData *[]int32) bool { deleteCount := 0 removeCount := len(removePoker) pokerCount := len(*cardData) tempPokerData := make([]int32, pokerCount) if pokerCount > len(tempPokerData) { return false } copy(tempPokerData[0:], (*cardData)[0:pokerCount]) for i := 0; i < removeCount; i++ { for j := 0; j < pokerCount; j++ { if removePoker[i] == tempPokerData[j] { deleteCount++ // fmt.Printf("找到待删除扑克: %x\n", removePoker[i]) tempPokerData[j] = -1 break } } } if deleteCount != removeCount { return false } //清理扑克 pos := 0 for i := 0; i < pokerCount; i++ { if tempPokerData[i] != -1 { (*cardData)[pos] = tempPokerData[i] pos++ } } (*cardData) = (*cardData)[:pos] // 删除扑克 1244 delete 2 --> 144 return true } func GetCardType(kind *KindOfCard) int { switch kind.same { case 4: // 四张 if kind.num != 8 { // 双四张 return -1 // 不能首出 } if kind.min > POKER_10 { return 1 } return 6 case 3: // 三牌 if kind.min > POKER_10 { return 1 } return 4 case 2: // 对牌 return 3 case 1: if kind.num >= 3 { // 单连 if kind.num > 5 { return 8 } if kind.min < POKER_7 && kind.min >= POKER_3 { return 7 } if kind.num == 3 && kind.min > POKER_10 { // 不先出 return 1 } return 5 } } // 单牌 return 2 } func MaxSingle(cpCards []int32, delCards []int32, f bool) (ret bool, retCards []int32) { if DelOtherPOKER2(cpCards, delCards) || (f && len(delCards) == 1) { for i := len(cpCards) - 1; i >= 0; i-- { card := cpCards[i] if card != InvalideCard { retCards = append(retCards, card) ret = true break } } } return } func GetSingle(cpCards []int32, kind *KindOfCard, f bool) (retkind *KindOfCard) { var retCards []int32 if kind == nil || kind.num == 0 { for _, card := range cpCards { if card != InvalideCard { retCards = append(retCards, card) break } } if ret, del := MaxSingle(cpCards, retCards, f); ret { retCards = del } } else { for _, card := range cpCards { if card != InvalideCard && Value32(card) > kind.min { retCards = append(retCards, card) break } } if ret, del := MaxSingle(cpCards, retCards, f); ret { retCards = del if Value32(retCards[0]) <= kind.min { retCards = []int32{} } } } retkind = GetCardKind(retCards) return } func findKindCommon(m map[int32]int32, n int32) (res []*KindOfCard) { for i := int32(0); i <= POKER_2; i++ { if m[i] >= n { card := []int32{} for num := int32(0); num < n; num++ { card = append(card, i) } res = append(res, GetCardKind(card)) } } return } // 双四 func findKindTwinFour(m map[int32]int32, n int32) (res []*KindOfCard) { card := []int32{} k := 0 for i := int32(0); i <= POKER_2; i++ { if m[i] >= n { for num := int32(0); num < n; num++ { card = append(card, i) } k++ } if k == 2 { res = append(res, GetCardKind(card)) break } } return } func haveStraightLine(m map[int32]int32, num int32, len int32, min int32) bool { if min+len > POKER_2 { // 2不能带 return false } for i := min; i < min+len; i++ { if m[i] < num { return false } } return true } // 连牌 func findStraight(m map[int32]int32, num int32, len int32) (res []*KindOfCard) { max := 11 - len min := int32(0) if m[-2] > 0 { min = -2 } else if m[-1] > 0 { // -1 ->2 min = -1 } for ; min <= max; min++ { if haveStraightLine(m, num, len, min) { if min == -2 && len < 6 { // 没必要做连牌 continue } if min == -1 && len < 5 { continue } card := []int32{} for num := int32(0); num < len; num++ { card = append(card, min+num) } res = append(res, GetCardKind(card)) } } return } func allfindStraight(m map[int32]int32, num int32, len int32) (res []*KindOfCard) { for ilen := len; ; ilen++ { var flag bool // 默认false 单联判断成功就继续 max := 11 - ilen min := int32(0) if m[-2] > 0 { min = -2 } else if m[-1] > 0 { // -1 ->2 min = -1 } for ; min <= max; min++ { if haveStraightLine(m, num, ilen, min) { if min == -2 && len < 6 { // 没必要做连牌 continue } if min == -1 && len < 5 { continue } card := []int32{} for num := int32(0); num < ilen; num++ { card = append(card, min+num) } res = append(res, GetCardKind(card)) flag = true } } if !flag { break } } return } // 超时出牌 TODO func TickOut(cards []int32, kind *KindOfCard, f bool) (delCards []int32) { cpCards := append([]int32{}, cards...) sort.Slice(cpCards, func(i, j int) bool { v_i := Value(cpCards[i]) v_j := Value(cpCards[j]) c_i := Color(cpCards[i]) c_j := Color(cpCards[j]) if v_i > v_j { return false } else if v_i == v_j { return c_i < c_j } return true }) var retkind *KindOfCard if kind == nil || kind.num == 0 { retkind = GetSingle(cpCards, kind, f) } else { retkind = PressOut(kind, cpCards, f) } delCards = retkind.OutPokers(cpCards) return } // 根据上家牌型是否需要额外延迟出牌时间(s) func NeedExDelay(lastCards []int32) bool { return false } // 计算输家输分数 func GetLoseScore(cards [HandCardNum]int32, baopei bool) (loseScore int32) { //cpCards := []int32{} num := int32(0) flag := false for _, card := range cards { if card != InvalideCard { if !flag && Value32(card) == POKER_2 { flag = true loseScore += Baopei2 } //cpCards = append(cpCards, card) num++ } } if num == HandCardNum { loseScore += Treo } else { loseScore += num } if baopei { // 庄家赔付 loseScore -= Baopei2 } return }