478 lines
9.9 KiB
Go
478 lines
9.9 KiB
Go
package tala
|
|
|
|
import (
|
|
"sort"
|
|
"strconv"
|
|
)
|
|
|
|
//牌序- K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3, 2, A
|
|
//方片- 51,50,49,48,47,46,45,44,43,42,41,40,39
|
|
//红桃- 38,37,36,35,34,33,32,31,30,29,28,27,26
|
|
//梅花- 25,24,23,22,21,20,19,18,17,16,15,14,13
|
|
//黑桃- 12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
|
|
|
const (
|
|
TaLaNil int = iota //nil
|
|
ColorStraight //1 同花顺
|
|
Triple //2 三张
|
|
)
|
|
|
|
// Color 黑桃0 梅花1 紅桃2 方片3
|
|
func Color(c int32) int {
|
|
return int(c) / PER_CARD_COLOR_MAX
|
|
}
|
|
|
|
func Value(c int32) int {
|
|
value := int(c+1) % PER_CARD_COLOR_MAX
|
|
if value == 0 {
|
|
value = PER_CARD_COLOR_MAX
|
|
}
|
|
return value
|
|
}
|
|
|
|
func ValueStr(c int32) string {
|
|
if c == InvalideCard {
|
|
return ""
|
|
}
|
|
str := ""
|
|
value := strconv.Itoa(Value(c))
|
|
switch Color(c) {
|
|
case 0:
|
|
str = "黑桃"
|
|
case 1:
|
|
str = "梅花"
|
|
case 2:
|
|
str = "紅桃"
|
|
case 3:
|
|
str = "方片"
|
|
}
|
|
return str + value
|
|
}
|
|
|
|
func IsStraight(cards []int32) bool { //顺子
|
|
if len(cards) < 3 || len(cards) > HandCardNum {
|
|
return false
|
|
}
|
|
tmpCards := []int{}
|
|
for _, card := range cards {
|
|
tmpCards = append(tmpCards, Value(card))
|
|
}
|
|
sort.Ints(tmpCards)
|
|
for i := 0; i < len(tmpCards)-1; i++ {
|
|
card := tmpCards[i]
|
|
nextCard := tmpCards[i+1]
|
|
if nextCard-card != 1 { //不相邻
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func IsColorStraight(cards []int32) bool { //同花顺子
|
|
// 先是顺子
|
|
if !IsStraight(cards) {
|
|
return false
|
|
}
|
|
c := Color(cards[0])
|
|
for _, card := range cards {
|
|
if c != Color(card) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func IsTriple(cards []int32) bool { //三张
|
|
if len(cards) < 3 || len(cards) > 4 { // 3张或者4张
|
|
return false
|
|
}
|
|
switch len(cards) {
|
|
case 3:
|
|
if Value(cards[0]) != Value(cards[1]) {
|
|
return false
|
|
}
|
|
if Value(cards[1]) != Value(cards[2]) {
|
|
return false
|
|
}
|
|
return true
|
|
case 4:
|
|
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
|
|
}
|
|
return false
|
|
}
|
|
|
|
func CanChi(cards []int32, chiCard int32, excludeCards []int32) (bool, []int32) { //可吃
|
|
chi2pPhom := []int32{chiCard}
|
|
if chiCard == InvalideCard {
|
|
return false, chi2pPhom
|
|
}
|
|
cpCards := []int32{}
|
|
for _, card := range cards {
|
|
if card != InvalideCard {
|
|
cpCards = append(cpCards, card)
|
|
}
|
|
}
|
|
if len(cpCards) == 0 {
|
|
return false, chi2pPhom
|
|
}
|
|
n := 0
|
|
tmp := []int32{}
|
|
for _, card := range cpCards {
|
|
if Value(chiCard) == Value(card) && !InSliceInt32(excludeCards, card) {
|
|
n++
|
|
tmp = append(tmp, card)
|
|
}
|
|
}
|
|
if n >= 2 { //找到两张以上牌值相同的,可以吃
|
|
for _, card := range tmp {
|
|
chi2pPhom = append(chi2pPhom, card)
|
|
}
|
|
return true, chi2pPhom
|
|
}
|
|
chi2pPhom = []int32{chiCard}
|
|
min1 := false
|
|
min2 := false
|
|
minPhom := []int32{}
|
|
mid1 := false
|
|
mid2 := false
|
|
midPhom := []int32{}
|
|
max1 := false
|
|
max2 := false
|
|
maxPhom := []int32{}
|
|
|
|
for _, card := range cpCards {
|
|
if Color(chiCard) == Color(card) && !InSliceInt32(excludeCards, card) {
|
|
//最小
|
|
if chiCard+1 == card {
|
|
minPhom = append(minPhom, card)
|
|
min1 = true
|
|
}
|
|
if chiCard+2 == card {
|
|
minPhom = append(minPhom, card)
|
|
min2 = true
|
|
}
|
|
if min1 && min2 {
|
|
for _, c := range minPhom {
|
|
chi2pPhom = append(chi2pPhom, c)
|
|
}
|
|
return true, chi2pPhom
|
|
}
|
|
//中间
|
|
if chiCard+1 == card {
|
|
midPhom = append(midPhom, card)
|
|
mid1 = true
|
|
}
|
|
if chiCard-1 == card {
|
|
midPhom = append(midPhom, card)
|
|
mid2 = true
|
|
}
|
|
if mid1 && mid2 {
|
|
for _, c := range midPhom {
|
|
chi2pPhom = append(chi2pPhom, c)
|
|
}
|
|
return true, chi2pPhom
|
|
}
|
|
//最大
|
|
if chiCard-1 == card {
|
|
maxPhom = append(maxPhom, card)
|
|
max1 = true
|
|
}
|
|
if chiCard-2 == card {
|
|
maxPhom = append(maxPhom, card)
|
|
max2 = true
|
|
}
|
|
if max1 && max2 {
|
|
for _, c := range maxPhom {
|
|
chi2pPhom = append(chi2pPhom, c)
|
|
}
|
|
return true, chi2pPhom
|
|
}
|
|
}
|
|
}
|
|
return false, chi2pPhom
|
|
}
|
|
|
|
func GetCardsValue(cards []int32) int {
|
|
cardValue := 0
|
|
for _, card := range cards {
|
|
if card != InvalideCard {
|
|
cardValue += Value(card)
|
|
}
|
|
}
|
|
return cardValue
|
|
}
|
|
|
|
// 尝试组合phom
|
|
func TryPhom(cards, chiCards []int32) ([]int32, [][]int32) { //胡
|
|
cpCards := []int32{}
|
|
phomCards := [][]int32{}
|
|
for _, card := range cards {
|
|
if card != InvalideCard {
|
|
cpCards = append(cpCards, card)
|
|
}
|
|
}
|
|
if len(cpCards) == 0 {
|
|
return cpCards, phomCards
|
|
}
|
|
cardValue := GetCardsValue(cards)
|
|
tmpPhoms := [][]int32{}
|
|
var TryOpPhom func([]int32)
|
|
|
|
TryOpPhom = func(cs []int32) {
|
|
if len(cs) == 0 {
|
|
return
|
|
}
|
|
cp := []int32{}
|
|
for _, i2 := range cs {
|
|
if i2 != InvalideCard {
|
|
cp = append(cp, i2)
|
|
}
|
|
}
|
|
//fmt.Println("===2===", cp)
|
|
phoms := needPhom(cp)
|
|
if len(phoms) != 0 {
|
|
//fmt.Println("===4===", phoms)
|
|
for _, phom := range phoms {
|
|
for _, card := range phom {
|
|
for i := 0; i < len(cp); i++ {
|
|
if cp[i] == card {
|
|
cp = append(cp[:i], cp[i+1:]...)
|
|
i--
|
|
}
|
|
}
|
|
}
|
|
tmpCp := []int32{}
|
|
for _, tmp := range cp {
|
|
tmpCp = append(tmpCp, tmp)
|
|
}
|
|
tmpPhoms = append(tmpPhoms, phom)
|
|
|
|
TryOpPhom(tmpCp)
|
|
|
|
//fmt.Println("===3===", tmpCp, tmpPhoms)
|
|
if GetCardsValue(tmpCp) < cardValue && !InSliceASliceB(tmpCp, chiCards) { //是不是最优解 //吃过的牌不能留在手牌里
|
|
cardValue = GetCardsValue(cp)
|
|
phomCards = [][]int32{}
|
|
for _, tmpPhom := range tmpPhoms {
|
|
if len(tmpPhom) > 0 {
|
|
tmp := []int32{}
|
|
for _, c := range tmpPhom {
|
|
tmp = append(tmp, c)
|
|
}
|
|
phomCards = append(phomCards, tmp)
|
|
}
|
|
}
|
|
}
|
|
cp = []int32{} //回退下 next
|
|
for _, card := range cs {
|
|
cp = append(cp, card)
|
|
}
|
|
tmpPhoms = append(tmpPhoms[:len(tmpPhoms)-1])
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
TryOpPhom(cpCards)
|
|
//fmt.Println("===1===", phomCards)
|
|
for _, phom := range phomCards {
|
|
for _, card := range phom {
|
|
for i, cpcard := range cpCards {
|
|
if card == cpcard {
|
|
cpCards = append(cpCards[:i], cpCards[i+1:]...)
|
|
i--
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cpCards, phomCards
|
|
}
|
|
|
|
// b中元素是否在a里面
|
|
func InSliceASliceB(a, b []int32) bool {
|
|
for _, bi := range b {
|
|
if InSliceInt32(a, bi) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 有所有的同花顺组合 或者 有所有的点数相同的组合
|
|
func needPhom(cards []int32) [][]int32 { //胡
|
|
tmps := [][]int32{}
|
|
haveColorStraights, colorStraights := needColorStraight(cards)
|
|
haveTriples, triples := needTriple(cards)
|
|
if haveColorStraights || haveTriples { //有所有的同花顺组合 或者 有所有的点数相同的组合
|
|
if haveColorStraights {
|
|
for _, straight := range colorStraights {
|
|
tmps = append(tmps, straight)
|
|
}
|
|
}
|
|
if haveTriples {
|
|
for _, triple := range triples {
|
|
tmps = append(tmps, triple)
|
|
}
|
|
}
|
|
}
|
|
return tmps
|
|
}
|
|
|
|
// 找所有相同点数的三张
|
|
func needTriple(cards []int32) (bool, [][]int32) {
|
|
haveNeed := false
|
|
needCards := [][]int32{}
|
|
if len(cards) != 0 {
|
|
mapTriple := make(map[int32][]int32)
|
|
for _, card := range cards {
|
|
if card != InvalideCard {
|
|
mapTriple[int32(Value(card))] = append(mapTriple[int32(Value(card))], card)
|
|
}
|
|
}
|
|
if len(mapTriple) > 0 {
|
|
for _, tripleCards := range mapTriple {
|
|
if len(tripleCards) == 3 {
|
|
haveNeed = true
|
|
needCards = append(needCards, tripleCards)
|
|
}
|
|
if len(tripleCards) == 4 {
|
|
haveNeed = true
|
|
needCards = append(needCards, tripleCards)
|
|
for _, card := range tripleCards {
|
|
tmps := []int32{}
|
|
for _, tmp := range tripleCards {
|
|
if card != tmp {
|
|
tmps = append(tmps, tmp)
|
|
}
|
|
}
|
|
if len(tmps) > 0 {
|
|
needCards = append(needCards, tmps)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return haveNeed, needCards
|
|
}
|
|
|
|
// 所有的同花顺
|
|
func needColorStraight(cards []int32) (bool, [][]int32) {
|
|
haveNeed := false
|
|
needCards := [][]int32{}
|
|
if len(cards) != 0 {
|
|
sliceCS := [4][]int32{} //color-card
|
|
for _, card := range cards {
|
|
if card != InvalideCard {
|
|
sliceCS[Color(card)] = append(sliceCS[Color(card)], card)
|
|
}
|
|
}
|
|
for _, colorCards := range sliceCS {
|
|
if len(colorCards) > 0 {
|
|
sort.Slice(colorCards, func(i, j int) bool {
|
|
if Value(colorCards[i]) > Value(colorCards[j]) {
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
for i := len(colorCards); i > 2; i-- {
|
|
tmps := FindStraightWithWidth(i, colorCards)
|
|
if len(tmps) > 0 {
|
|
haveNeed = true
|
|
for _, tmp := range tmps {
|
|
needCards = append(needCards, tmp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return haveNeed, needCards
|
|
}
|
|
|
|
// 找一个固定长度的顺子 (2,3,4,5,6) 3-> [2,3,4]
|
|
func FindOneStraightWithWidth(n int, pairs []int32) []int32 {
|
|
if len(pairs) == 0 {
|
|
return nil
|
|
}
|
|
lastKey := pairs[0]
|
|
tempPair := []int32{lastKey}
|
|
if n == 1 {
|
|
return tempPair
|
|
}
|
|
for i := 1; i < len(pairs); i++ {
|
|
if pairs[i]-lastKey == 1 {
|
|
tempPair = append(tempPair, pairs[i])
|
|
} else {
|
|
tempPair = []int32{pairs[i]}
|
|
}
|
|
if len(tempPair) == n {
|
|
break
|
|
}
|
|
lastKey = pairs[i]
|
|
}
|
|
if len(tempPair) == n {
|
|
return tempPair
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 找多个固定长度的顺子(2,3,4,5,6) 3-> [[2,3,4][3,4,5][4,5,6]]
|
|
func FindStraightWithWidth(n int, pairs []int32) [][]int32 {
|
|
if len(pairs) == 0 || n < 2 {
|
|
return nil
|
|
}
|
|
var tempPairs [][]int32
|
|
lastKey := pairs[0]
|
|
tempPair := []int32{lastKey}
|
|
for i := 1; i < len(pairs); i++ {
|
|
if pairs[i]-lastKey == 1 {
|
|
tempPair = append(tempPair, pairs[i])
|
|
} else {
|
|
tempPair = []int32{pairs[i]}
|
|
}
|
|
if len(tempPair) == n {
|
|
tempPairs = append(tempPairs, tempPair)
|
|
tempPair = []int32{}
|
|
for j := n - 1; j > 0; j-- {
|
|
tempPair = append(tempPair, pairs[i-j+1])
|
|
}
|
|
}
|
|
lastKey = pairs[i]
|
|
}
|
|
return tempPairs
|
|
}
|
|
|
|
func DelSliceInt32(sl []int32, v int32) []int32 {
|
|
index := -1
|
|
for key, value := range sl {
|
|
if value == v {
|
|
index = key
|
|
break
|
|
}
|
|
}
|
|
if index != -1 {
|
|
sl = append(sl[:index], sl[index+1:]...)
|
|
}
|
|
return sl
|
|
}
|
|
|
|
func InSliceInt32(sl []int32, v int32) bool {
|
|
for _, vv := range sl {
|
|
if vv == v {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|