-2

The N Queen is the problem of placing N chess queens on an N×N chessboard so that no two queens attack each other. I have solved this program earlier, but am trying to rework my code to mirror that which I used to fashion a sudoku solver. I cannot seem to find the logical error but when I run the code, nothing prints. My program is attached below and if anyone could find my error that would be very helpful!

import numpy as np

def main():
    global n
    n = input("Enter N")
    n = int(n)
    global board
    board = np.zeros((n,n), dtype=int)
    solve_board()

def solve_board():

    for row in range(n):
        for col in range(n):
            if board[row][col] == 0: #no queen
                if (is_valid (board,row,col,n)):
                    board[row][col] = 1 #Assigning 1 for queen
                    solve_board()
                    board[row][col] = 0
            return False


    print('-'*n)
    for row in board:
        for col in row:
            if col == 1:
                print ("Q", end = " ")
            else:
                print (".", end = " ")


def is_valid(board,i,j,n):

    if 1 in board[i]: #Checking row
        return False

    for row in range(0,i): #Checking column
        if (board[row][j]==1):
            return False
    x,y = i,j

    while (x>=0 and y>=0): #left diagonal
         if (board[x][y]==1):
             return False
         x-=1
         y-=1

    x,y = i,j
    while (x>=0 and y<n): #right diagonal
         if (board[x][y]==1):
             return False
         x-=1
         y+=1
    return True

if __name__ == "__main__":
    main()

This is how I had solved this code earlier, with solve_board being altered as followed.

def solve_board(row):

    if(row == n):
        print('-'*n)
        for row in board:
            for col in row:
                if col == 1:
                    print ("Q", end = " ")
                else:
                    print (".", end = " ")
            print("")


    else:
        for col in range(n):
            if (is_valid (board,row,col,n)):
                board[row][col]=1
                solve_board(row+1)
                board[row][col] = 0
        return False

Here is where the inspiration for my current code came from, a sudoku solver that I designed where I used 2 nested for loops; one for rows and one for columns. Based on this I had altered my solve_board(row) in my original n-queens code to the current function without a parameter. This sudoku code works perfectly.

def solve_board():

        global board
        for rowno in range(9):
            #print ("row",rowno)
            for colno in range(9):
                #print("col",colno)
                if board[rowno][colno] == 0:
                    for i in range(1,10):
                        #print(i)
                        if (is_valid(board,rowno,colno,i)):
                            board[rowno][colno]=i
                            solve_board()
                            board[rowno][colno]=0
                    return False

        print (np.matrix(board))

I think the issue might lie in the fact that in the N-Queens problem the board does not fill up, i.e there are still 0s while for sudoku the entire board fills up and therefore when the ''if board[row][col] == 0'' is proven false exits the loop and prints. In the N-Queens problem since zero's are always present, it becomes an issue.

Akashvshroff
  • 181
  • 1
  • 9
  • `return False` statemnet in `solve_board()` method is causing the problem if condition fails program will stop execution because of `return` statement – deadshot Apr 07 '20 at 17:16
  • If I remove the return False, then it does not follow n and gives back a long, incorrect pattern. What do you recommend? How do I alter the return statement? – Akashvshroff Apr 07 '20 at 17:30
  • if condition fails which statement do you want to execute is starts from next `row` or next `column` – deadshot Apr 07 '20 at 17:49
  • If the condition fails, and the value is reset (board[row][col] = 0), it should try the next column in the same row if possible, else if end of row move to the next row, that is why I nested the column in rows. Is my response making sense? Thank you so much. – Akashvshroff Apr 07 '20 at 17:57
  • If you could check my latest edit, it might be clearer? Thank you! – Akashvshroff Apr 07 '20 at 18:04
  • you can use `continue` if you want continue from next column. If you want start from next row use `break` – deadshot Apr 07 '20 at 18:05
  • Using either in place of the return False didn't work, it would be greatly appreciated if you could see the version of solve_board that worked as per my latest edit, the only difference is the use of row as a parameter that is manually updated and as a looped integer. Thank you. – Akashvshroff Apr 07 '20 at 18:12

1 Answers1

0

Try this

import numpy as np

def main():
    global n
    n = input("Enter N: ")
    n = int(n)
    global board
    board = np.zeros((n,n), dtype=int)
    solve_board()

def print_board():
    print('-'*n)
    for row in board:
        for col in row:
            if col == 1:
                print ("Q", end = " ")
            else:
                print (".", end = " ")
        print()


def is_valid(board,i,j,n):

    if 1 in board[i]: #Checking row
        return False

    for row in range(0, n): #Checking column
        if (board[row][j]==1):
            return False

    for k in range(0,n):
        for l in range(0,n):
            if (k+l==i+j) or (k-l==i-j):
                if board[k][l]==1:
                    return False
    return True

def solve_board():
    for row in range(n):
        for col in range(n):
            if board[row][col] == 0: #no queen
                if (is_valid (board,row,col,n)):
                    board[row][col] = 1 #Assigning 1 for queen
                    if np.count_nonzero(board) == n:
                      print_board()
                      return True
                    solve_board()
                    board[row][col] = 0
            else:
                  return False

if __name__ == "__main__":
    main()

deadshot
  • 8,881
  • 4
  • 20
  • 39
  • I tried this to no avail since the purpose of the code is backtracking and removing the recursive call and the board[row][col] = 0 eliminates that. Is there any other way? I have earlier successfully completed recursion within a for loop, I will edit my query and add that snippet. Maybe if you saw that, it would be easier? Thank you. – Akashvshroff Apr 07 '20 at 18:37
  • While I really appreciate your answer ( it still doesn't give me the desired output, however), I do not simply want to solve the problem, I have already done that in the other nqueen program as attached above, rather I want to understand why my recursion and backtracking are not working in this program. Your solution does not use recursion or backtracking and I would love if you could help me with that rather than simply a solution. Thank you! – Akashvshroff Apr 07 '20 at 19:29