日暮苍山远,天寒白屋贫。|

janbar

园龄:4年5个月 粉丝:29 关注:10

2023-03-04 21:01 阅读 337 评论 2 推荐

四川麻将判断胡牌(非递归),找到要听的牌

四川麻将胡牌规则,参考腾讯麻将“血流成河”规则

image

详细代码如下:

copy
package main import ( "bytes" "fmt" "strings" ) func main() { var ( tile = []string{ "56756744422222m", // 超过4张牌,记为4张 "675456234m32155p4s", // 没有缺一门,可以打一张后听牌 "112233m11224455p", // 七对 "11223355667799s", // 清七对 "1122335566s3333m", // 龙七对 "11m111222555666p", // 碰碰胡 "11122255566677p", // 清碰 "567567444222m3m3m", // 清一色 "1111333345667899m", // 两个杠的牌 "111133335555777799m", // 清十八罗汉 "22244455667m3p3p", // 计算听牌 "22244455667m43p3p", // 打一张,计算听哪些牌 "2224445666789m", // 计算听牌 "12224445666789m", // 打一张,计算听哪些牌 } ) for _, t := range tile { tt := StrToTile(&t) // 字符串转为tile34,更新字符串 fmt.Printf("当前牌: [%s]\n", t) fmt.Println(MahjongSolution(tt)) fmt.Println("-------------------------------") } } const TileMax = 34 func StrToTile(s *string) []int { tile := make([]int, TileMax) if s == nil || len(*s) < 2 { *s = "" // 至少2个字符1张牌,不满足则置为空 return tile } var ( ok = false i = len(*s) - 1 si = -1 ni int ) for ; i >= 0; i-- { switch c := (*s)[i]; c { case 'm': si = 0 // [0,8]m = [1,9]万 case 'p': si = 9 // [9,18]p = [1,9]筒 case 's': si = 18 // [18,26]s = [1,9]条 case 'z': si = 27 // [27,33]z = [1,7] = 东,南,西,北,白,发,中 case '1', '2', '3', '4', '5', '6', '7', '8', '9': if si >= 0 { if ni = int(c-'1') + si; ni < TileMax && tile[ni] < 4 { tile[ni]++ ok = true } } } } if ok { *s = TileToStr(tile) // 有牌时序列化并排序 } else { *s = "" // 无牌时置为空 } return tile } func TileToStr(tile []int) string { var ( i, j int lt = len(tile) // 支持lt<34的不完全入参 tmp strings.Builder ) ok := false // 拼接万牌 for i = 0; i < 9 && i < lt; i++ { for j = tile[i]; j > 0; j-- { tmp.WriteByte(byte(i + '1')) ok = true } } if ok { tmp.WriteByte('m') } ok = false // 拼接筒牌 for i = 9; i < 18 && i < lt; i++ { for j = tile[i]; j > 0; j-- { tmp.WriteByte(byte(i - 9 + '1')) ok = true } } if ok { tmp.WriteByte('p') } ok = false // 拼接条牌 for i = 18; i < 27 && i < lt; i++ { for j = tile[i]; j > 0; j-- { tmp.WriteByte(byte(i - 18 + '1')) ok = true } } if ok { tmp.WriteByte('s') } ok = false // 拼接字牌 for i = 27; i < TileMax && i < lt; i++ { for j = tile[i]; j > 0; j-- { tmp.WriteByte(byte(i - 27 + '1')) ok = true } } if ok { tmp.WriteByte('z') } return tmp.String() } func NumToTile(v int) []byte { if v < 0 || v >= TileMax { return []byte{'0', '-'} // 不合法数据 } if v >= 27 { return []byte{byte(v - 27 + '1'), 'z'} } if v >= 18 { return []byte{byte(v - 18 + '1'), 's'} } if v >= 9 { return []byte{byte(v - 9 + '1'), 'p'} } return []byte{byte(v + '1'), 'm'} } type MahjongResult struct { IsSame bool // 是否清一色 Type int // 牌类型 Jiang int // 将牌 NumKe int // 刻子数量 NumShun int // 顺子数量 NumGang int // 杠数量 ArrayKe []int // 刻子数组 ArrayShun []int // 顺子数组 ArrayGang []int // 杠数组 } func (mr *MahjongResult) String() string { b := bytes.NewBufferString("{") nv := NumToTile(mr.Jiang) if nv[1] == '-' { return "" // 将不合法 } if mr.IsSame { b.WriteString("清一色,") } switch mr.Type { case 1: b.WriteString("七对}") return b.String() case 2: b.WriteString("龙七对}") return b.String() } b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[1]) b.WriteByte(',') for _, v := range mr.ArrayKe { nv = NumToTile(v) b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[1]) b.WriteByte(',') } for _, v := range mr.ArrayShun { nv = NumToTile(v) b.WriteByte(nv[0]) b.WriteByte(nv[0] + 1) b.WriteByte(nv[0] + 2) b.WriteByte(nv[1]) b.WriteByte(',') } for _, v := range mr.ArrayGang { nv = NumToTile(v) b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[0]) b.WriteByte(nv[1]) b.WriteByte(',') } // 移除最后1个','号,并将结果括起来 b.Truncate(b.Len() - 1) b.WriteByte('}') return b.String() } func MahjongWin(tile []int) (res []*MahjongResult) { color, cnt := 0, [5]int{} for i, v := range tile { if v <= 0 || v > 4 { tile[i] = 0 // 纠正数量错误的牌 continue } nv := NumToTile(i) cnt[v]++ // 记录对应数量牌的个数 cnt[0] += v // 记录牌总数 switch nv[1] { case 's': color |= 4 // 存在条 case 'p': color |= 2 // 存在筒 case 'm': color |= 1 // 存在万 case 'z', '-': return nil // 四川麻将没有字牌 } } isSame := color == 1 || color == 2 || color == 4 // 清一色 if cnt[0] == 14 { if cnt[2] == 7 { return []*MahjongResult{{ IsSame: isSame, Type: 1, // 七对 }} } if cnt[2] == 5 && cnt[4] == 1 { // 注意,4张的牌不能杠出和碰出 return []*MahjongResult{{ IsSame: isSame, Type: 2, // 龙七对 }} } } var ( appNum = []func(tp []int, k, s, g *[]int){ func(tp []int, k, s, g *[]int) { for j := 0; j < TileMax; j++ { if tp[j] >= 3 { tp[j] -= 3 // 取刻子 *k = append(*k, j) } } }, func(tp []int, k, s, g *[]int) { var a, b, c int for a = 0; a < 3; a++ { for b = 0; b < 7; { c = 9*a + b if tp[c] >= 1 && tp[c+1] >= 1 && tp[c+2] >= 1 { tp[c]-- tp[c+1]-- tp[c+2]-- // 取顺子 *s = append(*s, c) } else { b++ } } } }, func(tp []int, k, s, g *[]int) { for j := 0; j < TileMax; j++ { if tp[j] >= 4 { tp[j] = 0 // 取杠牌 *g = append(*g, j) } } }, } tp = make([]int, len(tile)) mp = make(map[string]struct{}) ) for i := 0; i < TileMax; i++ { if tile[i] < 2 { continue // 跳过不能做雀头的牌 } for _, an := range [][]int{ {0, 1}, // 刻子,顺子 {1, 0}, // 顺子,刻子 {2, 0, 1}, // 杠,刻子,顺子 {2, 1, 0}, // 杠,顺子,刻子 } { copy(tp, tile) tp[i] -= 2 // 取雀头 var keNum, shunNum, gangNum []int for _, anv := range an { appNum[anv](tp, &keNum, &shunNum, &gangNum) } ok := true for _, vt := range tp { if vt != 0 { ok = false break } } if ok { // 胡牌,记录牌型,结果去重 key := fmt.Sprintf("%d%v%v%v", i, keNum, shunNum, gangNum) if _, ok = mp[key]; !ok { res = append(res, &MahjongResult{ IsSame: isSame, Type: 3, NumKe: len(keNum), NumShun: len(shunNum), NumGang: len(gangNum), Jiang: i, ArrayKe: keNum, ArrayShun: shunNum, ArrayGang: gangNum, }) mp[key] = struct{}{} } } } } return } func MahjongSolution(tile []int) string { status := MahjongWin(tile) if len(status) > 0 { return fmt.Sprint(status) } ting := func() (res []string) { for i, v := range tile { if v < 4 { tile[i]++ status = MahjongWin(tile) tile[i]-- if len(status) > 0 { nv := NumToTile(i) // 假设得到这张牌可以胡牌则听这张牌 res = append(res, fmt.Sprintf("%v听%c%c", status, nv[0], nv[1])) } } } return } resp := ting() // 当前听哪些牌 for i, v := range tile { if v > 0 { nv := NumToTile(i) tile[i]-- status = MahjongWin(tile) if len(status) > 0 { // 假设打出这张牌,直接胡牌(正常打牌不会有这种情况) resp = append(resp, fmt.Sprintf("打%c%c, %v", nv[0], nv[1], status)) } res := ting() tile[i]++ for _, rv := range res { // 假设打出这张牌,能听哪些牌 resp = append(resp, fmt.Sprintf("打%c%c, %s", nv[0], nv[1], rv)) } } } return strings.Join(resp, "\n") }

结果如下:

copy
当前牌: [2222444556677m] [{清一色,44m,222m,234m,567m,567m} {清一色,77m,222m,234m,456m,456m}]听3m 打4m, [{清一色,44m,567m,567m,2222m} {清一色,77m,456m,456m,2222m}] 打7m, [{清一色,44m,456m,567m,2222m}] ------------------------------- 当前牌: [234455667m12355p4s] 打4s, [{55p,234m,456m,567m,123p}] ------------------------------- 当前牌: [112233m11224455p] [{七对}] ------------------------------- 当前牌: [11223355667799s] [{清一色,七对}] ------------------------------- 当前牌: [3333m1122335566s] [{龙七对}] ------------------------------- 当前牌: [11m111222555666p] [{11m,111p,222p,555p,666p}] ------------------------------- 当前牌: [11122255566677p] [{清一色,77p,111p,222p,555p,666p}] ------------------------------- 当前牌: [22233444556677m] [{清一色,33m,222m,444m,567m,567m}] ------------------------------- 当前牌: [1111333345667899m] [{清一色,99m,456m,678m,1111m,3333m}] ------------------------------- 当前牌: [111133335555777799m] [{清一色,99m,1111m,3333m,5555m,7777m}] ------------------------------- 当前牌: [22244455667m33p] [{33p,222m,444m,456m,567m}]听4m [{33p,222m,444m,567m,567m}]听7m [{44m,222m,333p,456m,567m}]听3p ------------------------------- 当前牌: [22244455667m334p] 打3p, [{44m,222m,456m,567m,234p}]听2p 打3p, [{44m,222m,456m,567m,345p}]听5p 打4p, [{33p,222m,444m,456m,567m}]听4m 打4p, [{33p,222m,444m,567m,567m}]听7m 打4p, [{44m,222m,333p,456m,567m}]听3p ------------------------------- 当前牌: [2224445666789m] [{清一色,44m,222m,666m,345m,789m}]听3m [{清一色,66m,222m,444m,456m,789m}]听4m [{清一色,55m,222m,444m,666m,789m}]听5m [{清一色,44m,222m,666m,456m,789m}]听6m [{清一色,66m,222m,444m,567m,789m}]听7m ------------------------------- 当前牌: [12224445666789m] 打1m, [{清一色,44m,222m,666m,345m,789m}]听3m 打1m, [{清一色,66m,222m,444m,456m,789m}]听4m 打1m, [{清一色,55m,222m,444m,666m,789m}]听5m 打1m, [{清一色,44m,222m,666m,456m,789m}]听6m 打1m, [{清一色,66m,222m,444m,567m,789m}]听7m 打5m, [{清一色,11m,222m,444m,666m,789m}]听1m 打5m, [{清一色,22m,444m,666m,123m,789m}]听3m -------------------------------
posted @   janbar  阅读(337)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 10亿数据,如何做迁移?
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 易语言 —— 开山篇
· Trae初体验

FAVOURITE

点击右上角即可分享
微信分享提示
*✧⁺˚⁺ପ(๑・ω・)੭ु⁾⁾ 好好学习天天向上
进入亮色模式
进入亮色模式

FAVOURITE