羽毛球比赛规则:
1.21分制,3局2胜为佳。
2.每球得分制。
3.每回合中,取胜的一方加1分。
4.当双方均为20分时,领先对方2分的一方赢得该局比赛。
5.当双方均为29分时,先取得30分的一方赢得该局比赛。
6.一局比赛的获胜方在下一局率先发球。
该问题的IPO模式如下:
输入(I):选手A和B的能力值(用0至1的小数表示),模拟比赛的场次
处理(P):模拟比赛过程
输出(O):选手A和B分别赢得比赛的场次和概率
解决这种问题,首选自顶向下设计,即以一个总问题开始,将其拆分成若干个小问题,考虑每个小问题的解决方案,最终使总问题变得很容易解决。然后只需把所有小问题的解决方案组合起来,就可以得到一个程序。
自顶向下设计中最重要的是顶层设计。 以体育竞技分析为例,可以从问题的IPO描述开始。大多数程序都可以简单将IPO 描述直接用到程序结构设计中,体育竞技分析从用户得到模拟参数模拟比赛,最后输出结果。
步骤1:输入一些介绍信息
def main(): printinput()
步骤2:获得用户输入
def main(): printinput() abilityA,abilityB,n=getinput()
步骤3:使用abilityA、abilityB模拟n场比赛
def main(): printinput() abilityA,abilityB,n=getinput() winsA,winsB=simNGames(n,abilityA,abilityB)
步骤4:输出结果
def main(): printinput() abilityA,abilityB,n=getinput() winsA,winsB=simNGames(n,abilityA,abilityB) printoutcome(winsA,winsB)
由此我们将总问题分成了4个独立的函数:printinput()、getinput()、simNGames()、printoutcome()
printinput()函数中我们输入程序的介绍
def printinput(): print("这个程序模拟两个选手A和B的羽毛球比赛") print("该程序需要选手A和B的能力值(以0到1之间的小数表示)")
getinput()函数中我们获得选手A和B的能力值和模拟比赛的场次
def getinput(): a=eval(input("请输入选手A的能力值(0-1):")) b=eval(input("请输入选手B的能力值(0-1):")) n=eval(input("模拟比赛的场次:"))
simNGames()函数是整个程序最为关键的部分,它能模拟n场比赛的胜负关系并记录选手赢得比赛的场次
def simNGames(n,abilityA,abilityB): winsA,winsB=0,0 for i in range(n): scoreA,scoreB=simOneGame(abilityA,abilityB) if scoreA>scoreB: winsA+=1 else: winsB+=1 return winsA,winsB
在simNGames()函数中,我们可以看到其中又新添了一个函数simOneGame(),它是用来模拟一场比赛的胜负
def simOneGame(abilityA,abilityB): scoreA,scoreB=0,0 serving="A" #先将发球权给A while not gameOver(scoreA,scoreB,abilityA,abilityB): if serving=="A": if random()<abilityA: #采用random随机数判断A或B赢 scoreA+=1 #A赢加1分 else: scoreB+=1 #B赢加1分 serving="B" #B赢则将发球权给B else: if random()<abilityB: scoreB+=1 else: scoreA+=1 serving="B" return scoreA,scoreB
而在simOneGame()函数中,又进一步设计了gameOver()函数,它是用来判断一场比赛是否结束
def gameOver(scoreA,scoreB,abilityA,abilityB): if (scoreA==21 and scoreB<20) or (scoreA<20 and scoreB==21): return True #21分制 if scoreA==30 or scoreB==30: return True #谁先达到30分谁赢 if scoreA==20 and scoreB==20: #A和B都为20分的情况 againA,againB=0,0 serving="A" #同simOneGame()函数相同 if serving=="A": if random()<abilityA: againA+=1 else: againB+=1 serving="B" else: if random()<abilityB: againB+=1 else: againA+=1 serving="B" return againA==againB+2 or againB==againA+2 #谁先领先对方2分谁赢 else: return False
用printoutcome()函数打印比赛的结果
def printoutcome(winsA,winsB): n=winsA+winsB print("竞技分析开始,共模拟{}场比赛".format(n)) print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA,winsA/n)) print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB,winsB/n))
将所有的函数组装起来,就能得到解决该问题的程序:
from random import random def main(): printinput() abilityA,abilityB,n=getinput() winsA,winsB=simNGames(n,abilityA,abilityB) printoutcome(winsA,winsB) def printinput(): print("这个程序模拟两个选手A和B的羽毛球比赛") print("该程序需要选手A和B的能力值(以0到1之间的小数表示)") def getinput(): a=eval(input("请输入选手A的能力值(0-1):")) b=eval(input("请输入选手B的能力值(0-1):")) n=eval(input("模拟比赛的场次:")) return a,b,n def simNGames(n,abilityA,abilityB): winsA,winsB=0,0 for i in range(n): scoreA,scoreB=simOneGame(abilityA,abilityB) if scoreA>scoreB: winsA+=1 else: winsB+=1 return winsA,winsB def simOneGame(abilityA,abilityB): scoreA,scoreB=0,0 serving="A" while not gameOver(scoreA,scoreB,abilityA,abilityB): if serving=="A": if random()<abilityA: scoreA+=1 else: scoreB+=1 serving="B" else: if random()<abilityB: scoreB+=1 else: scoreA+=1 serving="B" return scoreA,scoreB def gameOver(scoreA,scoreB,abilityA,abilityB): if (scoreA==21 and scoreB<20) or (scoreA<20 and scoreB==21): return True if scoreA==30 or scoreB==30: return True if scoreA==20 and scoreB==20: againA,againB=0,0 serving="A" if serving=="A": if random()<abilityA: againA+=1 else: againB+=1 serving="B" else: if random()<abilityB: againB+=1 else: againA+=1 serving="B" return againA==againB+2 or againB==againA+2 else: return False def printoutcome(winsA,winsB): n=winsA+winsB print("竞技分析开始,共模拟{}场比赛".format(n)) print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA,winsA/n)) print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB,winsB/n)) main()
运行结果如下: