2015-10-09 60 views
2

我曾嘗試解決叔叔鮑勃斯保齡球遊戲kata(http://www.butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata),但並未真正找到足以感受pythonic的解決方案。pythonic python中的保齡球遊戲kata

該解決方案或多或少是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 

我本來可以使用便利功能的罷工和備用條件,但你得到的圖片。

但我認爲必須有辦法做到這一點,而無需通過索引直接訪問卷數組。這感覺就像一個非常類似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 

我的問題基本上是,有沒有人解決在Python保齡球卡塔比叔叔鮑勃C++的解決方案不同,更Python的方式?並建議如何改進我的嘗試?

回答

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成爲例如score方法中的生成器表達式。

另一個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]),而無需爲此專門分配一行。