大家是不是都玩过保龄球?虽然水平很烂,但我是保龄球爱好者。今天这一题是。首先讲一下保龄球的规则:
保龄球的一局称为一个frame,一共有10局。
第1到9局,一般每局可以投掷(roll)两次,但是有一个例外,就是第一次投掷就全中 - 这种情况称为strike,打出strike后这一局就算结束,不再投掷第二次。还有一种情况是补中,即第一次投掷没有全中,但第二次投掷把剩下的球都打倒了 - 这种情况称为spare。
第10局,如果第一次投掷strike,则再奖励(bonus)两次投掷。如果经历两次投掷打出spare,则再奖励一次投掷。否则就是两次投掷结束。
计分时,如果这一局两次投掷也未全中,直接记分如“43”。如果打出strike,记为“X”,且该局的分数为本来的10分,加上下两次投掷的分数。如果打出spare,记为“4/”(假设第一次投掷击中4个球),且该局的分数为10分加上下一次投掷的分数。
比如,“X X 9/ 80 X X 90 8/ 7/ 44”表示的总分为:
Frame#1: 10+10+9=29
Frame#2: 10+10=20
Frame#3: 10+8=18
Frame#4: 8+0=8
Frame#5: 10+10+9=29
Frame#6: 10+9+0=19
Frame#7: 9+0=9
Frame#8: 10+7=17
Frame#9: 10+4=14
Frame#10: 4+4=8
Total: 171
而一次完美的成绩“X X X X X X X X X XXX”则共计300分!
下面问题来了:输入一个保龄球记分的字符串,如何计算出总成绩呢?
分析:
每一局的比分有4种情况:
1. 第1-9局,未全中
2. 第10局,未全中
3. 第1-9局,有strike/spare
4. 第10局,有strike/spare
对于情况#1&2,直接加上分数即可。
对于情况#3,strike要加上下两次roll的分数,spare要加上下一次roll的分数。以strike为例,可能的分数组合有(标记了要算分的部分):
X 43, X 4/, X X 43, X X 4/, X X X
而spare的可能分数组合有:
4/ 43, 4/ 4/, 4/ X
可以看到,在算分时用到的都是相邻的3个字符,届时只要将X和4/都替换为10即可。
对于情况#4,可能的分数组合有:
X43, X4/, XX4, XXX, 4/4, 4/X
可以看到它与#3其实是一样的,而且本身已经是相邻无空格的3个字符了。
实现要点:
1. 在遍历列表时,如果同时还要操作index,可以使用enumerate函数:
enumerate(列表)
enumerate(列表, 索引起始值)
2. 取列表和字符串的片段:
lst[1:]表示从lst[1]到列表的最后一个元素
string[:3]表示前3个字符
3. “将X和4/都替换为10”可用re模块的高级替换方法sub。
借用:
import redef bowling_score(frames): frames = frames.split() score = 0 for index, frame in enumerate(frames, 1): if not frame.isdigit(): if index < 10: # 情况3 frame = (frame + "".join(frames[index:]))[:3] # 当前局的记分与后面所有局的记分合并,然后取前3个字符 score += sum(int(f) if f.isdigit() else 10 for f in re.sub("\d/", "X", frame)) return score
总算知道保龄球馆里的计分器是如何工作的了,接下来为了无限接近300分而努力吧!