我试图解决Uncle Bobs保龄球游戏kata(http://www.butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata),但没有找到足够感觉pythonic的解决方案。
此解决方案或多或少是对Martins C ++解决方案的改编,并使用数组索引来计算罢工和备件的分数。它有效,但感觉不像我希望的那样pythonic。
class Game():
def __init__(self):
self.rolls = []
def roll(self, pins):
self.rolls.append(pins)
def score_c(self):
total_score = 0
frame_index = 0
for frame in range(10):
if self.rolls[frame_index] == 10:
total_score += 10 + self.rolls[frame_index + 1] + self.rolls[frame_index + 2]
frame_index +=1
elif self.rolls[frame_index] + self.rolls[frame_index + 1] == 10:
total_score += 10 + self.rolls[frame_index + 1]
frame_index += 2
else:
total_score += self.rolls[frame_index] + self.rolls[frame_index + 1]
frame_index += 2
return total_score
我可以使用便利功能来实现打击和备用条件,但是你可以得到图片。
但是我认为必须有一种方法可以直接通过索引访问roll数组。这感觉就像一个非常类似于c的方式,直接增加frame_index肯定在python中感觉不对。所以我认为必须有一个更简洁的方法来做到这一点。我在下面做了一个尝试,并没有真正适用于完美游戏。
这个使用发电机来提供感觉非常整洁的框架,但这也意味着必须添加0来进行打击才能制作完整的2个滚动框架。
class Game():
def __init__(self):
self.rolls = []
def _frame_iterator(self):
for i in range(0, 20, 2):
yield (self.rolls[i], self.rolls[i+1])
def roll(self, pins):
self.rolls.append(pins)
if pins == 10:
self.rolls.append(0)
def score(self):
total_score = 0
spare = False
strike = False
for frame in self._frame_iterator():
if spare:
total_score += frame[0]
spare = False
if strike:
total_score += frame[1]
strike = False
if frame[0] + frame[1] == 10:
spare = True
if frame[0] == 10:
strike = True
total_score += frame[0] + frame[1]
return total_score
我的问题基本上是,有没有人用不同于更多的pythonic方式解决Python中的保龄球kata而不是叔叔bobs C ++解决方案?并建议如何改进我的尝试?
答案 0 :(得分:0)
这绝对是一种不同的方法(实现roll()
中的大多数规则,而不是score()
),我认为它也是非常pythonic。
class Game(object):
def __init__(self):
self._score = [[]]
def roll(self, pins):
# start new frame if needed
if len(self._score[-1]) > 1 or 10 in self._score[-1]:
self._score.append([])
# add bonus points to the previous frames
for frame in self._score[-3:-1]:
if sum(frame[:2]) >= 10 and len(frame) < 3:
frame.append(pins)
# add normal points to current frame
for frame in self._score[-1:10]:
frame.append(pins)
def score(self):
return sum(sum(x) for x in self._score)
这里的主要思想是将所有卷存储在一个列表中,以制作包含每个帧的卷(和奖励点)列表的帧列表。
使它成为pythonic的原因是例如得分方法中的生成器表达式。
另一个pythonic示例是使用列表切片。我roll()
的中间部分的早期版本看起来像:
for i in [2, 3]:
if len(self._score) >= i:
sum(self._score[-i][:2]) >= 10 and len(self._score[-i]) < 3:
self._score[-i].append(pins)
使用列表切片的当前版本的优雅之处在于,您不必检查列表是否足够长以回显1或2帧。而且,你可以免费得到一个很好的局部变量(frame = self._score[-i]
),而不必为它专门设置一条线。