有这样一个报数问题,
有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)
}
我对于并发之间的通信还是需要加强,继续努力.