GO开发之路 麻将mahjong的基本实现

基本情况

  1. 条、筒、万共108张
  2. 随机洗牌,每局开始,洗牌后牌序固定
  3. 按序摸牌、打牌、碰牌和胡牌
  4. 四方分别代号为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号位置----------------
[17815678911679]
---------------1号位置----------------
[1393567991577]
---------------2号位置----------------
[1223469168229]
---------------3号位置----------------
[2334466783469]
0号打牌     :(第几张):1
0号出牌     :10号当前的手牌:[7815678911679]
1号摸牌     :51号当前的手牌:[13593567991577]
1号打牌     :(第几张):4
1号出牌     :91号当前的手牌:[1353567991577]
2号摸牌     :22号当前的手牌:[12234691268229]
2号打牌     :(第几张):14
2号出牌     :92号当前的手牌:[1223469126822]
3号摸牌     :53号当前的手牌:[23344667834569]
3号打牌     :(第几张):

源代码链接:源代码链接

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值