[Go]报数问题

有这样一个报数问题,
有10个人(goroutine)一起报数 有一个裁判随机选一个地雷数 随机选数用rand就行
这10个人讲选完的数字告诉裁判用channel传递 然后如果这个选数字的人正好踩雷了 则这个人出局
输出m局后还有几个人存活

要求是不能用要求不许用全局变量 所有的数据用channel
最开始把题意没看清楚,写了一个取巧的方法
每一轮生成一个随机数传给每个选手,每个选手每一轮生成一个随机数,然后自己判断自己是否被淘汰,如果被淘汰就通知裁判,而裁判此时减少一个总人数.

const (
	MaxNum = 10 //随机数最大数
	M      = 10 //游戏轮数
	N      = 10 //玩家数
)

//运动员
func person(id int, Survive []bool, key int, Dead chan bool, wg *sync.WaitGroup) {
	defer wg.Done()
	num := RandNum()
	if num == key { //判断出自己被淘汰
		Survive[id] = true
		Dead <- true
	}
}

//裁判--如果有人淘汰减少总人数
func center(sum *int, Dead chan bool, over chan bool) {
	for {
		select {
		case <-Dead:
			*sum--
		case <-over:
			return
		}
	}
}

func main() {
	wg := sync.WaitGroup{}
	Dead := make(chan bool) //告知裁判有人淘汰
	over := make(chan bool)
	sum := N                    //总人数
	Survive := make([]bool, 15) //不同编号的人是否存活的标志(默认false存活)
	go center(&sum, Dead, over) //开启裁判
	for i := 0; i < M; i++ {
		key := RandNum() //每轮一个随机数传进去让选手自己判断
		for j := 1; j <= N; j++ {
			if Survive[j] == true {
				continue
			}
			wg.Add(1)
			go person(j, Survive, key, Dead, &wg)
		}
		wg.Wait() //等待上一轮所有人完成
	}
	over <- true //结束裁判
	fmt.Println(N, "个人,", M, "轮游戏后,", "剩余", sum, "个人")
}

func RandNum() int {
	time.Sleep(10 * time.Nanosecond)
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(MaxNum)
}

然后看了学长发的方法,感觉真的很巧妙,对channel的理解又加深了一些
总结了下
裁判负责生成随机数,接受玩家的数字,判断玩家是否被淘汰,给玩家返回是否被淘汰的信息.
玩家负责生成随机数,给裁判传随机数,接受是否继续游戏的信息.
由此就可以使用传递channel的channel来为裁判区分不同玩家

const (
	NumSize  = 10
	M        = 5  //M轮游戏
	N        = 10 //N个人
	GameOver = 0
	GameNext = 1
)

func main() {
	var ReadyGame, StartGame = sync.WaitGroup{}, sync.WaitGroup{}
	ReadyGame.Add(N)             //N个人准备
	var ch = make(chan chan int) //传送手机的chan
	for i := 0; i < N; i++ {     //N个人M轮报数
		go func() {
			phone := make(chan int)
			for j := 0; j < M; j++ {
				ReadyGame.Done()                           //准备完成
				ch <- phone                                //先传手机过去
				phone <- RandNum()                         //再往手机里传数据
				if result := <-phone; result == GameOver { //判断自己是否被淘汰
					break
				}
				StartGame.Wait() //等待新一轮
			}
		}()
	}
	StartGame.Add(1)         //让所有人等待这一轮结束
	cnt := N                 // 确定当前剩余人数
	for i := 0; i < M; i++ { //裁判
		key := RandNum()
		tempCnt := cnt
		for j := 0; j < tempCnt; j++ {
			phone := <-ch
			if result := <-phone; result == key {
				phone <- GameOver
				cnt--
			} else {
				phone <- GameNext
			}
		}
		if i == M-1 { //最后一轮完了就不用再准备下一轮的东西了
			break
		}
		ReadyGame.Add(cnt) //准备人数
		StartGame.Done()   //开始下一轮
		ReadyGame.Wait()   //等待所有人准备完成
		StartGame.Add(1)   //让所有人完成后等待
	}
	fmt.Println(N, "个人,", M, "轮游戏后,", "剩余", cnt, "个人")
}

// RandNum 生成随机数
func RandNum() int {
	time.Sleep(15 * time.Nanosecond)
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(NumSize)
}

我对于并发之间的通信还是需要加强,继续努力.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值