保龄球计分

大家是不是都玩过保龄球?虽然水平很烂,但我是保龄球爱好者。今天这一题是用python来计算保龄球的分数。首先讲一下保龄球的规则:

保龄球的一局称为一个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 43X 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 re

def 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分而努力吧!

posted on 2017-05-21 17:43  jennyz_2017  阅读(3302)  评论(0编辑  收藏  举报

导航