2016-08-08 75 views
2

我在寫一個Python腳本,它應該允許人類和電腦玩家玩井字遊戲。爲了表示棋盤,我使用了3x3的Numpy陣列,其中10用於玩家的標記(而不是「X」和「O」)。我已經寫了下面的函數來決定勝負:如何使功能決定Tic-Tac-Toe的優勝者更簡潔

import numpy as np 

class Board(): 
    def __init__(self, grid = np.ones((3,3))*np.nan): 
     self.grid = grid 

    def winner(self): 
     rows = [self.grid[i,:] for i in range(3)] 
     cols = [self.grid[:,j] for j in range(3)] 
     diag = [np.array([self.grid[i,i] for i in range(3)])] 
     cross_diag = [np.array([self.grid[2-i,i] for i in range(3)])] 

     lanes = np.concatenate((rows, cols, diag, cross_diag)) 

     if any([np.array_equal(lane, np.ones(3)) for lane in lanes]): 
      return 1 
     elif any([np.array_equal(lane, np.zeros(3)) for lane in lanes]): 
      return 0 

因此,舉例來說,如果我執行

board = Board() 
board.grid = np.diag(np.ones(3)) 
print board.winner() 

我得到的結果1。令我困擾的是any聲明的重複。我想會有一個更簡潔,乾爽的編碼方式。 (我正在考慮使用MATLAB中的開關/外殼,但在Python中並不存在)。有什麼建議麼?

+0

提供任何生成器表達式比列表理解更有效率。 「任何」短路,即一旦它獲得了真元素,它就會停止評估其他元素。但是,如果你通過一個列表comp,整個列表必須在'any'開始工作之前建立。然而如果你通過一個像任何一個gen exp(np.array_equal(lane,np.ones(3))的泳道,那麼gen exp甚至不會生成後面的元素。類似的評論適用於「全部」。 –

回答

2

另一種選擇是檢查總和lanes

s = np.sum(lanes, axis=1) 
    if 3 in s: 
     return 1 
    elif 0 in s: 
     return 0 
1

我做了一個循環,而不是,並返回只有一次,PEP8符合,老實說我個人的編碼標準:)

以正確的順序enumerate將產生0,zeromatrix然後1,onematrix

rval = None 
for i,m in enumerate([np.zeros(3),np.ones(3)]): 
    if any([np.array_equal(lane, m) for lane in lanes]): 
     rval = i; break 
return rval 
+0

你不需要'return None',如果沒有調用return,我總是返回'None' –

+0

我知道,但我認爲這是一個不好的習慣。好的,那就更短了,謝謝。 –

+2

「在返回語句中保持一致,函數中的所有返回語句都應該返回一個表達式,否則它們都不應該。如果任何返回語句返回一個表達式,那麼沒有返回值的任何返回語句都應該明確聲明這個返回值爲None,並且在函數的末尾應該有一個顯式的return語句(如果可以的話)。「 -PEP8 – acdr

0

我發現了一種方法,通過使用Lambda函數:

any_lane = lambda x: any([np.array_equal(lane, x) for lane in lanes]) 

if any_lane(np.ones(3)): 
    return 1 
elif any_lane(np.zeros(3)): 
    return 0 

這增加了一個額外的行合作但我認爲整體更清晰。

+1

你可以使用'functools.partial'來代替。另外''和'''不僅是多餘的,它們實際上首先創建一個新列表。 –

0

這可以在兩線進行,從電路板(grid)出發:沿列,行簡單的算術和兩個主要對角線爲您提供了0或3取決於誰是贏家值(或只有在沒有人獲勝時纔有中間值)。由此就可以計算出類似:

# Score along each column, row and both main diagonals: 
scores = (grid.sum(axis=0).tolist() + grid.sum(axis=1).tolist() 
      +[grid.trace(), np.flipud(grid).trace()]) 

# If there is no winner, None is declared the winner: 
print "Winner:", 1 if 3 in scores else 0 if 0 in scores else None 

其中flipud()變換對角線到反對角(對角90°從主對角線)通過水平翻轉陣列,使得簡單trace()給出的合計值沿反對角線。