I have a piece of Python code that implements a recursive backtracking algorithm for solving the famous N-Queens problem in chess.
def Backtrack(board, col):
if col >= N:
return True
for i in range(N):
if (ld[i - col + N - 1] != 1 and rd[i + col] != 1) and cl[i] != 1:
board[i][col] = 1
ld[i - col + N - 1] = rd[i + col] = cl[i] = 1
if Backtrack(board, col + 1):
return True
board[i][col] = 0 # Backtrack
ld[i - col + N - 1] = rd[i + col] = cl[i] = 0
return False
where
ld = np.zeros(2*N - 1, dtype=int)
rd = np.zeros(2*N - 1, dtype=int)
cl = np.zeros(N, dtype=int)
board = np.zeros((N, N), dtype=int)
I want to keep a track of how many times the recursive backtracking algorithm is called.
I added a counter variable to the code such that
def Backtrack(board, col, counter):
counter += 1
print('here', counter)
if col >= N:
return True
for i in range(N):
if (ld[i - col + N - 1] != 1 and rd[i + col] != 1) and cl[i] != 1:
board[i][col] = 1
ld[i - col + N - 1] = rd[i + col] = cl[i] = 1
if Backtrack(board, col + 1, counter):
return True
board[i][col] = 0 # Backtrack
ld[i - col + N - 1] = rd[i + col] = cl[i] = 0
return False
however for N = 4 the output is
here 1
here 2
here 3
here 3
here 4
here 2
here 3
here 4
here 5
which shows that my attempt is incorrect. The function is called 9 times but at the end the counter variable is 5.
Integers are immutable, so when you do counter += 1
, you create a new number, say from 1 to 2, and 2 is now bound to the name counter
. So when you're at depth 2 and call the function twice, both calls will increment 2 to their own 3. In python you don't pass by variable, but by name, so that counter
isn't referring to the same thing throughout all the calls.
What you want is either a mutable or global variable. For example
# or a class implementation equivalent
counter = 0
def backtrack(board, col):
global counter
counter += 1
# the rest
But that way you'd need to reset counter
to 0 every time you want to restart the algorithm. Therefore, I think it's better to do
def backtrack(board, col, counter=None):
if not counter:
counter = [0]
counter[0] += 1
# the rest of your function
Be very careful of doing backtrack(board, col, counter=[0])
, because counter
will be initialised to the list only once. After you've solved, for say N=4, it will have the value 9 and if you call the function again, it will keep incrementing from there.