麻将番型计算(二人麻将)

您所在的位置:网站首页 二人麻将规则及玩法图片 麻将番型计算(二人麻将)

麻将番型计算(二人麻将)

2024-07-12 10:40:22| 来源: 网络整理| 查看: 265

上一篇文章序数了关于使用索引查表法进行麻将胡牌判定,这篇文章,我们将会对胡牌的番型进行计算,这里的番型指的是国标下的麻将番型,文章中的代码,暂时只考虑了二人麻将(只有万牌和字牌),想要通用,可以按着同样的方法进行扩展。

国标二人麻将番型表 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 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) 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 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 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 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 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 return } num := 0 //判断是否有三个风牌刻子 for _, m := range v.Array_ke { if m >= 27 && m return } *mask |= mahjong.XIAOSIXI *noMask |= mahjong.SANFENGKE | mahjong.YAOJIUKE } //小三元 //胡牌时,牌里有箭牌的两副刻子及将牌。不记番:箭刻、双箭刻 func IsXiaoSanYuan(v *mahjong.MahjongCount, mask, noMask *int64) { //将牌必须是箭牌 if v.Jiang return } //刻子中有两副是箭牌 num := 0 for _, m := range v.Array_ke { if m >= 31 { num++ } } if num //将牌必须是字牌 if v.Jiang return } bo := true kg := make([]byte, 0) kg = append(append(kg, v.Array_ke...), v.Array_gang...) //刻子、杠都要为字牌 for _, m := range kg { if m 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) ///将牌必须是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 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) if m == 0 || m == 8 { yjKe ++ } else if m > 30 { ziKe ++ } } if yjKe != 2 { return } if ziKe 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 if v.Array_shun[i] == v.Array_shun[i+1] { num++ } else if i == 1 { num = 0 } } if num //刻子数至少是三个 l := len(v.Array_ke) if l if v.Array_ke[i]+1 == v.Array_ke[i+1] { num++ } else if i == 1 { break } } if num //顺子至少三个 l := len(v.Array_shun) if l 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 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 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) sum := byte(0) //判断所有牌索引是否在5-8之间(至少是14张牌) for i := 5; i return } *mask |= mahjong.DAYUWU } //小于五 //胡牌时,牌型由序数牌1-4的顺子、刻子、将牌组成。 func IsXiaoYuWu(v *mahjong.MahjongCount, mask, noMask *int64) { sum := byte(0) for i := 0; i return } *mask |= mahjong.XIAOYUWU } //三风刻 //胡牌时,牌里有3个风刻 func IsSanFengKe(v *mahjong.MahjongCount, mask, noMask *int64) { //刻子必须有三个以上 if len(v.Array_ke) if 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 bo = true break } } for i := byte(27); i 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 *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) 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 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) for j := i + 1; j 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) 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) 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 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 } }


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭