上一篇文章序数了关于使用索引查表法进行麻将胡牌判定,这篇文章,我们将会对胡牌的番型进行计算,这里的番型指的是国标下的麻将番型,文章中的代码,暂时只考虑了二人麻将(只有万牌和字牌),想要通用,可以按着同样的方法进行扩展。
国标二人麻将番型表
88番
番型 | 胡牌方式 | 示例 |
---|---|---|
大四喜 | 胡牌时,牌里有4组风刻子(杠)加一对将牌组成的牌型。(不计门风刻、圈风刻、小四喜、三风刻、碰碰胡、幺九刻) | |
大三元 | 胡牌时,牌里有中、发、白3副刻子。(不计双箭刻、箭刻) | |
九莲宝灯 | 由一种花色序数组成的特定牌型,见同花色任何一张序数牌即成胡牌。不计清一色,门前清,自摸 | |
大七星 | 胡牌为七对子,并且由“东南西北中发白“其中字牌构成,不计七对,三元七对,四喜七对,全带幺,单钓将,门前清,自摸,字一色 | |
四杠 | 4个杠,不计三杠,双明杠,明杠,单钓将 | |
连七对 | 由一种花色序数牌组成序数相连的7个对子的胡牌。不计七对,单钓将,门前清,自摸,清一色 | |
天胡 | 庄家在发完牌就胡牌。如果庄家有补花,在补完花后就胡牌也算。如果庄家在发完牌后有暗杠, 那么不算天和,不计边张,坎张单钓将不求人,和绝张,自摸 | |
地胡 | 闲家摸到第一张牌 就胡牌,称为地和。如果闲家抓的第一张牌是花牌,那么补花之后胡牌也算地和。如果闲家抓牌前有人吃碰杠(包括暗杠),那么不算地和。 |
64番
番型 | 胡牌方式 | 示例 |
---|---|---|
小四喜 | 胡牌时,牌里有风牌的3副刻子及将牌。不记番:三风刻、幺九刻。 | |
小三元 | 胡牌时,牌里有箭牌的两副刻子及将牌。不记番:箭刻、双箭刻。 | |
字一色 | 字一色:胡牌时,牌型由字牌的刻子(杠)、将组成。不记番:碰碰和、混么九、全带幺、么九刻。 | |
四暗刻 | 胡牌时,牌里有4个暗刻(暗杠)。不记番:门前清、碰碰和、三暗刻、双暗刻、不求人。 | |
一色双龙会 | 胡牌时,牌型由一种花色的两个老少副,5为将牌组成。不记番:平和、七对、清色、一般高、老少副。 |
48番
番型 | 胡牌方式 | 示例 |
---|---|---|
一色四同顺 | 胡牌时,牌里有一种花色且序数相同的4副顺子。不记番:一色三节高、一般高、四归一,一色三同顺、七对。 | |
一色四节高 | 胡牌时牌里有一种花色且序数依次递增一位数的4副刻子(或杠子)。不记番:一色三同顺、一色三节高、碰碰和。 |
32番
番型 | 胡牌方式 | 示例 |
---|---|---|
一色四步高 | 胡牌时,牌里有一种花色4副依次递增一位数或依次递增二位数的顺子。不记番:一色三步高。 | |
三杠 | 胡牌时,牌里有3副杠,明杠暗杠均可。 | |
混幺九 | 胡牌时,由字牌和序数牌、九的刻子及将牌组成的牌型。不记番:碰碰和、幺九刻、全带么。 |
24番
番型 | 胡牌方式 | 示例 |
---|---|---|
七对 | 胡牌时,胡牌时,牌型由7个对子组成。(不计门前清、不求人、单钓将) | |
清一色 | 胡牌时,牌型由一种花色的顺序牌组成。 | |
一色三同顺 | 胡牌时,牌里有一种花色且依次递增一位数字的3副刻子。不记番: 一色三节高、一般高 | |
一色三节高 | 胡牌时,牌里有一种花色且依次递增一位数字的3副刻子。不记番: 一色三同顺 |
16番
番型 | 胡牌方式 | 示例 |
---|---|---|
清龙 | 胡牌时,有一种相同花色的123,456,789三付顺子即可。清龙就是清一色条龙。不记番:连6、老少副。 | |
一色三步高 | 胡牌时,牌里有一种花色的牌,依次递增一位或依次递增二位数字的3副顺子。三暗刻:胡牌时,牌里有3个暗刻。不记番:双暗刻。 | |
天听 | 庄家打出第-张牌时报听称为天听;发完牌后闲家便报听也称为天听。天听要在胡牌后才算番。如果庄家在发完牌后有暗杠,则庄家不算天听。如果发完牌之后有补花,补花之后报听也算天听。 | |
三暗刻 | 胡牌时,牌里有3个暗刻。 |
12番
番型 | 胡牌方式 | 示例 |
---|---|---|
大于5 | 胡牌时,牌型由序数牌6 9的顺子、刻子、将牌组成。 | |
小于5 | 胡牌时,牌型由序数牌1-4的顺子、刻子、将牌组成。 | |
三风刻 | 胡牌时,牌里有3个风刻。 |
8番
番型 | 胡牌方式 | 示例 |
---|---|---|
妙手回春 | 自摸牌墙上最后一张牌胡牌。不记番: 自摸。 | |
海底捞月 | 和打出的最后一张牌。 | |
杠上开花 | 胡牌时,开杠抓进的牌成胡牌。不记番:自摸。 | |
抢杠胡 | 胡牌时,和别人自抓开明杠的牌。不记番:胡绝张。 |
6番
番型 | 胡牌方式 | 示例 |
---|---|---|
碰碰胡 | 胡牌时,牌型由4副刻子(或杠)、将牌组成。 | |
双暗杠 | 胡牌时,有2个暗杠。 | |
混一色 | 胡牌时,牌型由一种花色序数牌及字牌组成。 | |
全求人 | 胡牌时,全靠吃牌、碰牌、单钓别人打出的牌胡牌。不记番:单钓。 | |
双箭刻 | 胡牌时,牌里有2副箭刻(或杠)。不记番:箭刻。 |
4番
番型 | 胡牌方式 | 示例 |
---|---|---|
全带幺 | 胡牌时,每副牌、将牌都有么牌。(胡牌时各组牌除了字牌都必须有一或九的序数牌)。 | |
不求人 | 胡牌时,4副牌及将中没有吃牌、碰牌(包括明杠),自摸胡牌。 | |
双明杠 | 胡牌时,牌里有2个明杠。不记番:明杠。 | |
和绝张 | 胡牌时,胡牌池、桌面已亮明的3张牌所剩的第4张牌。 |
2番
番型 | 胡牌方式 | 示例 |
---|---|---|
箭刻 | 胡牌时,牌里有中、发、白,这3个牌中的任一个牌组成的1副刻子。 | |
门风刻 | 胡牌时牌里有与门风相同的风刻。 | |
门前清 | 没有吃、碰、明杠,和别人打出的牌。 | |
平胡 | 胡牌时,牌型由4副顺子及序数牌作将组成。边、坎、钓不影响平和。 | |
四归一 | 胡牌时,牌里有4张相同的牌归于一家的顺、刻子、对、将牌中(不包括杠牌)。双暗刻:胡牌时,牌里有2个暗刻。 | |
双暗刻 | 胡牌时,牌里有2个暗刻。 | |
暗杠 | 胡牌时,牌里有一副自抓4张相同的牌且开杠。 | |
断幺 | 胡牌时,牌里没有一、九牌及字牌。 | |
报听 | 报听后胡牌。 |
1番
番型 | 胡牌方式 | 示例 |
---|---|---|
一般高 | 胡牌时,牌里有一种花色且序数相同的2副顺子。 | |
连六 | 一种花色六张序数相连的顺子(例如: 3-4-5条和6-7-8条) | |
老少副 | 胡牌时,牌里花色相同的123、789的顺子各一副。 | |
幺九刻 | 胡牌时,牌里有序数为一、九的一副刻子(杠)或是字牌的一副刻子(杠)。 | |
明杠 | 自己有暗刻,碰别人打出的一张相同的牌开杠:或自己抓进一张与碰的明刻相同。 | |
边张 | 单和123的3及789的7或1233和3、7789和7都为边张。手中有12345和3,56789和7不算边张。 | |
坎张 | 胡牌时,和2张牌之间的牌。4556和5也为坎张,手中有45567和6不算坎张。 | |
单钓将 | 钓单张牌作将成和。 | |
自摸 | 自己抓进牌成胡牌。 | |
二五八将 | 胡牌时,将牌是二万、五万、八万。 |
番型计算
在上一篇文章中提到的查表法进行胡牌判定,其中查表法会给我们提供两个返回值,一个是是否胡牌的布尔值,还有一个是胡牌类型返回结果(MahjongResult):
//牌型结果
type MahjongResult struct {
Num_ke int //刻子数量
Num_shun int //顺子数量
Jiang byte //将牌值
Array_ke []byte //刻子数组
Array_shun []byte //顺子数组
Qidui bool //是否七对
Tongtian bool //是否通天
}
右手牌(吃碰杠):
//一组牌
type Meld struct {
Key byte //Key牌 牌面值
Kind WEAVE_KIND //组牌类型
Ids []byte //id 数组 唯一id
Values []byte //牌面值 数组
Sites []byte //座位 数组
}
结合右手牌(吃碰杠)信息,将每一种胡牌牌型统计成一个结构体:
//统计一种胡牌类型麻将角色(刻子等)
type MahjongCount struct {
Jiang byte //将牌值
Array_ke []byte //刻子数组 只列第一个 索引(包含暗刻 和碰)
Array_a_ke []byte //暗刻
Array_shun []byte //顺子数组 只列第一个
Array_c_shun []byte //吃牌获得的顺子
Array_h_shun []byte //手牌中的顺子
Array_gang []byte //杠数组 只列第一个 (包含明杠 暗杠)
Array_m_gang []byte //明杠
Array_a_gang []byte //暗杠
TileIndexs []byte //玩家所有牌 索引
QiDui bool //是否七对
TongTian bool //是否通天
Zimo bool // 是否自摸
HuId byte // 胡牌那张 唯一id
HuIndex byte //胡得那张牌得索引
MenFeng byte //当前胡牌玩家门风(庄为0x31东 闲家为 033西)
TingBool bool //是否报听
}
转换代码:
//将麻将 手牌 和右手牌统一到MahjongCount,每一个MahjongCount都是一种胡牌牌型
func CountMahjongResult(results []*MahjongResult, meld []*Meld, tileIndexs []byte, zimo bool, huId, huIndex, menFeng byte, baoTing bool) []*MahjongCount {
res := make([]*MahjongCount, 0)
if results != nil && len(results) > 0 {
//遍历手牌
for _, v := range results {
mc := &MahjongCount{}
mc.Zimo = zimo
mc.HuId = huId
mc.HuIndex = huIndex
mc.TingBool = baoTing
mc.TileIndexs = make([]byte, len(tileIndexs)) //初始化tiles
mc.TileIndexs = append(mc.TileIndexs, tileIndexs...) //将tilesIndexs值复制给 tiles
mc.QiDui = v.Qidui //是否七对
mc.TongTian = v.Tongtian //是否通天
mc.Jiang = v.Jiang //将牌
mc.MenFeng = menFeng //门风
mc.Array_ke = append(mc.Array_ke, v.Array_ke...) //暗刻
mc.Array_a_ke = append(mc.Array_a_ke, v.Array_ke...) //暗刻
mc.Array_shun = append(mc.Array_shun, v.Array_shun...) //顺子
mc.Array_h_shun = append(mc.Array_h_shun, v.Array_shun...)
res = append(res, mc)
}
}
//遍历右手牌
if meld != nil && len(meld) > 0 {
for _, m := range meld {
index := ValueToIndex(m.Values[0])
if len(res) == 0 {
mc := &MahjongCount{}
mc.Zimo = zimo
mc.HuId = huId
mc.HuIndex = huIndex
mc.MenFeng = menFeng //门风
mc.TingBool = baoTing
mc.TileIndexs = make([]byte, len(tileIndexs)) //初始化tiles
mc.TileIndexs = append(mc.TileIndexs, tileIndexs...) //将tilesIndexs值复制给 tiles
res = append(res, mc)
}
for _, v := range res {
//右手 牌类型为左吃 或右吃或中吃
if m.Kind == KIND_LEFT || m.Kind == KIND_RIGHT || m.Kind == KIND_CENTER {
v.Array_shun = append(v.Array_shun, index) //将顺子添加到count中
v.Array_c_shun = append(v.Array_c_shun, index)
for _, m := range m.Values {
v.TileIndexs[ValueToIndex(m)] ++
}
} else if m.Kind == KIND_PENG { //如果右手牌是 刻子
v.Array_ke = append(v.Array_ke, index)
v.TileIndexs[index] += 3
} else if m.Kind == KIND_GANG || m.Kind == KIND_ANGANG || m.Kind == KIND_JIAGANG { //如果右手牌是 明杠或者暗杠
v.Array_gang = append(v.Array_gang, index)
//将右手牌加入到所有牌中
v.TileIndexs[index] += 4
if m.Kind == KIND_ANGANG { //暗杠
v.Array_a_gang = append(v.Array_a_gang, index)
} else { //明杠
v.Array_m_gang = append(v.Array_m_gang, index)
}
}
}
}
}
for _, v := range res {
sortByte(v.Array_ke)
sortByte(v.Array_gang)
sortByte(v.Array_shun)
sortByte(v.Array_m_gang)
sortByte(v.Array_a_ke)
sortByte(v.Array_a_gang)
sortByte(v.Array_c_shun)
}
return res
}
//升序排序
func sortByte(a []byte) {
for i := 0; i < len(a); i++ {
l := len(a)
for j := i + 1; j < l; j++ {
if a[i] > a[j] {
temp := a[j]
a[j] = a[i]
a[i] = temp
}
}
l--
}
}
进过统计之后的牌型,只需要遍历所有番型进行判断即可。
由于番型种类过多,所以这里我们将函数写进map中,通过遍历这个map对其进行判断。番型返回的结果是一个二进制掩码,这里的番型有62种,所以我们可以使用int64位数对番型进行表示,一位二进制代表着一种番型。同时再使用一种排除番型,表示不能胡某种番。番型二进制掩码表示如下:
package mahjong
//胡牌掩码 null表示没有胡牌(试用二进制表示 1位代表胡牌)
const NULL = int64(0)
const (
// 二五八将 1
ERWUBAJIANG = int64(1) << iota
// 自摸 10
ZIMO
// 单调将 100
DANDIAOJIANG
// 坎张 1000
KANZHANG
// 边张 10000
BIANZHANG
// 明杠100000
MINGGANG
// 幺九刻 1000000
YAOJIUKE
// 老少副 10000000
LAOSHAOFU
// 连六 100000000
LIANLIU
// 一般高 1000000000
YIBANGAO
// 2f番
// 报听 10000000000
BAOTING
// 断幺 100000000000
DUANYAO
// 暗杠 13 2
ANGANG
// 双暗刻 14 2
SHUANGANKE
// 四归一 15 2
SIGUIYI
// 平胡 16 2
PINGHU
// 门前清 17 2
MENQIANQING
// 门风刻 18 2
MENFENGKE
// 箭刻 19 2
JIANKE
// 4fan
// 和绝张 20 4
HUJUEZHANG
// 双明杠 21 4
SHUANGMINGGANG
// 不求人 22 4
BUQIUREN
// 全带幺 23 4
QUANDAIYAO
// 6fan
// 双箭刻 24 6
SHUANGJIANKE
// 全求人 25 6
QUANQIUREN
// 混一色 26 6
HUNYISE
// 双暗杠 27 6
SHUANGANGANG
// 碰碰胡 28 6
PENGPENGHU
// 8fan
// 抢杠胡 29 8
QIANGGANGHU
// 杠上开花 30 8
GANGSHANGKAIHUA
// 海底捞月 31 8
HAIDILAOYUE
// 妙手回春 32 8
MIAOSHOUHUICHUN
// 12fan
// 三风刻 33 12
SANFENGKE
// 小于五 34 12
XIAOYUWU
// 大于五 35 12
DAYUWU
// 16fan
// 三暗刻 36 16
SANANKE
// 天听 37 16
TIANTING
// 一色三步高 38 16
YISESANBUGAO
// 清龙 39 16
QINGLONG
// 24fan
// 一色三节高 40 24
YISESANJIEGAO
// 一色三同顺 41 24
YISESANTONGSHUN
// 清一色 42 24
QINGYISE
// 七对 43 24
QIDUI
// 32fan
// 混幺九 44 32
HUNYAOJIU
// 三杠 45 32
SANGANG
// 一色四步高 46 32
YISESIBUGAO
// 48fan
// 一色四节高 47 48
YISESIJIEGAO
// 一色四同顺 48 48
YISESITONGSHUN
// 64fan
// 一色双龙会 49 64
YISESHUANGLONGHUI
// 四暗刻 50 64
SIANKE
// 字一色 51 64
ZIYISE
// 小三元 52 64
XIAOSANYUAN
// 小四喜 53 64
XIAOSIXI
// 88fan
// 地胡 55 88
DIHU
// 天胡 56 88
TIANHU
// 连七对 57 88
LIANQIDUI
// 四杠 58 88
SIGANG
// 大七星 59 88
DAQIXING
// 九宝莲灯 60 88
JIUBAOLIANDENG
// 大三元 61 88
DASANYUAN
// 大四喜 62 88
DASIXI
)
//胡牌番型判断切片
var HuType_slice = []int64 {
DASIXI,
DASANYUAN,
JIUBAOLIANDENG,
DAQIXING,
SIGANG,
LIANQIDUI,
XIAOSIXI,
XIAOSANYUAN,
ZIYISE,
SIANKE,
YISESHUANGLONGHUI,
YISESITONGSHUN,
YISESIJIEGAO,
YISESIBUGAO,
SANGANG,
HUNYAOJIU,
QIDUI,
QINGYISE,
YISESANTONGSHUN,
YISESANJIEGAO,
QINGLONG,
YISESANBUGAO,
TIANTING,
SANANKE,
DAYUWU,
XIAOYUWU,
SANFENGKE,
MIAOSHOUHUICHUN,
HAIDILAOYUE,
GANGSHANGKAIHUA,
PENGPENGHU,
SHUANGANGANG,
HUNYISE,
QUANQIUREN,
SHUANGJIANKE,
QUANDAIYAO,
BUQIUREN,
HUJUEZHANG,
JIANKE,
MENFENGKE,
MENQIANQING,
PINGHU,
SIGUIYI,
SHUANGANKE,
ANGANG,
DUANYAO,
BAOTING,
YIBANGAO,
LIANLIU,
LAOSHAOFU,
YAOJIUKE,
MINGGANG,
BIANZHANG,
KANZHANG,
DANDIAOJIANG,
ZIMO,
ERWUBAJIANG,
}
//胡牌掩码 对应的胡牌名称
var HuType_name = map[int64]string{
NULL: "NULL",
ERWUBAJIANG: "ERWUBAJIANG",
ZIMO: "ZIMO",
DANDIAOJIANG: "DANDIAOJIANG",
KANZHANG: "KANZHANG",
BIANZHANG: "BIANZHANG",
MINGGANG: "MINGGANG",
YAOJIUKE: "YAOJIUKE",
LAOSHAOFU: "LAOSHAOFU",
LIANLIU: "LIANLIU",
YIBANGAO: "YIBANGAO",
BAOTING: "BAOTING",
DUANYAO: "DUANYAO",
ANGANG: "ANGANG",
SHUANGANKE: "SHUANGANKE",
SIGUIYI: "SIGUIYI",
PINGHU: "PINGHU",
MENQIANQING: "MENQIANQING",
MENFENGKE: "MENFENGKE",
JIANKE: "JIANKE",
HUJUEZHANG: "HUJUEZHANG",
SHUANGMINGGANG: "SHUANGMINGGANG",
BUQIUREN: "BUQIUREN",
QUANDAIYAO: "QUANDAIYAO",
SHUANGJIANKE: "SHUANGJIANKE",
QUANQIUREN: "QUANQIUREN",
HUNYISE: "HUNYISE",
SHUANGANGANG: "SHUANGANGANG",
PENGPENGHU: "PENGPENGHU",
QIANGGANGHU: "QIANGGANGHU",
GANGSHANGKAIHUA: "GANGSHANGKAIHUA",
HAIDILAOYUE: "HAIDILAOYUE",
MIAOSHOUHUICHUN: "MIAOSHOUHUICHUN",
SANFENGKE: "SANFENGKE",
XIAOYUWU: "XIAOYUWU",
DAYUWU: "DAYUWU",
SANANKE: "SANANKE",
TIANTING: "TIANTING",
YISESANBUGAO: "YISESANBUGAO",
QINGLONG: "QINGLONG",
YISESANJIEGAO: "YISESANJIEGAO",
YISESANTONGSHUN: "YISESANTONGSHUN",
QINGYISE: "QINGYISE",
QIDUI: "QIDUI",
HUNYAOJIU: "HUNYAOJIU",
SANGANG: "SANGANG",
YISESIBUGAO: "YISESIBUGAO",
YISESIJIEGAO: "YISESIJIEGAO",
YISESITONGSHUN: "YISESITONGSHUN",
YISESHUANGLONGHUI: "YISESHUANGLONGHUI",
SIANKE: "SIANKE",
ZIYISE: "ZIYISE",
XIAOSANYUAN: "XIAOSANYUAN",
XIAOSIXI: "XIAOSIXI",
DIHU: "DIHU",
TIANHU: "TIANHU",
LIANQIDUI: "LIANQIDUI",
SIGANG: "SIGANG",
DAQIXING: "DAQIXING",
JIUBAOLIANDENG: "JIUBAOLIANDENG",
DASANYUAN: "DASANYUAN",
DASIXI: "DASIXI",
}
//胡牌对应的番值
var HuType_Fan_Value = map[string]int32{
"NULL": 0,
"ERWUBAJIANG": 1,
"ZIMO": 1,
"DANDIAOJIANG": 1,
"KANZHANG": 1,
"BIANZHANG": 1,
"MINGGANG": 1,
"YAOJIUKE": 1,
"LAOSHAOFU": 1,
"LIANLIU": 1,
"YIBANGAO": 1,
"BAOTING": 2,
"DUANYAO": 2,
"ANGANG": 2,
"SHUANGANKE": 2,
"SIGUIYI": 2,
"PINGHU": 2,
"MENQIANQING": 2,
"MENFENGKE": 2,
"JIANKE": 2,
"HUJUEZHANG": 4,
"SHUANGMINGGANG": 4,
"BUQIUREN": 4,
"QUANDAIYAO": 4,
"SHUANGJIANKE": 6,
"QUANQIUREN": 6,
"HUNYISE": 6,
"SHUANGANGANG": 6,
"PENGPENGHU": 6,
"QIANGGANGHU": 8,
"GANGSHANGKAIHUA": 8,
"HAIDILAOYUE": 8,
"MIAOSHOUHUICHUN": 8,
"SANFENGKE": 12,
"XIAOYUWU": 12,
"DAYUWU": 12,
"SANANKE": 16,
"TIANTING": 16,
"YISESANBUGAO": 16,
"QINGLONG": 16,
"YISESANJIEGAO": 24,
"YISESANTONGSHUN": 24,
"QINGYISE": 24,
"QIDUI": 24,
"HUNYAOJIU": 32,
"SANGANG": 32,
"YISESIBUGAO": 32,
"YISESIJIEGAO": 48,
"YISESITONGSHUN": 48,
"YISESHUANGLONGHUI": 64,
"SIANKE": 64,
"ZIYISE": 64,
"XIAOSANYUAN": 64,
"XIAOSIXI": 64,
"DIHU": 88,
"TIANHU": 88,
"LIANQIDUI": 88,
"SIGANG": 88,
"DAQIXING": 88,
"JIUBAOLIANDENG": 88,
"DASANYUAN": 88,
"DASIXI": 88,
}
番型掩码确定后就可以定义函数,
//判定胡牌类型 函数集合 key值为胡牌类型掩码,value为func
var funcFan map[int64]func(countResults *mahjong.MahjongCount, mask, noMask *int64)
胡牌番型判定只需遍历这个函数:
//计算胡牌 类型
func CountHuFan(countResults []*mahjong.MahjongCount) (int64, int64) {
mask := make([]int64, len(countResults)) //胡牌掩码
noMask := make([]int64, len(countResults)) //不能胡牌型 掩码
//遍历所有类型
maxMask := int64(0)
maxNoMask := int64(0)
for k, v := range countResults { //遍历结果
for _, i := range mahjong.HuType_slice {
if noMask[k]&i > 0 { //判断当前牌型是否可以胡
continue
}
f, ok := funcFan[i]
if !ok {
//fmt.Println("没有此牌型:", i)
continue
}
f(v, &mask[k], &noMask[k]) //调用对应函数 判断是否是此类型胡牌
}
if mask[k] > maxMask {
maxMask = mask[k]
maxNoMask = noMask[k]
}
}
return maxMask, maxNoMask
}
番型函数的map初始化需要在init函数中进行,
//初始化
func init() {
funcFan = make(map[int64]func(countResults *mahjong.MahjongCount, mask, noMask *int64), len(mahjong.HuType_slice))
funcFan[mahjong.DASIXI] = IsBigFourHappy //大四喜
funcFan[mahjong.DASANYUAN] = IsDaSanYuan //大三元
funcFan[mahjong.JIUBAOLIANDENG] = IsJiuLianBaoDeng //九莲宝灯
funcFan[mahjong.DAQIXING] = IsDaQiXing //大七星
funcFan[mahjong.SIGANG] = IsSiGang //四杠
funcFan[mahjong.LIANQIDUI] = IsLianQiDui //连七对
funcFan[mahjong.XIAOSIXI] = IsXiaoSiXi //小四喜
funcFan[mahjong.XIAOSANYUAN] = IsXiaoSanYuan //小三元
funcFan[mahjong.ZIYISE] = IsZiYiSe //字一色
funcFan[mahjong.SIANKE] = IsSiAnKe //四暗刻
funcFan[mahjong.YISESHUANGLONGHUI] = IsYiSeShuangLongHui //一色双龙会
funcFan[mahjong.YISESITONGSHUN] = IsYiSeSiTongShun //一色四同顺
funcFan[mahjong.YISESIJIEGAO] = IsYiSeSiJieGao //一色四节高
funcFan[mahjong.YISESIBUGAO] = IsYiSeSiBuGao //一色四步高
funcFan[mahjong.SANGANG] = IsSanGang //三杠
funcFan[mahjong.HUNYAOJIU] = IsHunYaoJiu //混幺九
funcFan[mahjong.QIDUI] = IsQiDui //七对
funcFan[mahjong.QINGYISE] = IsQingYiSe //清一色
funcFan[mahjong.YISESANTONGSHUN] = IsYiSeSanTongShun //一色三同顺
funcFan[mahjong.YISESANJIEGAO] = IsYiSeSanJieGao //一色三节高
funcFan[mahjong.QINGLONG] = IsQingLong //清龙
funcFan[mahjong.YISESANBUGAO] = IsYiSeSanBuGao //一色三步高
funcFan[mahjong.TIANTING] = IsTianTing //天听
funcFan[mahjong.SANANKE] = IsSanAnKe //三暗刻
funcFan[mahjong.DAYUWU] = IsDaYuWu //大于五
funcFan[mahjong.XIAOYUWU] = IsXiaoYuWu //小于五
funcFan[mahjong.SANFENGKE] = IsSanFengKe //三风刻
funcFan[mahjong.MIAOSHOUHUICHUN] = IsMiaoShouHuiChun //妙手回春
funcFan[mahjong.HAIDILAOYUE] = IsHaiDiLaoYue //海底捞月
funcFan[mahjong.GANGSHANGKAIHUA] = IsGangShangKaiHua //杠上开花 上层方法计算
funcFan[mahjong.QIANGGANGHU] = IsQiangGangHu //抢杠胡 上层方法计算
funcFan[mahjong.PENGPENGHU] = IsPengPengHu //碰碰胡
funcFan[mahjong.SHUANGANGANG] = IsShuangAnGang //双暗杠
funcFan[mahjong.HUNYISE] = IsHunYiSe //混一色
funcFan[mahjong.QUANQIUREN] = IsQuanQiuRen //全求人
funcFan[mahjong.SHUANGJIANKE] = IsShuangJianKe //双箭刻
funcFan[mahjong.QUANDAIYAO] = IsQuanDaiYao //全带幺
funcFan[mahjong.BUQIUREN] = IsBuQiuRen //不求人
funcFan[mahjong.SHUANGMINGGANG] = IsShuangMingGang //双明杠
funcFan[mahjong.HUJUEZHANG] = IsHuJueZhang //胡绝张
funcFan[mahjong.JIANKE] = IsJianKe //箭刻
funcFan[mahjong.MENFENGKE] = IsMenFengKe //门风刻
funcFan[mahjong.MENQIANQING] = IsMenQianQing //门前清
funcFan[mahjong.PINGHU] = IsPingHu //平胡
funcFan[mahjong.SIGUIYI] = IsSiGuiYi //四归一
funcFan[mahjong.SHUANGANKE] = IsShuangAnKe //双暗刻
funcFan[mahjong.ANGANG] = IsAnGang //暗杠
funcFan[mahjong.DUANYAO] = IsDuanYao //断幺
funcFan[mahjong.BAOTING] = IsBaoTing //报听
funcFan[mahjong.YIBANGAO] = IsYiBanGao //一般高
funcFan[mahjong.LIANLIU] = IsLianLiu //连六
funcFan[mahjong.LAOSHAOFU] = IsLaoShaoFu //老少副
funcFan[mahjong.YAOJIUKE] = IsYaoJiuKe //幺九刻
funcFan[mahjong.MINGGANG] = IsMingGang //明杠
funcFan[mahjong.BIANZHANG] = IsBianZhang //边张
funcFan[mahjong.KANZHANG] = IsKanZhang //坎张
funcFan[mahjong.DANDIAOJIANG] = IsDanDiaoJiang //单钓将
funcFan[mahjong.ZIMO] = IsZiMo //自摸
funcFan[mahjong.ERWUBAJIANG] = IsErWuBaJiang //二五八将
}
下面是62种番型计算方法:
/**
0 1 2 3 4 5 6 7 8 9 万 索引
27 28 29 30 风
31 32 33 中发白
*/
/**
params:
results : 判断手牌是否胡牌返回结果
melds :右手牌
*/
//大四喜
//胡牌时,牌里有4组风牌刻子(杠)加一对将牌组成的牌型。(不计门风刻、圈风刻、小四喜、三风刻、碰碰胡、幺九刻)
func IsBigFourHappy(v *mahjong.MahjongCount, mask, noMask *int64) {
//判断4组风刻子情况
//判断手牌中的刻子的情况
num_ke := len(v.Array_ke)
num_gang := len(v.Array_gang)
//一副牌中 刻的数量没有4个 并且 杠的数量也没有4个 必定不是大四喜
if num_ke != 4 && num_gang != 4 {
return
} else {
//杠或刻子的数量是 4个 ,判断是否是风牌杠
arr := v.Array_ke
if num_gang == 4 {
arr = v.Array_gang
}
bo := true
for _, m := range arr {
if m < 27 || m > 30 { //杠、刻不是风
bo = false
break
}
}
if !bo {
return
}
*mask |= mahjong.DASIXI
//不计门风刻 小四喜 三风刻 碰碰胡 幺九刻
*noMask |= mahjong.MENFENGKE | mahjong.XIAOSIXI | mahjong.SANFENGKE | mahjong.PENGPENGHU | mahjong.YAOJIUKE
return
}
return
}
//大三元
//胡牌时,牌里有中、发、白3副刻子。(不计双箭刻、箭刻)
func IsDaSanYuan(v *mahjong.MahjongCount, mask, noMask *int64) {
lenKe := len(v.Array_ke)
if lenKe < 3 { // 判断胡牌中 刻子数是否大于三 最多只有4刻子
return
}
//如果有三幅以上刻子 则判断这三幅刻子是否是中 发 白 0x35 0x36 0x37
//如果刻子数=3,并且第一个不是 中 0x35 或者 刻子数=4,并且第二个刻子不是中0x35
if (lenKe == 3 && mahjong.IndexToValue(v.Array_ke[0]) != 0x35) || (lenKe == 4 && mahjong.IndexToValue(v.Array_ke[1]) != 0x35) {
return
}
*mask |= mahjong.DASANYUAN
//排除牌型
*noMask |= mahjong.SHUANGJIANKE | mahjong.JIANKE
return
}
//九莲宝灯
//由一种花色序数组成的特定牌型,见同花色任何一张序数牌即成胡牌。不计清一色,门前清,自摸
//牌型为 11123456789999
func IsJiuLianBaoDeng(v *mahjong.MahjongCount, mask, noMask *int64) {
fmt.Println("jiang:", v.Jiang)
//判断将牌是否是1
if v.Jiang != 0 {
return
}
//判断刻子是否是9
if len(v.Array_ke) != 1 || (v.Array_ke[0] != 8) {
return
}
//判断顺子是否是 1 4 7
if len(v.Array_shun) != 3 || (v.Array_shun[0] != 0 || v.Array_shun[1] != 3 || v.Array_shun[2] != 6) {
return
}
*mask |= mahjong.JIUBAOLIANDENG
*noMask |= mahjong.QINGYISE | mahjong.MENQIANQING | mahjong.ZIMO
}
//大七星
//胡牌为七对子,并且由“东南西北中发白“其中字牌构成,不计七对,三元七对,四喜七对,全带幺,单钓将,门前清,自摸,字一色
func IsDaQiXing(v *mahjong.MahjongCount, mask, noMask *int64) {
if !v.QiDui { //如果不是七对
return
}
//遍历所有牌型,可以从东南西北中发白 处开始遍历
bo := true
for i := byte(27); i < mahjong.MAX_INDEX; i++ {
if v.TileIndexs[i] != 2 {
bo = false
break
}
}
if bo {
*mask |= mahjong.DAQIXING
*noMask |= mahjong.QIDUI | mahjong.QUANDAIYAO | mahjong.DANDIAOJIANG | mahjong.MENQIANQING | mahjong.ZIMO | mahjong.ZIYISE
}
}
//四杠
//4个杠,不计三杠,双明杠,明杠,单钓将
func IsSiGang(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_gang) != 4 { //杠的数量没有四个
return
}
*mask |= mahjong.SIGANG
*noMask |= mahjong.SANGANG | mahjong.SHUANGMINGGANG | mahjong.MINGGANG | mahjong.DANDIAOJIANG
}
//连七对
//由一种花色序数牌组成序数相连的7个对子的胡牌。不计七对,单钓将,门前清,自摸,清一色
func IsLianQiDui(v *mahjong.MahjongCount, mask, noMask *int64) {
if !v.QiDui { //不是七对
return
}
//判断这七对是否是顺序
bo := true
for i := byte(0); i < 9; i++ { //由于是二人麻将,只有一种序数牌(万),所以只需判断前九个
if v.TileIndexs[i] != 2 {
bo = false
break
}
}
if bo {
*mask |= mahjong.LIANQIDUI
*noMask |= mahjong.QIDUI | mahjong.DANDIAOJIANG | mahjong.MENQIANQING | mahjong.QINGYISE
}
}
//小四喜
//胡牌时,牌里有风牌的3副刻子及将牌。不记番:三风刻、幺九刻。
func IsXiaoSiXi(v *mahjong.MahjongCount, mask, noMask *int64) {
lke := len(v.Array_ke)
fmt.Println(v)
if lke < 3 { //判断刻子数是否小于三
return
}
//判断将牌是否是风牌
if v.Jiang > 30 || v.Jiang < 27 {
return
}
num := 0
//判断是否有三个风牌刻子
for _, m := range v.Array_ke {
if m >= 27 && m <= 30 {
num ++
}
}
if num != 3 {
return
}
*mask |= mahjong.XIAOSIXI
*noMask |= mahjong.SANFENGKE | mahjong.YAOJIUKE
}
//小三元
//胡牌时,牌里有箭牌的两副刻子及将牌。不记番:箭刻、双箭刻
func IsXiaoSanYuan(v *mahjong.MahjongCount, mask, noMask *int64) {
//将牌必须是箭牌
if v.Jiang < 31 {
return
}
//刻子数不能少于2副
if len(v.Array_ke) <= 1 {
return
}
//刻子中有两副是箭牌
num := 0
for _, m := range v.Array_ke {
if m >= 31 {
num++
}
}
if num < 2 {
return
}
*mask |= mahjong.XIAOSANYUAN
*noMask |= mahjong.JIANKE | mahjong.SHUANGJIANKE
}
//字一色(字牌 包含风牌(东南西北)和箭牌(中发白))
//胡牌时,牌型由字牌的刻子(杠)、将组成。不记番:碰碰和、混么九、全带幺、么九刻。
func IsZiYiSe(v *mahjong.MahjongCount, mask, noMask *int64) {
//将牌必须是字牌
if v.Jiang < 27 {
return
}
//不可能有顺子
if len(v.Array_shun) > 0 {
return
}
bo := true
kg := make([]byte, 0)
kg = append(append(kg, v.Array_ke...), v.Array_gang...)
//刻子、杠都要为字牌
for _, m := range kg {
if m < 27 {
bo = false
break
}
}
if !bo {
return
}
*mask |= mahjong.ZIYISE
*noMask |= mahjong.PENGPENGHU | mahjong.HUNYAOJIU | mahjong.QUANDAIYAO | mahjong.YAOJIUKE
}
//四暗刻
//胡牌时,牌里有4个暗刻(暗杠)。不记番:门前清、碰碰和、三暗刻、双暗刻、不求人。
func IsSiAnKe(v *mahjong.MahjongCount, mask, noMask *int64) {
//判断暗刻和暗杠数量之和
if len(v.Array_a_ke)+len(v.Array_a_gang) < 4 {
return
}
*mask |= mahjong.SIANKE
*noMask |= mahjong.MENQIANQING | mahjong.PENGPENGHU | mahjong.SANANKE | mahjong.SHUANGANKE | mahjong.BUQIUREN
}
//一色双龙会
//胡牌时,牌型由一种花色的两个老少副,5为将牌组成。不记番:平和、七对、清色、一般高、老少副
//老少副:胡牌时,牌里花色相同的123、789的顺子各一副
//二人麻将只有一种情况 1 2 3 1 2 3 5 7 8 9 7 8 9 5
func IsYiSeShuangLongHui(v *mahjong.MahjongCount, mask, noMask *int64) {
///将牌必须是5
if v.Jiang != 4 {
return
}
//顺子数必须是4个
if len(v.Array_shun) != 4 {
return
}
//1 和9 开头的顺子必须都有两个
num1 := 0
num9 := 0
for _, m := range v.Array_shun {
if m == 0 {
num1++
}
if m == 6 {
num9++
}
}
if num1 != 2 || num9 != 2 {
return
}
*mask |= mahjong.YISESHUANGLONGHUI
*noMask |= mahjong.PINGHU | mahjong.QIDUI | mahjong.QINGYISE | mahjong.YIBANGAO | mahjong.LAOSHAOFU
}
//一色四同顺
//牌里有一种花色且序数相同的4副顺子。不记番:一色三节高、一般高、四归一,一色三同顺、七对。
func IsYiSeSiTongShun(v *mahjong.MahjongCount, mask, noMask *int64) {
//顺子数要4个
if len(v.Array_shun) != 4 {
return
}
//顺子要一样
bo := true
f := v.Array_shun[0]
for _, m := range v.Array_shun {
if f != m {
bo = false
break
}
}
if !bo {
return
}
*mask |= mahjong.YISESITONGSHUN
*noMask |= mahjong.YISESANJIEGAO | mahjong.YIBANGAO | mahjong.SIGUIYI | mahjong.YISESANTONGSHUN | mahjong.QIDUI
}
//一色四节高
//胡牌时牌里有一种花色且序数依次递增一位数的4副刻子(或杠子)。不记番:一色三同顺、一色三节高、碰碰和。
func IsYiSeSiJieGao(v *mahjong.MahjongCount, mask, noMask *int64) {
//杠或者刻子数只能是四个
if len(v.Array_ke) != 4 && len(v.Array_gang) != 4 {
return
}
a := make([]byte, 0)
a = v.Array_ke[:]
if len(v.Array_gang) == 4 {
a = v.Array_gang[:]
}
//最后一个刻或者杠 与第一个杠或者刻相差3(因为Array_ke 和Array_gang是经过排序的)
if a[3]-a[0] != 3 {
return
}
*mask |= mahjong.YISESIJIEGAO
*noMask |= mahjong.YISESANTONGSHUN | mahjong.YISESANJIEGAO | mahjong.PENGPENGHU
}
//一色四步高
//胡牌时,牌里有一种花色4副依次递增一位数或依次递增二位数的顺子。不记番:一色三步高。
//递增一位:123 234 345 456 北北 递增两位: 123 345 567 789 北北
func IsYiSeSiBuGao(v *mahjong.MahjongCount, mask, noMask *int64) {
//顺子数必须是4个
if len(v.Array_shun) != 4 {
return
}
// 第一个顺子和第二个顺子之间的差
c := v.Array_shun[1] - v.Array_shun[0]
if c != 1 && c != 2 { //相差必须是1 或者2
return
}
bo := true
//从第三个顺子开始判断,
for i := 2; i < len(v.Array_shun); i++ {
if v.Array_shun[i]-v.Array_shun[i-1] != c {
bo = false
break
}
}
if !bo {
return
}
*mask |= mahjong.YISESIBUGAO
*noMask |= mahjong.YISESANBUGAO
}
//三杠
//胡牌时,牌里有3副杠,明杠暗杠均可。
func IsSanGang(v *mahjong.MahjongCount, mask, noMask *int64) {
//必须三幅杠
if len(v.Array_gang) != 3 {
return
}
*mask |= mahjong.SANGANG
}
//混幺九
//胡牌时,由字牌和序数牌、九的刻子及将牌组成的牌型。不记番:碰碰和、幺九刻、全带么。
func IsHunYaoJiu(v *mahjong.MahjongCount, mask, noMask *int64) {
//刻子数至少两个
if len(v.Array_ke) < 2 {
return
}
ziKe := 0
yjKe := 0
for _, m := range v.Array_ke {
if m == 0 || m == 8 {
yjKe ++
} else if m > 30 {
ziKe ++
}
}
if yjKe != 2 {
return
}
if ziKe < 1 {
return
}
*mask |= mahjong.HUNYAOJIU
*noMask |= mahjong.PENGPENGHU | mahjong.YAOJIUKE | mahjong.QUANDAIYAO
}
//七对
//胡牌时,胡牌时,牌型由7个对子组成。(不计门前清、不求人、单钓将)
func IsQiDui(v *mahjong.MahjongCount, mask, noMask *int64) {
if !v.QiDui {
return
}
*mask |= mahjong.QIDUI
*noMask |= mahjong.MENQIANQING | mahjong.BUQIUREN | mahjong.DANDIAOJIANG
}
//清一色
//胡牌时,牌型由一种花色的顺序牌组成
func IsQingYiSe(v *mahjong.MahjongCount, mask, noMask *int64) {
//检查将牌 刻子 顺子 杠 是否是同一色(二人麻将只需判断是否是万牌)
if v.Jiang > 8 {
return
}
//最大一个刻必须是万
if len(v.Array_ke) > 0 && v.Array_ke[len(v.Array_ke)-1] > 8 {
return
}
//最大杠必须是万
if len(v.Array_gang) > 0 && v.Array_gang[len(v.Array_gang)-1] > 8 {
return
}
//顺子不需要判断,因为二人麻将只有万才会有顺子
*mask |= mahjong.QINGYISE
}
//一色三同顺
//胡牌时,牌里有一种花色且依次递增一位数字的3副顺子。不记番: 一色三节高、一般高
func IsYiSeSanTongShun(v *mahjong.MahjongCount, mask, noMask *int64) {
l := len(v.Array_shun)
//顺子必须三幅以上
if l < 3 {
return
}
num := 1
for i := 0; i < l-1; i++ {
if v.Array_shun[i] == v.Array_shun[i+1] {
num++
} else if i == 1 {
num = 0
}
}
if num < 3 {
return
}
*mask |= mahjong.YISESANTONGSHUN
*noMask |= mahjong.YISESANJIEGAO | mahjong.YIBANGAO
}
//一色三节高
//胡牌时,牌里有一种花色且依次递增一位数字的3副刻子。不记番: 一色三同顺
func IsYiSeSanJieGao(v *mahjong.MahjongCount, mask, noMask *int64) {
//刻子数至少是三个
l := len(v.Array_ke)
if l < 3 {
return
}
num := 1
for i := 0; i < l-1; i++ {
if v.Array_ke[i]+1 == v.Array_ke[i+1] {
num++
} else if i == 1 {
break
}
}
if num < 3 {
return
}
*mask |= mahjong.YISESANJIEGAO
*noMask |= mahjong.YISESANTONGSHUN
}
//清龙
//胡牌时,有一种相同花色的123,456,789三付顺子即可。清龙就是清一色条龙。不记番:连6、老少副。
func IsQingLong(v *mahjong.MahjongCount, mask, noMask *int64) {
//顺子至少三个
l := len(v.Array_shun)
if l < 3 {
return
}
num1 := false
num4 := false
num7 := false
//遍历顺子,判断是否存在 1 4 7 开头的顺子。
for _, m := range v.Array_shun {
if m == 0 {
num1 = true
} else if m == 3 {
num4 = true
} else if m == 6 {
num7 = true
}
}
if num1 && num4 && num7 {
*mask |= mahjong.QINGLONG
*noMask |= mahjong.LIANLIU | mahjong.LAOSHAOFU
}
}
//一色三步高
//胡牌时,牌里有一种花色的牌,依次递增一位或依次递增二位数字的3副顺子。
/*
123 234 345 777 3131
123 345 456 567 303030 3131
*/
func IsYiSeSanBuGao(v *mahjong.MahjongCount, mask, noMask *int64) {
//顺子三个以上
l := len(v.Array_shun)
if l < 3 {
return
}
//相差1
n1 := 0
n2 := 0
for i := 0; i < l-1; i++ {
if v.Array_shun[i+1]-v.Array_shun[i] == 1 {
n1 ++
} else if v.Array_shun[i+1]-v.Array_shun[i] == 2 {
n2 ++
}
}
if n1 < 2 && n2 < 2 {
return
}
c := byte(1)
if n2 > 1 {
c = 2
}
if l == 3 {
*mask |= mahjong.YISESANBUGAO
} else {
if v.Array_shun[2]-v.Array_shun[1] == c {
*mask |= mahjong.YISESANBUGAO
}
}
}
//天听
///庄家打出第-张牌时报听称为天听;发完牌后闲家便报听也称为天听。天听要在胡牌后才算番。如果庄家在发完牌后有暗杠,则庄家不算天听。如果发完牌之后有补花,补花之后报听也算天听。
func IsTianTing(v *mahjong.MahjongCount, mask, noMask *int64) {
}
//三暗刻
//胡牌时,牌里有3个暗刻。
func IsSanAnKe(v *mahjong.MahjongCount, mask, noMask *int64) {
//暗刻必须三个
if len(v.Array_a_ke) < 3 {
return
}
*mask |= mahjong.SANANKE
}
//大于五
//胡牌时,牌型由序数牌6 9的顺子、刻子、将牌组成。(二人麻将只需判断万牌)
func IsDaYuWu(v *mahjong.MahjongCount, mask, noMask *int64) {
sum := byte(0)
//判断所有牌索引是否在5-8之间(至少是14张牌)
for i := 5; i < 9; i++ {
sum += v.TileIndexs[i]
}
if sum < 14 {
return
}
*mask |= mahjong.DAYUWU
}
//小于五
//胡牌时,牌型由序数牌1-4的顺子、刻子、将牌组成。
func IsXiaoYuWu(v *mahjong.MahjongCount, mask, noMask *int64) {
sum := byte(0)
for i := 0; i < 5; i++ {
sum += v.TileIndexs[i]
}
if sum < 14 {
return
}
*mask |= mahjong.XIAOYUWU
}
//三风刻
//胡牌时,牌里有3个风刻
func IsSanFengKe(v *mahjong.MahjongCount, mask, noMask *int64) {
//刻子必须有三个以上
if len(v.Array_ke) < 3 {
return
}
sum := 0
for _, m := range v.Array_ke {
if m < 31 && m > 26 {
sum++
}
}
if sum > 2 {
*mask |= mahjong.SANFENGKE
}
}
//妙手回春
//最后一张牌 ,自摸胡牌。不记番: 自摸。
func IsMiaoShouHuiChun(v *mahjong.MahjongCount, mask, noMask *int64) {
//必须是自摸
if !v.Zimo {
return
}
//牌唯一id必须是最后一张
if v.HuId == MaxTiles-1 {
*mask |= mahjong.MIAOSHOUHUICHUN
*noMask |= mahjong.ZIMO
}
}
//海底捞月
//胡最后一张打出来的牌
func IsHaiDiLaoYue(v *mahjong.MahjongCount, mask, noMask *int64) {
//不能是自摸
if v.Zimo {
return
}
//牌必须是最后一张
if v.HuId == MaxTiles-1 {
*mask |= mahjong.HAIDILAOYUE
}
}
//杠上开花
//胡牌时,开杠抓进的牌成胡牌。不记番:自摸。
func IsGangShangKaiHua(v *mahjong.MahjongCount, mask, noMask *int64) {
//杠上开花在上层计算
}
//抢杠胡
//胡牌时,和别人自抓开明杠的牌。不记番:胡绝张。
func IsQiangGangHu(v *mahjong.MahjongCount, mask, noMask *int64) {
//抢杠胡在上层计算
}
//碰碰胡
//胡牌时,牌型由4副刻子(或杠)、将牌组成。
func IsPengPengHu(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_ke) != 4 && len(v.Array_gang) != 4 {
return
}
*mask |= mahjong.PENGPENGHU
}
//双暗杠
//胡牌时,有2个暗杠
func IsShuangAnGang(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_a_gang) == 2 {
*mask |= mahjong.SHUANGANGANG
}
}
//混一色
//胡牌时,牌型由一种花色序数牌及字牌组成
func IsHunYiSe(v *mahjong.MahjongCount, mask, noMask *int64) {
//
bo := false
bo1 := false
for i := byte(0); i < byte(9); i++ {
if v.TileIndexs[i] > 0 {
bo = true
break
}
}
for i := byte(27); i < mahjong.MAX_INDEX; i++ {
if v.TileIndexs[i] > 0 {
bo1 = true
break
}
}
if bo && bo1 {
*mask |= mahjong.HUNYISE
}
}
//全求人
//胡牌时,全靠吃牌、碰牌、单钓别人打出的牌胡牌。不记番:单钓。
func IsQuanQiuRen(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_c_shun) != len(v.Array_shun) || len(v.Array_a_gang) != 0 || len(v.Array_a_ke) != 0 {
return
}
*mask |= mahjong.QUANQIUREN
*noMask |= mahjong.DANDIAOJIANG
}
//双箭刻
//胡牌时,牌里有2副箭刻(或杠)。不记番:箭刻。
func IsShuangJianKe(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_ke) != 2 && len(v.Array_gang) != 2 {
return
}
var a []byte
if len(v.Array_ke) == 2 {
a = v.Array_ke
} else {
a = v.Array_gang
}
bo := true
for _, m := range a {
if m < 31 {
bo = false
break
}
}
if bo {
*mask |= mahjong.SHUANGJIANKE
*noMask |= mahjong.JIANKE
}
}
//全带幺
//胡牌时,每副牌、将牌都有么或九牌。(胡牌时各组牌除了字牌都必须有一或九的序数牌)。
func IsQuanDaiYao(v *mahjong.MahjongCount, mask, noMask *int64) {
//将牌必须是1 或9
if v.Jiang != 0 && v.Jiang != 8 {
return
}
//顺子中必须有1 或9
for _, m := range v.Array_shun {
if m != 0 && m != 7 {
return
}
}
//刻子、杠必须是1 或者9
var a []byte
a = append(append(a, v.Array_ke...), v.Array_shun...)
for _, m := range a {
if m != 0 && m != 8 {
return
}
}
*mask |= mahjong.QUANDAIYAO
}
//不求人
//胡牌时,4副牌及将中没有吃牌、碰牌(包括明杠),自摸胡牌。
func IsBuQiuRen(v *mahjong.MahjongCount, mask, noMask *int64) {
//必须是自摸
if !v.Zimo {
return
}
//不能有吃、碰、和明杠
if len(v.Array_c_shun) != 0 || len(v.Array_a_ke) != len(v.Array_ke) || len(v.Array_m_gang) != 0 {
return
}
*mask |= mahjong.BUQIUREN
}
//双明杠
//胡牌时,牌里有2个明杠。不记番:明杠。
func IsShuangMingGang(v *mahjong.MahjongCount, mask, noMask *int64) {
//必须两个明杠
if len(v.Array_m_gang) != 2 {
return
}
*mask |= mahjong.SHUANGMINGGANG
*noMask |= mahjong.MINGGANG
}
//胡绝张
//胡牌时,胡牌池、桌面已亮明的3张牌所剩的第4张牌。
func IsHuJueZhang(v *mahjong.MahjongCount, mask, noMask *int64) {
//在上层实现
}
//箭刻
//胡牌时,牌里有中、发、白,这3个牌中的任一个牌组成的1副刻子
func IsJianKe(v *mahjong.MahjongCount, mask, noMask *int64) {
for _, m := range v.Array_ke {
if m > 29 {
*mask |= mahjong.JIANKE
return
}
}
}
//门风刻
//胡牌时牌里有与门风相同的风刻。
func IsMenFengKe(v *mahjong.MahjongCount, mask, noMask *int64) {
//刻子
if len(v.Array_ke) < 1 {
return
}
for _, m := range v.Array_ke {
if m == v.MenFeng {
*mask |= mahjong.MENFENGKE
return
}
}
}
//门前清
//没有吃、碰、明杠,和别人打出的牌。
func IsMenQianQing(v *mahjong.MahjongCount, mask, noMask *int64) {
///不能是自摸
if v.Zimo {
return
}
if len(v.Array_c_shun) != 0 || len(v.Array_a_ke) != len(v.Array_ke) || len(v.Array_m_gang) != 0 {
return
}
*mask |= mahjong.MENQIANQING
}
//平胡
//胡牌时,牌型由4副顺子及序数牌作将组成。边、坎、钓不影响平和。
func IsPingHu(v *mahjong.MahjongCount, mask, noMask *int64) {
//将必须是1-9
if v.Jiang > 8 {
return
}
//顺子有四个
if len(v.Array_shun) != 4 {
return
}
*mask |= mahjong.PINGHU
}
//四归一
//胡牌时,牌里有4张相同的牌归于一家的顺、刻子、对、将牌中(不包括杠牌)。
func IsSiGuiYi(v *mahjong.MahjongCount, mask, noMask *int64) {
//找到四张一样的牌(可以排除字牌)
s := make([]byte, 0)
for i, m := range v.TileIndexs {
if m == 4 {
s = append(s, byte(i))
}
}
//遍历这些四张一样的牌,只要不是杠,就可以
for _, c := range s {
bo := true
for _, k := range v.Array_gang {
if k == c {
bo = false
break
}
}
if bo {
*mask |= mahjong.SIGUIYI
return
}
}
}
//双暗刻
//胡牌时,牌里有2个暗刻。
func IsShuangAnKe(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_a_ke) == 2 {
*mask |= mahjong.SHUANGANKE
}
}
//暗杠
//胡牌时,牌里有一副自抓4张相同的牌且开杠
func IsAnGang(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_a_gang) > 0 {
*mask |= mahjong.ANGANG
}
}
//断幺
//胡牌时,牌里没有一、九牌及字牌。
func IsDuanYao(v *mahjong.MahjongCount, mask, noMask *int64) {
//没有1 和9
if v.TileIndexs[0] != 0 || v.TileIndexs[8] != 0 {
return
}
//判断字牌
for i := byte(27); i < mahjong.MAX_INDEX; i++ {
if v.TileIndexs[i] != 0 {
return
}
}
*mask |= mahjong.DUANYAO
}
//报听
//报听后胡牌。
func IsBaoTing(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.TingBool {
*mask |= mahjong.BAOTING
}
}
//一般高
//胡牌时,牌里有一种花色且序数相同的2副顺子。
func IsYiBanGao(v *mahjong.MahjongCount, mask, noMask *int64) {
//顺子数 必须是2个以上
if len(v.Array_shun) < 2 {
return
}
bo := false
for i, m := range v.Array_shun {
for j := i + 1; j < len(v.Array_shun); j++ {
if v.Array_shun[j] == m {
bo = true
break
}
}
if bo {
*mask |= mahjong.YIBANGAO
return
}
}
}
//连六
//一种花色六张序数相连的顺子(例如: 3-4-5条和6-7-8条)
func IsLianLiu(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_shun) < 2 {
return
}
for i := 0; i < len(v.Array_shun)-1; i++ {
if v.Array_shun[i+1]-v.Array_shun[i] == 3 {
*mask |= mahjong.LIANLIU
return
}
}
}
//老少副
//胡牌时,牌里花色相同的123、789的顺子各一副。
func IsLaoShaoFu(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_shun) < 2 {
return
}
o := 0
y := 0
for _, m := range v.Array_shun {
if o > 0 && y > 0 {
*mask |= mahjong.LAOSHAOFU
return
}
if m == 0 {
y++
} else if m == 8 {
o++
}
}
}
//幺九刻
//胡牌时,牌里有序数为一、九的一副刻子(杠)或是字牌的一副刻子(杠)。
func IsYaoJiuKe(v *mahjong.MahjongCount, mask, noMask *int64) {
var a []byte
a = append(append(a, v.Array_ke...), v.Array_gang...)
for _, m := range a {
if m == 0 || m == 8 || (m > 26 && m < 31) {
*mask |= mahjong.YAOJIUKE
return
}
}
}
//明杠
//自己有暗刻,碰别人打出的一张相同的牌开杠:或自己抓进一张与碰的明刻相同
func IsMingGang(v *mahjong.MahjongCount, mask, noMask *int64) {
if len(v.Array_m_gang) > 0 {
*mask |= mahjong.MINGGANG
}
}
//边张
//单和123的3及789的7或1233和3、7789和7都为边张。手中有12345和3,56789和7不算边张。
//123 3 胡得那张牌只能是顺子的两边牌,两个相邻的顺子不能有连接)
func IsBianZhang(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.HuIndex != 2 && v.HuIndex != 6 {
return
}
for _, m := range v.Array_h_shun {
if v.HuIndex == 2 {
if m == 2 {
return
}
} else if v.HuIndex == 6 && m+2 == 6 {
return
}
}
*mask |= mahjong.BIANZHANG
}
//坎张
//胡牌时,和2张牌之间的牌。4556和5也为坎张,手中有45567和6不算坎张。
func IsKanZhang(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.HuIndex == 0 || v.HuIndex == 8 {
return
}
//遍历手牌顺子,胡的那张牌必须在中间,
for _, m := range v.Array_h_shun {
if v.HuIndex == m || v.HuIndex == m+2 {
return
}
}
*mask |= mahjong.KANZHANG
}
//单钓将
//钓单张牌作将成和
func IsDanDiaoJiang(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.HuIndex == v.Jiang {
*mask |= mahjong.DANDIAOJIANG
}
}
//自摸
//自己抓进牌成胡牌
func IsZiMo(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.Zimo {
*mask |= mahjong.ZIMO
}
}
//二五八将
//胡牌时,将牌是二万、五万、八万。
func IsErWuBaJiang(v *mahjong.MahjongCount, mask, noMask *int64) {
if v.Jiang == 1 || v.Jiang == 4 || v.Jiang == 7 {
*mask |= mahjong.ERWUBAJIANG
}
}
转载自原文链接, 如需删除请联系管理员。
原文链接:麻将番型计算(二人麻将),转载请注明来源!