[英]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.