一个解决复杂问题行之有效的方法被称作自顶向下的设计方法,其基本思想是
以一个总问题开始,试图把它表达为很多小问题组成的解决方案。再用同样的技术
依次攻破每个小问题,最终问题变得非常小,以至于可以很容易解决。然后只需把
所有的碎片组合起来,就可以得到一个程序。
1.顶层设计
自顶向下设计中最重要的是顶层设计。以体育竞技分析为例,可以从问题的IPO描述开始。大多数程序都可以将IPO描述直接用到程序结构设计中,体育竞技分析从用户处得到模拟参数,最后输出结果。下面是一个基础设计的4个步骤。
步骤1:打印程序的介绍性信息。
步骤2:获得程序运行需要的参数,即 probA、probB、n。
步骤3:利用球员A和B的能力值probA和 probB,模拟n次比赛。步骤4:输出球员A和B获胜比赛的场次及概率。
2.第n层设计
经过顶层设计,main()函数成为体育竞技分析的顶层结构,上述设计可以表示为图8.1,其中每层按照从左至右的顺序执行,每个函数用一个矩形表示,连接两个矩形的线表示上面函数对下面函数的调用关系。在信息流方面,箭头和注释表示函数之间的输入和输出。
代码:
from random import random
def printIntro():
print("这个程序模拟两个选手A和B的某种竞技比赛")
print("程序运行需要A和B的能力值(以0到1之间的小数表示)")
def getIntputs():
a = eval(input("请输入A的能力值(0-1):"))
b = eval(input("请输入B的能力值(0-1):"))
n = eval(input("模拟比赛的场次:"))
return a, b, n
def simNGames(n, probA, probB):
winsA, winsB = 0, 0
for i in range(n):
scoreA, scoreB = simOneGame(probA, probB)
if scoreA > scoreB:
winsA += 1
else:
winsB += 1
return winsA, winsB
def gameOver(a, b):
return a == 15 or b == 15
def simOneGame(probA, probB):
scoreA, scoreB = 0, 0
serving = "A"
while not gameOver(scoreA, scoreB):
if serving == "A":
if random() < probA:
scoreA += 1
else:
serving = "B"
else:
if random() < probB:
scoreB += 1
else:
serving = "A"
return scoreA, scoreB
def printSummary(winsA, winsB):
n = winsA + winsB
print("竞技分析开始,共模拟{}场比赛".format(n))
print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA, winsA / n))
print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB, winsB / n))
def main():
printIntro()
probA, probB, n = getIntputs()
winsA, winsB = simNGames(n, probA, probB)
printSummary(winsA, winsB)
main()
运行结果: