game_sync/gamerule/samloc/card.go

946 lines
19 KiB
Go

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
}