题目:

  1. 有四个选手, A1和A2为一个队, B1和B2为另一个队. A1首先发球(启动球), 然后B1, A2, B2将最后发球. 每一轮每个选手发2个球.
  2. 选手不改变他们的位置.
  3. 比赛期间, 双方选手必须轮流发球,并且在同一个队伍的两个选手可以竞争发球.
  4. 当轮到某个选手时, 他/她可以调用一个叫做shot(rate) 的随机函数来模拟比赛,在给定概率rate以内,该函数返回 “in”, 否则返回”out”. 例如 rate=85%, 则球在界内的概率为85%, 出界的概率为15%.
  5. 如果shot函数返回”in”, 对方选手必须调用shot函数把球打回.
  6. 如果shot函数返回”out”, 对方选手赢得1分,随后重新发球.
  7. 当每个选手发完2个球后比赛终止.分数多的一方赢得比赛.分数一样多,比赛为平局.
  8. 每个选手作为一个线程实现.

实现思路:


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    inttrail 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("比赛开始...")// 初始化球的idfor 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)}}

结果:

Golang -- goroutine实例(乒乓球双打比赛)相关推荐

  1. 羽毛球双打比赛中两位运动员谁来发球以及如何换位?

    例如: A和B对C和D的双打比赛. A和B赢了挑边并选择了发球.A发球C接发球.A为首先发球员,而C则为首先接发球员. 只有发球方在得分时发球方两位运动员才交换位置,由原发球员继续发球.除此以外,运动 ...

  2. golang goroutine实现_Go goroutine理解

    Go语言最大的特色就是从语言层面支持并发(Goroutine),Goroutine是Go中最基本的执行单元.事实上每一个Go程序至少有一个Goroutine:主Goroutine.当程序启动时,它会自 ...

  3. golang goroutine实现_golang技术随笔(二)理解goroutine

    进程.线程和协程 要理解甚么是goroutine,我们先来看看进程.线程和协程它们之间的区分,这能帮助我们更好的理解goroutine. 进程:分配完全独立的地址空间,具有自己独立的堆和栈,既不同享堆 ...

  4. golang goroutine协程运行机制及使用详解

    Go(又称Golang)是Google开发的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语言.Go于2009年正式推出,国内各大互联网公司都有使用,尤其是七牛云,基本都是golang写的, ...

  5. golang goroutine实现_golang中的Mutex设计原理详解(一)

    Mutex系列是根据我对晁岳攀老师的<Go 并发编程实战课>的吸收和理解整理而成,如有偏差,欢迎指正~ 目标 本系列除了希望彻底学习和了解 golang 中 sync.Mutex 的原理和 ...

  6. python乒乓球比赛甲乙_用python进行对乒乓球的比赛分析,并且将该程序进行封装...

    2.单打的淘汰赛采用七局四胜制,双打淘汰赛和团体赛采用五局三胜制. 重点: 思维方式:自顶向下即将一个复杂问题分解成几个问题,再细分成一个个具体的小问题,从而来解决复杂问题.自底向上为自顶向下的逆过程 ...

  7. golang goroutine实现_Go语言潜力有目共睹,但它的Goroutine机制底层原理你了解吗?...

    来源 | 后端技术指南针(ID:gh_ed1e2b37dcb6) Go语言的巨大潜力有目共睹,今天我们来学习Go语言的Goroutine机制,这也可能是Go语言最为吸引人的特性了,理解它对于掌握Go语 ...

  8. VSCode配置Golang单元测试实例

    目录 前言 正文 一.导入testing工具包 二.单元测试文件命名规范 三.单元测试方法命名规范 四.执行单元测试 结尾 前言 说到代码的健壮性,单元测试是少不了的,基本上所有语言都有自己的单元测试 ...

  9. Ray实例-乒乓球训练学习

    在本例中(代码在文末),我们将使用OpenAI Gym训练一个非常简单的神经网络来打乒乓球.这个应用程序改编自Andrej Karpathy的代码,只做了很少的修改(请参阅附带的博客文章). 首先安装 ...

最新文章

  1. Vue+Spring boot前后端响应流程总结
  2. 【Eclipse 字符集】Eclipse在哪里设置字符集?三个位置,分别控制不同的范围
  3. C++ 面向对象(二)—— 操作符重载
  4. SpringMVC(一):环境搭建
  5. matlab编程范例_编程范例到底是什么?
  6. Exchange 2010 RPC配置静态RPC端口客户端访问、通讯簿服务和公用文件夹连接
  7. 个人Web自动化测试学习点总结
  8. 「首席架构师推荐」统计软件一览表
  9. 抓包分析数据(Charles以及HttpCanary)
  10. 三菱Q系列PLC大型程序Q01U伺服12轴
  11. tomcat的access日志配置
  12. 2022深圳中小学生学位补贴申报形式及流程
  13. Linux:Ubuntu系统解决不能上网问题
  14. 统计学习方法第一章思维导图
  15. 当下的力量(解读版)
  16. pluck()取表中一列中所有值组成数组
  17. FPGA零基础学习:数字通信中的电压标准
  18. BZOJ1006神奇的国度
  19. Fate原理(面试必备)
  20. Nacos 极简入门

热门文章

  1. spring中aop拦截自定义注解不生效
  2. 弱电机房动环监控系统
  3. 无知造就对阿法狗(AlphaGo)的恐惧与喧闹
  4. 【微信机器人】可做自动回复,自动接收转账,群聊机器人。
  5. D55XT80-ASEMI大功率三相整流桥55A 800V
  6. golang 代码检测工具之goimports
  7. Qcom android L ro.sf.lcd_density属性修改
  8. 基于物联网技术的智能电力抄表服务平台
  9. ICT 2017 | 以色列驻华大使馆商务官欧美雅: 以色列人一直都在追求创新
  10. 【NLP数据训练】文本标注工具推荐