簡體   English   中英

Python:將此檢查重構為自己的方法是否有意義?

[英]Python: does it make sense to refactor this check into its own method?

我還在學習python。 我只是寫了這個方法,以確定一個玩家是否贏得了一個井字游戲,給出了一個董事會狀態: '[['o','x','x'],['x','o','-'],['x','o','o']]'

def hasWon(board):
  players = ['x', 'o']
  for player in players:
    for row in board:
      if row.count(player) == 3:
        return player
    top, mid, low = board
    for i in range(3):
      if [ top[i],mid[i],low[i] ].count(player) == 3:
        return player
    if [top[0],mid[1],low[2]].count(player) == 3:
        return player
    if [top[2],mid[1],low[0]].count(player) == 3:
        return player
  return None

在我看來,我多次檢查3個字符列表,並可以將檢查重構為自己的方法,如下所示:

def check(list, player):
  if list.count(player) == 3:
    return player

...但后來意識到所有真正做的就是更改線條:

 if [ top[i],mid[i],low[i] ].count(player) == 3:
    return player

至:

  if check( [top[i],mid[i],low[i]], player ):
    return player

......坦率地說,似乎並沒有多大的改進。 你有沒有看到更好的重構方法? 或者一般來說更多的Pythonic選項? 我很樂意聽到它!

我可能會用

def check(somelist, player):
  return somelist.count(player) == 3

編輯 :正如@Andrew在評論(tx @Andrew!)中建議的那樣,你可以做得更好,例如:

def check(somelist, player):
  return somelist.count(player) == len(somelist)

沒有硬編碼3 - 這也暗示了另一個不錯的選擇:

def check(somelist, player):
  return all(x==player for x in somelist)

它直接讀取“列表中的所有項目相等的player ”。 一般的觀點是,通過重構到一個單獨的方法,你可以使用該方法的實現 - 現在當然這里的代碼非常簡單,所以優勢同樣適中,但是當你轉移到時,這是一個很好的注意事項。更復雜的代碼。

正如你已經注意到你無論如何你只需要一個bool,所以這允許一個更簡單的方法 - 只返回bool表達式而不是在它上面做一個if 重要的是永遠不要為你自己的標識符使用像list這樣的內置名稱 - 這種語言的“有吸引力的麻煩”...... ;-)。

我的意思是,Python為其內置函數使用了許多漂亮,有吸引力的名稱,如list,bool,sum等等,所以很容易發現自己不小心使用其中一個名稱作為自己的變量,而沒有糟糕似乎發生......直到你需要把一個元組轉換成一個列表的時候,使用明顯最好的解決方案, x = list(thetuple) ...並最終花費我們試圖理解和解決錯誤因為你使用list而不是該名稱的內置類型。

所以,只是養成使用那些漂亮的內置名稱而不是指示相應內置的目的的習慣,你將為自己節省很多未來的惡化! - )

回到你的代碼,你可能會考慮通過拆包提供的簡潔board (一個艱難的決定,因為你的代碼相當可讀......但看起來可能有點冗長):

for i in range(3):
  if check([row[i] for row in board], player):
    return player
if check([row[i] for i, row in enumerate(board)], player):
    return player
if check([row[2-i] for i, row in enumerate(board)], player):
    return player

最后,我認為我會堅持你的選擇 - 更具可讀性,只是略微更冗長,如果有的話 - 但我很高興知道替代品,我認為 - 在這里,列出理解和enumerate生成要檢查的列表作為“手動編碼”三種可能性的替代方法。

只需在board制作自定義迭代器即可。

def get_lines(board):
  nums = range(3)
  for i in nums: 
    yield (board[i][j] for j in nums) #cols
  for j in nums: 
    yield (board[i][j] for i in nums) #rows
  yield (board[i][i] for i in nums) #diag \
  yield (board[i][2-i] for i in nums) #diag /

def get_winner(board): #a bit too indented
  for line in get_lines(board): #more expensive, so go through it only once
    for player in 'x', 'o':
      if line == player, player, player: #other way to check victory condition
        return player
  return None

顯然這些應該是board級的方法:)

您可以使用更好的名稱,而不是check不是很多。 經驗法則是:如果你能想出一個代碼和平的好名字,那么將它移動到單獨的函數中可能是有益的,即使它只是一行代碼。 allsame可能是這里的替代選擇之一。

def winner(board):
    main_diag = [row[i] for i, row in enumerate(board)]
    aux_diag = [row[len(board) - i - 1] for i, row in enumerate(board)]   
    for triple in board + zip(*board) + [main_diag, aux_diag]: 
        if allsame(triple):         
           return triple[0]

def allsame(lst):    
    return all(x == lst[0] for x in lst)

就我個人而言,我認為你最好的選擇就是將函數冒出來,為你提供董事會的行(),列()和diags(),作為列表列表。 然后你可以迭代這些並統一檢查。 您甚至可以定義allTriples(),它附加rows(),columns()和diags()的輸出,以便您可以在一個簡潔的循環中進行檢查。 我可能也會把電路板作為一個對象,這樣這些函數就可以成為對象方法。

而現在完全不同的東西:

通過九個要素列表代表董事會。 每個元素可以是-1(X),1(O)或0(空):

WIN_LINES = (
    (0, 1, 2),
    (3, 4, 5),
    (6, 7, 8),
    (0, 3, 6),
    (1, 4, 7),
    (2, 5, 8),
    (2, 4, 6),
    (0, 4, 8),
    )

def test_for_win(board):
    for line in WIN_LINES:
        total = sum(board[point] for point in line)
        if abs(total) == 3:
            return total // 3
    return None

細化:

WIN_LINES = (
    0, 1, 2,
    3, 4, 5,
    6, 7, 8,
    0, 3, 6,
    1, 4, 7,
    2, 5, 8,
    2, 4, 6,
    0, 4, 8,
    )

def test_for_win(board):
    wpos = 0
    for _unused in xrange(8):
        total  = board[WIN_LINES[wpos]]; wpos += 1
        total += board[WIN_LINES[wpos]]; wpos += 1
        total += board[WIN_LINES[wpos]]; wpos += 1
        if total ==  3: return  1
        if total == -3: return -1
    return None

只是一個想法

def hasWon(board):
  players = ['x', 'o']
  for player in players:
    top, mid, low = board
    game = board + [[ top[i],mid[i],low[i]] for i in range(3)] + [top[0],mid[1],low[2]] +[top[2],mid[1],low[0]]
    if 3 in [l.count(player) for l in game] :
      return player
  return None

您的解決方案很好 - 正確,可讀和易懂。

盡管如此,如果你想優化速度,我會使用一維數字而不是字符串數組,並嘗試盡可能少地查找每個數字。 肯定會有一個非常尷尬的解決方案,您只需檢查一次每個字段。 我現在不想構建它。 :)如果您想要在探索可能移動的整個搜索樹時實施與您對戰的AI,那么這樣的事情可能很重要。 那里有必要進行有效的贏/輸檢查。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM