Golang -- goroutine实例(乒乓球双打比赛)
来源:互联网 发布:oracle数据库漏洞 编辑:程序博客网 时间:2024/04/30 15:14
题目:
- 有四个选手, A1和A2为一个队, B1和B2为另一个队. A1首先发球(启动球), 然后B1, A2, B2将最后发球. 每一轮每个选手发2个球.
- 选手不改变他们的位置.
- 比赛期间, 双方选手必须轮流发球,并且在同一个队伍的两个选手可以竞争发球.
- 当轮到某个选手时, 他/她可以调用一个叫做shot(rate) 的随机函数来模拟比赛,在给定概率rate以内,该函数返回 “in”, 否则返回”out”. 例如 rate=85%, 则球在界内的概率为85%, 出界的概率为15%.
- 如果shot函数返回”in”, 对方选手必须调用shot函数把球打回.
- 如果shot函数返回”out”, 对方选手赢得1分,随后重新发球.
- 当每个选手发完2个球后比赛终止.分数多的一方赢得比赛.分数一样多,比赛为平局.
- 每个选手作为一个线程实现.
实现思路:
serve: 是指发球的goroutine.
serveMetux: 发球锁。
playerA: 是指A队伍抢到球的goroutine.
playerB: 是指B队伍抢到球的goroutine.
catch_chanel_A : 给A队伍的球的通道。
catch_chanel_B : 给B队伍的球的通道。
大致步骤:
1. serve 先加锁,后发球(将TableTennis放入通道中,如catch_chanel_A ),然后重复上锁(serveMetux)阻塞自身。
2. playerA 如果catch_chanel_A 没有球,阻塞自身。如果有球,则从通道中拿到球,shot(rate) 后返回in, 记录信息后,则将球放入给B的通道catch_chanel_B中。
3. playerB 如果catch_chanel_B 没有球,阻塞自身。如果有球,则从通道中拿到球,shot(rate) 后返回in, 记录信息后,则将球放入给B的通道catch_chanel_A中。如果shot(rate)返回out, 则解除锁(serveMetux),此时serve唤醒,开始下一次发球。
实现代码:
package mainimport ( "fmt" "sync" "math/rand" "container/ring" "strings" "time")var ( wg sync.WaitGroup // 用于goroutine计数 times = 2 // 每个选手发球次数 nums = 4 // 多少个选手 serveTotals = nums * times // 总发球次数 score_balls_A = make([]TableTennis, 0, serveTotals) // A的得分球 score_balls_B = make([]TableTennis, 0, serveTotals) // B的得分球 turn = ring.New(4) // 发球顺序 serveMetux sync.Mutex // 发球锁 catch_chanel_B = make(chan TableTennis, 0) // B队伍接球的通道 catch_chanel_A = make(chan TableTennis, 0) // A队伍接球的通道 balls_ids = make(chan int, serveTotals) // 球的id)// 乒乓球type TableTennis struct { id int trail string // 球的轨迹}func serve() { defer wg.Done() // 初始化发球顺序 turn.Value = "A1" turn = turn.Next() turn.Value = "B1" turn = turn.Next() turn.Value = "A2" turn = turn.Next() turn.Value = "B2" // 开始发球 for i := 0; i < times; i++ { for j := 0; j < nums; j++ { serveMetux.Lock() // 解锁时发下一个球 turn = turn.Next() name := turn.Value.(string) t := TableTennis{<-balls_ids, name + "-in"} if name[0] == 'A' { catch_chanel_B <- t } else { catch_chanel_A <- t } } } time.Sleep(time.Second) // 等待player goroutine对catch_chanel的使用 close(catch_chanel_A) close(catch_chanel_B)}// A队选手func playerA(name string, rate int) { defer wg.Done() // 延迟递减计数 for t := range catch_chanel_A { // 2. 将球击打出去 rest := shot(rate) // 3. 记录球的轨迹 t.trail += "-" + name + "-" + rest // 球出界 if strings.Compare("out", rest) == 0 { // 对方得分 score_balls_B = append(score_balls_B, t) fmt.Println(t) serveMetux.Unlock() continue } // 4. 对面队伍准备接球 catch_chanel_B <- t }}// B队选手func playerB(name string, rate int) { defer wg.Done() // 延迟递减计数 for t := range catch_chanel_B { // 2. 将球击打出去 rest := shot(rate) // 3. 记录球的轨迹 t.trail += "-" + name + "-" + rest // 球出界 if strings.Compare("out", rest) == 0 { // 对方得分 score_balls_A = append(score_balls_A, t) fmt.Println(t) serveMetux.Unlock() continue } // 4. 对面队伍准备接球 catch_chanel_A <- t }}// 击球func shot(rate int) string { if rand.Intn(100) < rate { return "in" } else { return "out" }}func main() { fmt.Println("比赛开始...") // 初始化球的id for i := 0; i < serveTotals; i++ { balls_ids <- i + 1 } // 初始化发球顺序 wg.Add(nums + 1) // 累加计数 go serve() //time.Sleep(time.Second) go playerA("A1", 45) go playerA("A2", 60) go playerB("B1", 50) go playerB("B2", 90) wg.Wait() fmt.Println("比赛结束.") fmt.Printf("A : B = (%d, %d)\n", len(score_balls_A), len(score_balls_B)) for _, t := range score_balls_A { fmt.Println(t) } fmt.Println() for _, t := range score_balls_B { fmt.Println(t) }}
结果:
阅读全文
0 0
- Golang -- goroutine实例(乒乓球双打比赛)
- 乒乓球比赛
- 乒乓球比赛
- 乒乓球比赛
- 乒乓球比赛
- C语言——实例022 乒乓球比赛名单
- 乒乓球比赛日程
- Golang goroutine and channel
- GoLang学习 -- goroutine使用指南
- 【GOLANG】goroutine原理
- golang-并发编程goroutine
- Golang之chan/goroutine
- Golang获取goroutine ID
- golang技术,理解goroutine
- Golang -- goroutine (一)
- golang goroutine顺序输出
- 乒乓球单打比赛程序模拟
- 猴子吃桃&乒乓球比赛
- 复习-高等数学的求导
- 哈希表
- 【IO流】FileInputStream,FileOutputStream读写文件
- js的运算符
- 【opencv3.0】鱼眼图像畸变校正——标定校正
- Golang -- goroutine实例(乒乓球双打比赛)
- 链栈初始化、进栈、出栈、判空、遍历、求长、求顶、清栈、毁栈
- Magic Number LCA求路径点集的并
- Flask在linux系统下环境的离线搭建及简单实用教程
- 树莓派下安装Django环境
- shell变量
- Centos下安装mysql
- 代码编写技巧
- 软件工程-系统开发方法-jackson方法