话不多说,代码先给出来 文件名 mahjong.go
很多的实现方法,写的注释我觉得已经很详细了,多看下注释。
package main
import (
"sort"
"fmt"
)
//牌类型
type CardType int
const (
CardType_Unknown CardType = iota
CardType_W
CardType_T
CardType_S
)
//实现string
func (st CardType) String() string {
str := ""
switch st {
case CardType_W:
str += "W"
case CardType_T:
str += "T"
case CardType_S:
str += "S"
}
return str
}
//牌定义
type Card struct {
Type CardType
Value int
}
//实现string
func (c *Card) String() string {
return fmt.Sprint("Card: ", c.Value, " ", c.Type)
}
//自定义排序
type SortCards []*Card
func (sc SortCards) Len() int {
return len(sc)
}
func (sc SortCards) Less(i, j int) bool {
if sc[i].Type != sc[j].Type {
return sc[i].Type < sc[j].Type
} else {
return sc[i].Value < sc[j].Value
}
panic("unknown...")
}
func (sc SortCards) Swap(i, j int) {
sc[i], sc[j] = sc[j], sc[i]
}
//实现
func (sc SortCards) Sort() {
sort.Sort(sc)
}
//最简单的胡牌算法
/*
1.首先我们要明白,什么样的牌可以胡牌?
2. 4*3+2,7*2 可以胡牌;当然,这是手上有14张牌的时候,所以用公式来说就是 N*3 + 1*2 (0<=n<=4)
3. 再者,麻将有不同的花色,而且每一个花色是没有关联的,所以可以分开单独计算,随便还可以加个携程,还能提高效率(单核机当我没说),多好啊。
总结:说简单点就是 先分开花色,在每一个花色中计算能否符合条件,只要一个不符合,直接false。
*/
func AnalyzeCardsSimple(cards []*Card) bool {
//有个七对,特殊判断一下就可以了
if len(cards) ==14 {
// todo 计算是否有七个对子
}
//用一个slice来装不同花色的牌
diffColorCards := GetDiffColorCards(cards)
fmt.Println(diffColorCards)
for _,tempCards := range diffColorCards {
//1-9 每张牌的数量
cardsNum := make([]int,10)
for _, card := range tempCards {
cardsNum[card]++
}
isHu := SplitCards(cardsNum,false)
fmt.Println(isHu)
if !isHu {
return false
}
}
return true
}
/**
这是目前最简单的单机拆牌,只能判断是否能胡,不能用于计算牌型方面的东西。
原理:
从第一张牌开始计算,
假如一个牌有4张,在整个牌里面他只能做刻字和一个顺子;除开 333344445555 这种特殊情况,但是拆分出来也是判断可以胡的。
所以减去三张牌,在调用SplitCards,这个时候它的第一张牌就只有一张,自然而然的就走找顺子的道路上了。
但是减去三张发现后面也没有办法胡,看代码继续走下面,再减去2张试试呢。比如 22223344 这种牌
一张牌它就只能去找后面的顺子,没有就不能胡。
这里还有一个问题,就是有重复计算的部分
比如 33334567 的牌,减去三个 3 剩下 34567,减去345剩67 不能胡;
在回来减去两个 3 剩下 334567 ,在减去345剩下367不能胡;
在回来到下面减一个345 剩33367,减去333 剩下67 ,这里和第一次其实是一样的算法,只是顺序不同。
*/
//对子只能存在一对。
func SplitCards(cardsNum []int,hasPair bool) bool {
cnt := 0
for _, num := range cardsNum {
if num > 0 {
break
}
cnt++
}
//判断没有牌为可以胡牌
if len(cardsNum) == cnt {
return true
}
for i := 0; i < len(cardsNum); i++ {
switch cardsNum[i] {
case 4:
fallthrough
case 3:
//这种存在这几种情况,可以加后面成顺子,取两张为对子,或取一个刻字
//减掉后再传入SplitCards
cardsNum[i]-=3
if SplitCards(cardsNum,hasPair) {
return true
}
cardsNum[i]+=3
//这种不行就向下传递。。。
fallthrough
case 2:
if !hasPair {
hasPair = true
cardsNum[i]-=2
if SplitCards(cardsNum,hasPair) {
return true
}
cardsNum[i]+=2
}
fallthrough
case 1:
if i+2 < len(cardsNum) && cardsNum[i+1] > 0 && cardsNum[i+2] >0 {
cardsNum[i]--
cardsNum[i+1]--
cardsNum[i+2]--
if SplitCards(cardsNum,hasPair) {
return true
}
cardsNum[i]++
cardsNum[i+1]++
cardsNum[i+2]++
}
}
}
return false
}
//获取不同颜色的牌
func GetDiffColorCards(cards []*Card) map[CardType][]int {
colorCards := make(map[CardType][]int)
for _, card := range cards {
if _,ok := colorCards[card.Type]; !ok {
colorCards[card.Type] = append([]int{},card.Value)
}else {
colorCards[card.Type] = append(colorCards[card.Type],card.Value)
}
}
return colorCards
}
测试代码:mahjong_test.go
package main
import (
"testing"
"fmt"
)
func TestSortCards(t *testing.T) {
cards := []*Card{
&Card{CardType_W,1},
&Card{CardType_W,1},
&Card{CardType_W,1},
&Card{CardType_W,2},
&Card{CardType_W,2},
&Card{CardType_W,2},
&Card{CardType_T,3},
&Card{CardType_T,3},
&Card{CardType_T,4},
&Card{CardType_T,4},
&Card{CardType_S,3},
&Card{CardType_S,3},
&Card{CardType_S,5},
&Card{CardType_S,5},
}
SortCards(cards).Sort()
fmt.Println(cards)
//tempCards := make([]*Card, len(cards))
//copy(tempCards,cards)
//fmt.Println(tempCards)
//temp := append([]*Card{}, &Card{CardType_S, 7})
//fmt.Println(temp)
//diffColorCards := GetDiffColorCards(cards)
//fmt.Println(diffColorCards)
//for _,tempCards := range diffColorCards {
// fmt.Println(tempCards)
//}
simple := AnalyzeCardsSimple(cards)
fmt.Println(simple)
}
当然,这代码是第一个版本,其中还有更多可以优化。
那得看有需要优化需求的朋友是不是多了。
请留言我会实时收到消息。