You need to adapt your code to return after the solution is found, not returned. You only want to come back when you find yourself stepping back from the first line (because it indicates that you have studied all the possible solutions).
I think this is the easiest way to do this if you change the structure of your code a bit and loop into columns, and the reverse tracking logic will start when you are outside the row or column:
import copy def place_queen(board, row, column, solutions): """place a queen that satisfies all the conditions""" while True:
This will work for small boards (e.g. 4), but you will fall into Python's recursion limit if you try it for large board sizes. Python does not optimize tail recursion, so this code creates many stack frames when it moves from one line to another.
Fortunately, tail recursive algorithms usually easily turn into iterative algorithms. Here's how to do it with the code above:
import copy def place_queen_iterative(n): board = [[0 for x in range(n)] for x in range(n)] solutions = [] row = column = 0 while True: # loop unconditionally if len(board) in (row, column): if row == 0: return solutions elif row == len(board): solutions.append(copy.deepcopy(board)) for c in range(len(board)): if board[row-1][c] == 1: board[row-1][c] = 0 row -= 1 # directly change row and column, rather than recursing column = c+1 break # break out of the for loop (not the while) elif is_safe(board, row, column): # need "elif" here board[row][column] = 1 row += 1 # directly update row and column column = 0 else: # need "else" here column += 1 # directly increment column value
Please note that the iterative version does not need to be called with different initial values ββof rows and columns, therefore they are not needed as parameters. Similarly, the setup of the board and the list of results can be performed before the start of the cycle, and not in an auxiliary function (further reduce the functional parameters).
A slightly more Pythonic version of this will be a generator that yield its results, instead of collecting them in a list to return at the end, but this requires only minor changes (just yield instead of calling solutions.append ). Using a generator can also allow you to skip copying the board every time you have a solution, if you can depend on the consumer of the generator, using the result immediately (or making your own copy) before it starts the generator again.
Another idea is to simplify the presentation of your advice. You know that there can only be one queen in this row, so why not just keep the column where it was placed in the one-dimensional list (with the sentinel value, for example 1000 , indicating that the queen was not placed)? Thus, [1, 3, 0, 2] will be the solution to the problem with four queens, with queens in (0, 1) , (1, 3) , (2, 0) and (3, 2) (you can get these tuples using enumerate if you need them). This avoids the for loop during the backtracking phase and probably checks if the square is safe, since you do not need to look for a queen board.
Edit to ask additional questions:
At point Q1, you must deeply copy the board, because otherwise you will get a list of links to the same board. For comparison:
board = [0, 0] results.append(board) # results[0] is a reference to the same object as board board[0] = 1 # this mutates results[0][0] too! result.append(board) # this appends another reference to board! board[1] = 2 # this also appears in results[0][1] and result[1][1] print(board) # as expected, this prints [1, 2] print(results) # this however, prints [[1, 2], [1, 2]], not [[0, 0], [1, 0]]
As with Q2, you need return stop the code from working. You can separate the return from the recursive call if you want to make it more clear that the return value does not matter:
place_queen(board, row+1, 0) return
Please note that your current code may work, but it does some dubious things. You call is_safe with row values ββoutside ( row == len(board) ), and this only happens because your implementation of is_safe reports them as unsafe (without failures), which you return accordingly. And when you are in the backtracking code at line 0 (at the very end of the run), you simply exit correctly because the for loop cannot find the value 1 in board[-1] (that is, the last line). I suggest refactoring your code a bit more so as not to rely on such quirks to work properly.