基本情况
- 条、筒、万共108张
- 随机洗牌,每局开始,洗牌后牌序固定
- 按序摸牌、打牌、碰牌和胡牌
- 四方分别代号为0、1、2、3
1 洗牌
//洗牌
func (ms *mainStruct) xiPai() {
//1 108个数随机生成
rand.Seed(time.Now().UnixNano())
ms.paiList = rand.Perm(108)
}
2 初始发牌
//发牌
func (ms *mainStruct) faPai() {
for i := 0; i < 4*13+1; i++ {
switch i % 4 {
case 0:
ms.shouPai[0] = append(ms.shouPai[0], ms.paiList[i])
case 1:
ms.shouPai[1] = append(ms.shouPai[1], ms.paiList[i])
case 2:
ms.shouPai[2] = append(ms.shouPai[2], ms.paiList[i])
case 3:
ms.shouPai[3] = append(ms.shouPai[3], ms.paiList[i])
}
}
}
3 理牌
//理牌
func (ms *mainStruct) liPai(i int) {
sort.Ints(ms.shouPai[i])
}
4 显示手牌
//显示手牌 n为第几位玩家 v为传进来的牌的序号 传的是一个值
func (ms *mainStruct) showPai(n, v int) {
switch v / 36 {
case 0:
ms.paiClass[n]["条"] = append(ms.paiClass[n]["条"], mahjongStore[v])
s := fmt.Sprintf("%d条", mahjongStore[v])
ms.paiDis[n] = append(ms.paiDis[n], s)
case 1:
ms.paiClass[n]["筒"] = append(ms.paiClass[n]["筒"], mahjongStore[v])
s := fmt.Sprintf("%d筒", mahjongStore[v])
ms.paiDis[n] = append(ms.paiDis[n], s)
case 2:
ms.paiClass[n]["万"] = append(ms.paiClass[n]["万"], mahjongStore[v])
s := fmt.Sprintf("%d万", mahjongStore[v])
ms.paiDis[n] = append(ms.paiDis[n], s)
}
}
5 下一轮摸牌
func (ms *mainStruct) nextMoPai(n int) {
var next = (n + 1) % 4
//以下为提示性信息
var s string
t := (ms.paiList[count] % 36) / 4
t1 := ms.paiList[count] / 36
switch t1 {
case 0:
s = fmt.Sprintf("%d条", t+1)
case 1:
s = fmt.Sprintf("%d筒", t+1)
case 2:
s = fmt.Sprintf("%d万", t+1)
}
//if count == 64 {
//测试自摸 输入值:2 11 14 2 1 11 4 5 2 11 1 1 1
// count = 60
//}
fmt.Printf("%d号摸牌 :%s\n", next, s)
//加上摸到手的牌
ms.shouPai[next] = append(ms.shouPai[next], ms.paiList[count])
count++
//理牌
ms.liPai(next)
//fmt.Println(next, ms.shouPai[next])
//更新牌分类 paiClass、牌显示paiDis
ms.qingKongData(next)
fmt.Printf("%d号当前的手牌:%v\n", next, ms.paiDis[next]) //打印显示的手牌
ms.moPai(next)
}
6 屁胡
func piHu(vDelete int, shou intSlice) bool {
//0 定义一个临时结构体,用来做判断
msDemo := temporaryStruct{
shou: shou, // intSlice 手牌,是洗牌后paiList的序号
}
msDemo.class = make(map[string]intSlice)
//1 把别人打出来的牌,加到自己手上
msDemo.shou = append(msDemo.shou, vDelete)
//2 理牌
sort.Ints(msDemo.shou)
//3 根据手牌,生成class和dis
//msDemo.dis
//msDemo.class
//msDemo.shou
//msDemo.cards
for _, v := range msDemo.shou {
switch v / 36 {
case 0:
msDemo.class["条"] = append(msDemo.class["条"], mahjongStore[v])
s := fmt.Sprintf("%d条", mahjongStore[v])
msDemo.dis = append(msDemo.dis, s)
case 1:
msDemo.class["筒"] = append(msDemo.class["筒"], mahjongStore[v])
s := fmt.Sprintf("%d筒", mahjongStore[v])
msDemo.dis = append(msDemo.dis, s)
case 2:
msDemo.class["万"] = append(msDemo.class["万"], mahjongStore[v])
s := fmt.Sprintf("%d万", mahjongStore[v])
msDemo.dis = append(msDemo.dis, s)
}
}
//4 判断是否胡牌
ok := AnalyzeCardsSimple(msDemo.class)
if ok == true {
return true
} else {
return false
}
}
7 胡牌判断
func AnalyzeCardsSimple(class Map) bool {
//有个七对,特殊判断一下就可以了
if len(class) == 14 {
// todo 计算是否有七个对子
fmt.Println("---------------七对,特殊判断,未实现---------------")
}
for _, tempCards := range class { //first:"W:[1 1 2 2 3 3]" second:"T:[3 3 6 6]" last:"S:[4 4 5 5]"
//cardsNum 每张牌的数量 用map实现
cardsNum := make([]int, 10)
for _, card := range tempCards {
cardsNum[card]++
}
isHu := SplitCards(cardsNum, false) //传进去的是一个类型中各个牌的数量
//fmt.Println(isHu)
if !isHu {
return false
}
}
fmt.Println(true)
return true
}
func SplitCards(cardsNum []int, hasPair bool) bool {
cnt := 0
for _, num := range cardsNum {
if num > 0 {
break
}
cnt++
}
//判断没有牌为可以胡牌
if len(cardsNum) == cnt { //len(cardsNum)恒为10
return true
}
for i := 0; i < len(cardsNum); i++ {
switch cardsNum[i] {
case 4:
fallthrough //强制执行后面的case代码
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 produceMahjong() {
for j := 0; j < 3; j++ {
for i := 0; i < 36; i++ {
mahjongStore[j*36+i] = (i / 4) + 1
}
}
}
9 逻辑实现
func (ms *mainStruct) moPai(n int) {
if count == 108 {
fmt.Println("流局")
return
}
//从53张开始打牌,0号位(庄家)初始多一张牌
//1 判断胡牌了吗
ok := AnalyzeCardsSimple(ms.paiClass[n])
if ok == true {
fmt.Println(n, ":我自摸了")
os.Exit(0)
} //else {
// fmt.Println(n, "与我无瓜!")
//}
//2 庄家出牌 得到出牌信息:s
var (
s int
vDelete int
)
fmt.Printf("%d号打牌 :(第几张):", n)
_, _ = fmt.Scan(&s) // 2:9条
//2.1 获得对应字符串 ["条"][9]
var sMap = make(map[string]int)
sMap, vDelete = ms.getDeleteData(n, s, sMap)
//2.2 删除打出去的那张
//2.2.1 在手牌库里删除了
ms.shouPai[n] = append(ms.shouPai[n][0:s-1], ms.shouPai[n][s:]...) //在手牌库里删除了
//2.2.2 清空当前的map并重新统计
ms.qingKongData(n)
fmt.Printf("%d号当前的手牌:%v\n", n, ms.paiDis[n]) //打印显示的手牌
//3 判断是否有人碰,或者胡牌
//3.1 是否有人胡牌
for i := 0; i < 4; i++ {
if i == n {
continue
}
//fmt.Println("**********", i, "**************")
var a intSlice
for _, v := range ms.shouPai[i] {
a = append(a, v)
}
ok = piHu(vDelete, a)
if ok == true {
fmt.Println(i, ":我胡了")
os.Exit(0)
}
}
//3.2 是否有人碰牌
//3.1.1 判断是否有人有两个或以上的此牌,若有,则选择碰不碰
for i := 0; i < 4; i++ {
if i == n {
continue
}
ms.paiTypeCount(i) //这里出现的错误!!!!!!!!!!!!!
//fmt.Println("-----------------", i, "------------------------")
for k, v := range sMap {
//fmt.Println(k, v)
if ms.cardsNum[i][k][v] >= 2 {
fmt.Println(i, ":碰?\n 请选择:\n 1:碰\n 2:不碰")
var t int
_, _ = fmt.Scan(&t)
switch t {
case 1:
//加上这张牌
ms.shouPai[i] = append(ms.shouPai[i], vDelete)
//理牌
ms.liPai(i)
//fmt.Printf("%d号当前的手牌:%v\n",i, ms.shouPai[i])
//更新牌分类 paiClass、牌显示showPai
ms.qingKongData(i)
//显示手牌
fmt.Printf("%d号当前的手牌:%v\n", i, ms.paiDis[i])
//判断是否胡了,继续向下,出牌,是否碰,谁碰谁负责
ms.moPai(i)
case 2:
//不碰就下一个人摸牌 (n+1)%4
ms.nextMoPai(n)
}
}
}
}
//4 没人碰的了就直接下一个人摸牌
ms.nextMoPai(n)
}
10 运行
// RunDemo 运行
func RunDemo() (err error) {
produceMahjong()
//fmt.Println(mahjongStore)
var ms mainStruct
for i := 0; i < 4; i++ {
ms.paiClass[i] = make(Map)
}
ms.xiPai()
//fmt.Println(ms.paiList)
ms.faPai()
for i := 0; i < 4; i++ {
fmt.Printf("---------------%d号位置----------------\n", i)
ms.liPai(i)
//fmt.Println(ms.shouPai[i])
for _, v := range ms.shouPai[i] {
ms.showPai(i, v)
}
//fmt.Println(ms.paiClass[i])
fmt.Println(ms.paiDis[i])
}
//sMap := map[string]int{"条": mahjongStore[35]}
//ms.piHu(0, 35, sMap)
ms.moPai(0)
//fmt.Println(ms.shouPai[0])
return err
}
运行结果
---------------0号位置----------------
[1条 7条 8条 1筒 5筒 6筒 7筒 8筒 9筒 1万 1万 6万 7万 9万]
---------------1号位置----------------
[1条 3条 9条 3筒 5筒 6筒 7筒 9筒 9筒 1万 5万 7万 7万]
---------------2号位置----------------
[1条 2条 2条 3条 4条 6条 9条 1筒 6筒 8筒 2万 2万 9万]
---------------3号位置----------------
[2条 3条 3条 4条 4条 6条 6条 7条 8筒 3万 4万 6万 9万]
0号打牌 :(第几张):1
0号出牌 :1条
0号当前的手牌:[7条 8条 1筒 5筒 6筒 7筒 8筒 9筒 1万 1万 6万 7万 9万]
1号摸牌 :5条
1号当前的手牌:[1条 3条 5条 9条 3筒 5筒 6筒 7筒 9筒 9筒 1万 5万 7万 7万]
1号打牌 :(第几张):4
1号出牌 :9条
1号当前的手牌:[1条 3条 5条 3筒 5筒 6筒 7筒 9筒 9筒 1万 5万 7万 7万]
2号摸牌 :2筒
2号当前的手牌:[1条 2条 2条 3条 4条 6条 9条 1筒 2筒 6筒 8筒 2万 2万 9万]
2号打牌 :(第几张):14
2号出牌 :9万
2号当前的手牌:[1条 2条 2条 3条 4条 6条 9条 1筒 2筒 6筒 8筒 2万 2万]
3号摸牌 :5万
3号当前的手牌:[2条 3条 3条 4条 4条 6条 6条 7条 8筒 3万 4万 5万 6万 9万]
3号打牌 :(第几张):