2017-07-18 112 views
0

我開始學習球拍,我正在使用任意的arity樹和生成遞歸來從給定棋盤上獲取棋盤的所有可能版本。球拍 - > Python

所以我們可以說我有這樣的板,其中假指空:

(list "X" "X" "O" "O" "X" "O" "X" #false "X") 

的解決方案,這個根據要求是:

(list 
(list "X" "X" "O" "O" "X" "O" "X" "X" "X") 
(list "X" "X" "O" "O" "X" "O" "X" "O" "X")) 

球拍該解決方案的偉大工程。我在Python中嘗試了同樣的事情,但它並不像預期的那樣工作。

我不斷收到輸出這樣的:

[['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X'], [['X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X'], []]] 

['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X', 'X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X'] 

或更糟。

我似乎無法讓它給我我想要的輸出。

我正在考慮對輸出做一些後期處理,如果沒有其他工作,但我想避免這種情況。

我需要的是這樣的:

[['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X'], ['X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X']] 

在任何情況下,讓我知道如果你能幫助。

這裏是我的Python代碼:

""" 
Brute force solution for tic-tac-toe. 
""" 


""" 
Data definitions: 

;; Value is one of: 
;; - false 
;; - "X" 
;; - "O" 
;; interp. a square is either empty (represented by false) or has and "X" or an "O" 


;; Board is (listof Value) 
;; a board is a list of 9 Values 

""" 

# 
## CONSTANTS 
# 
B0 = [False for i in range(9)] 
B1 = [ 
    False, "X", "O", 
    "O", "X", "O", 
    False, False, "X" 
] 
B2 = [ 
     "X", "X", "O", 
     "O", "X", "O", 
     "X", False, "X", 
     ] 

B3 = [ 
     "X", "O", "X", 
     "O", "O", False, 
     "X", "X", False, 
] 


""" 
PROBLEM 1 

In this problem we want you to design a function that produces all 
possible filled boards that are reachable from the current board. 

In actual tic-tac-toe, O and X alternate playing. For this problem 
you can disregard that. You can also assume that the players keep 
placing Xs and Os after someone has won. This means that boards that 
are completely filled with X, for example, are valid. 

""" 


def fill_board(index, bd): 
    """ 
    Returns a list of 2 board versions with 
    the index filled with "X" and "O" 

    :param index: int; index of position in list to be filled 
    :param bd: Board 
    :return: (listof Board) 
    """ 
    return [ 
     bd[:index] + ["X"] + bd[index+1:], 
     bd[:index] + ["O"] + bd[index + 1:], 
    ] 


assert fill_board(0, B1) == [ 
    [ 
    "X", "X", "O", 
    "O", "X", "O", 
    False, False, "X" 
    ], 
    [ 
    "O", "X", "O", 
    "O", "X", "O", 
    False, False, "X" 
    ], 
] 

assert fill_board(5, B3) == [ 
[ 
     "X", "O", "X", 
     "O", "O", "X", 
     "X", "X", False, 
], 
[ 
     "X", "O", "X", 
     "O", "O", "O", 
     "X", "X", False, 
], 
] 


def find_blank(bd): 
    """ 
    Return the index of the 
    first empty (False) value 
    in the board. 
    ASSUME: there is at least one 
    empty cell. 

    :param bd: Board 
    :return: Index 
    """ 
    return bd.index(False) 

assert find_blank(B0) == 0 
assert find_blank(B2) == 7 
assert find_blank(B3) == 5 


def next_boards(bd): 
    """ 
    Produce the next version of initial board. 
    Finds the first empty (False) cell, and produces 
    2 versions of the board; one with X and one with O 
    :param bd: Board 
    :return: (listof Board) 
    """ 

    return fill_board(find_blank(bd), bd) 


assert next_boards(B0) == [ 
    ["X"] + B0[1:], 
    ["O"] + B0[1:], 
] 


assert next_boards(B3) == [ 
[ 
     "X", "O", "X", 
     "O", "O", "X", 
     "X", "X", False, 
], 
[ 
     "X", "O", "X", 
     "O", "O", "O", 
     "X", "X", False, 
], 
] 


def solve(bd): 
    """ 
    Produce all possible filled boards that are 
    reachable from the current board. 

    :param bd: Board (listof Value) 
    :return: (listof Board) 
    """ 
    def is_full(bd): 
     """ 
     Returns true if board is full; meaning 
     if every value on the board is a string. 

     :param bd: Board (listof Value) 
     :return: Boolean 
     """ 
     return all(type(i) is str for i in bd) 

    def solve__bd(bd): 
     """ 
     Mutually refential function with 
     solve__lobd. This is where all the actual 
     computation takes place. 
     The two functions are responsible for 
     generating and operating on the tree. 
     The tree (arbitraty arity tree) represents 
     another version of the board filled with an 
     additional X or O. 

     :param bd: Board (listof Value) 
     :return: (listof Board) 
     """ 

     if is_full(bd): 
      return list(bd) 

     return solve__lobd(next_boards(bd)) 

    def solve__lobd(lobd): 
     """ 
     Helper function of solve, alongside solve__bd 
     :param lobd: (listof Board) 
     :return:  (listof Board) 
     """ 

     if not lobd: 
      return [] 

     return [solve__bd(lobd[0]), solve__lobd(lobd[1:])] 

    return solve__bd(bd) 


assert solve(B2) == [ 
    [ 
     "X", "X", "O", 
     "O", "X", "O", 
     "X", "X", "X", 
     ], 
    [ 
     "X", "X", "O", 
     "O", "X", "O", 
     "X", "O", "X", 
     ], 
] 


assert solve(B3) == [ 
    [ 
     "X", "O", "X", 
     "O", "O", "X", 
     "X", "X", "X", 
    ], 
    [ 
     "X", "O", "X", 
     "O", "O", "X", 
     "X", "X", "O", 
    ], 
    [ 
     "X", "O", "X", 
     "O", "O", "O", 
     "X", "X", "X", 
    ], 
    [ 
     "X", "O", "X", 
     "O", "O", "O", 
     "X", "X", "O", 
    ], 
] 
+0

只要做,例如[B1,B2] – perigon

回答

0

這看起來像一個缺點般的混亂。我沒有測試過這一點,但我敢打賭,你的問題就出現在這裏:

return [solve__bd(lobd[0]), solve__lobd(lobd[1:])] 

我猜你想

return [solve__bd(lobd[0])] + solve__lobd(lobd[1:])] 

...相反。

但是:Python列表不是鏈表。 cons是向Racket中的列表添加元素的高效且合理的方式,但是在單元素列表和更長列表上使用Python的+運算符形成列表將需要複製列表中的所有後面的元素。

對於短列表(小於10K元素列表的線性操作或 小於100元素左右列表上的二次操作),則無關緊要。 對於更長的,它會。 Python的人會告訴你,你做錯了,你應該在現有的數組上使用突變。然後球拍人士會告訴你,Python人陷入了過去。歡迎來到精彩的編程世界!

+0

感謝您花時間回答@John Clements!您的解決方案適用於求解(B2),但求解(B3)仍然無法通過測試。我把你的建議改爲:return [solve__bd(lobd [0])] + solve__lobd(lobd [1:]),但是我得到的輸出結果是3個列表,如下所示:[[['X O','X','O','O','X','X','X','X'],['X','O','X','O ','O','X','X','X','O']],[['X','O','X','O','O','O', X,X,X,X,O,X,O,O,O,X,X,O, ]。我想移植到Python的球拍解決方案不會,但我還沒有找到更容易解決這個問題的解決方案。 – bjj