[英]How can "self" update original variable correctly? Recursion/Backtracking in the N-queens problem (Python)
這是我解決8皇后問題的python程序。 除了打印已解決的電路板的最后一步之外,一切都在工作。 我使用遞歸/回溯來用皇后填充棋盤,直到找到解決方案。 保存解決方案的板對象是self
,它是對b1
的引用,所以我假設b1
是我初始化的原始板,將被更新以包含最終解決的板,並將使用printBoard
打印解決方案。 但是,由於某種未知原因,當我打印b1
它沒有更新並且持有一個失敗的板。
編輯:在solve
添加了placeQueen
EMPTY = 0
QUEEN = 1
RESTRICTED = 2
class Board:
# initializes a 8x8 array
def __init__ (self):
self.board = [[EMPTY for x in range(8)] for y in range(8)]
# pretty prints board
def printBoard(self):
for row in self.board:
print(row)
# places a queen on a board
def placeQueen(self, x, y):
# restricts row
self.board[y] = [RESTRICTED for i in range(8)]
# restricts column
for row in self.board:
row[x] = RESTRICTED
# places queen
self.board[y][x] = QUEEN
self.fillDiagonal(x, y, 0, 0, -1, -1) # restricts top left diagonal
self.fillDiagonal(x, y, 7, 0, 1, -1) # restructs top right diagonal
self.fillDiagonal(x, y, 0, 7, -1, 1) # restricts bottom left diagonal
self.fillDiagonal(x, y, 7, 7, 1, 1) # restricts bottom right diagonal
# restricts a diagonal in a specified direction
def fillDiagonal(self, x, y, xlim, ylim, xadd, yadd):
if x != xlim and y != ylim:
self.board[y + yadd][x + xadd] = RESTRICTED
self.fillDiagonal(x + xadd, y + yadd, xlim, ylim, xadd, yadd)
# recursively places queens such that no queen shares a row or
# column with another queen, or in other words, no queen sits on a
# restricted square. Should solve by backtracking until solution is found.
def solve(self, col):
if col == -1:
return True
for i in range(8):
if self.board[i][col] == EMPTY:
temp = self.copy()
self.placeQueen(col, i)
if self.solve(col - 1):
return True
temp.board[i][col] = RESTRICTED
self = temp.copy()
return False
# deep copies a board onto another board
def copy(self):
copy = Board()
for i in range(8):
for j in range (8):
copy.board[j][i] = self.board[j][i]
return copy
b1 = Board()
b1.solve(7)
b1.printBoard()
我知道我的實際求解器正在工作,因為當我像這樣添加printBoard
:
if col == -1:
self.printBoard()
return True
在solve
方法中,印刷求解板。 簡而言之,為什么板的self
實例不更新b1
?
我相信您的問題與在解決方法中重新定義自我有關,我什至不確定您為什么要這樣做。
有關更多詳細信息,請參閱此問題: 在方法中將 self 對象替換為相同類型的另一個對象是否安全?
像您正在做的那樣重新分配 self 並不是重新分配“b1”引用。 因此,當您再次引用 b1 並執行 printBoard 時,您引用的對象與解決完成時“self.printBoard()”將引用的對象不同。
我會退后一步,問問自己為什么要替換 self ,這對您有什么好處。 您可能不需要也不應該這樣做。
我不確定這是如何工作的,因為從來沒有調用過placeQueen
。 因此,我不認為按照建議添加印刷品會呈現成品板(我認為它是空的)。 [注意:最新更新修復了這個]
使用受限方塊的想法是可行的,但這里的實現方式(沒有撤消選項)效率低下; 為每個內部循環復制一個全新的Board
對象非常昂貴。 對於所有的麻煩,我們也可以在每次移動時執行迭代沖突檢查,這至少可以節省新堆對象的分配和垃圾收集成本。
至於返回完成的板子結果,使用self
或self.board
的返回值,失敗時使用None
而不是True
和False
。
其他幾點:
__init__
方法是否__init__
。 該類作為封裝結構很好,我們應該在Board
類中隱藏諸如EMPTY
、 QUEEN
等靜態變量,無論該類是靜態的還是實例化的。printBoard
不應產生副作用--override __str__
。len(self.board)
並自由提供參數。fillDiagonal
不需要遞歸。 考慮使用列表推導式或 numpy 來簡化此矩陣遍歷邏輯。snake_case
變量名稱和文檔字符串而不是主題標簽注釋。 如果你覺得有必要寫一個評論,比如# restricts column
,可以考慮將相關的塊移動到一個名為restrict_column(...)
的函數中並跳過評論。這是實現以下幾點的初始重寫:
class Board:
EMPTY = 0
QUEEN = 1
DIRS = [(x, y) for x in range(-1, 2) for y in range(-1, 2) if x]
def __init__ (self, size=8):
self.board = [[Board.EMPTY] * size for _ in range(size)]
def __str__(self):
return "\n".join(map(str, self.board))
def legal_from(self, row, col, dr, dc):
while row >= 0 and row < len(self.board) and \
col >= 0 and col < len(self.board[row]):
if self.board[row][col] != Board.EMPTY:
return False
row += dr; col += dc
return True
def legal_move(self, row, col):
return all([self.legal_from(row, col, *d) for d in Board.DIRS])
def solve(self, row=0):
if row >= len(self.board):
return self
for col in range(len(self.board[row])):
if self.legal_move(row, col):
self.board[row][col] = Board.QUEEN
if self.solve(row + 1):
return self
self.board[row][col] = Board.EMPTY
if __name__ == "__main__":
for result in [Board(i).solve() for i in range(9)]:
print(result, "\n")
輸出:
[1]
None
None
[0, 1, 0, 0]
[0, 0, 0, 1]
[1, 0, 0, 0]
[0, 0, 1, 0]
[1, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 0, 0, 1]
[0, 1, 0, 0, 0]
[0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 1]
[0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.