2

I have written the following code to solve the n-queens problem:

(defun solve (board max-steps)

    (enforce-one-queen-per-column board)

    (dotimes (step max-steps) ; repeat for a max amount of times, 
        (if (eql (get-threatened-queens board) 0) ; if we have solved the board, return it
            (progn
                (format t "Solved!")
                (return board)
            )
        )

        (let ((threatened-queens (get-threatened-queens board)) ; get all threatened queens
              (queen nil))

             (setf queen (nth (random (length threatened-queens)) threatened-queens)) ; choose random threatened queen

             ; find which row in its column where it would be least threatened
             (let ((row-with-min-threats nil) ; (row_index, num_threats set to a high number)
                   (col (car queen))
                   (row (cdr queen)))

                  (format t "Dealing with threatened queen at (~A, ~A)...~%" col row)

                  (dotimes (i (array-dimension board 0)) ; for each row, find num of threats
                      (let ((num-threats (get-num-threats board col i)))
                           (print (car row-with-min-threats))
                           (format t "Checking (~A, ~A)~%" col i)
                           (format t "Threatened by ~A queens...~%" num-threats)

                            ; if row-with-min-threats has not yet been initialized
                           ; or if the row's threat is smaller than the tracked row with min threats

                            ; take first row as min threat so far
                            (if (eql row-with-min-threats nil) ; 
                                (setf row-with-min-threats (cons i num-threats))
                                (if (< num-threats (cdr row-with-min-threats)) ; if not first row and current min threats is smaller than tracked min
                                    (setf row-with-min-threats (cons i num-threats))
                                    (if (and (eql num-threats (cdr row-with-min-threats)) 
                                             (eql (random 2) 1))                            ; if current cell's & min cell's threats are equal, we randomly decide which cell to assign
                                        (progn 
                                            (format t "Randomly chose (~A, ~A)...~%" col i)
                                            (setf row-with-min-threats (cons i num-threats)))
                                        )

                                    )
                                )
                        )
                 )

                  (format t "Least threatened cell is (~A, ~A)...~%" col (car row-with-min-threats))

                  (if (not (eql row (car row-with-min-threats))) ; if its least threatened position isn't where it currently is
                      (progn
                          (setf (aref board (car row-with-min-threats) col) 1) ; move queen
                          (setf (aref board row col) 0) 
                          (format t "Moved queen to (~A, ~A)...~%" col (car row-with-min-threats))
                      )
                  )



             )
        )
    )

    nil
)

I'm trying to solve the 8-queens problem. The problem is in the solve function, but I'm not sure what I'm doing wrong. Since I am using the min-conflicts heuristic, I have a feeling that I am getting stuck in a local minima. I tried to overcome this by restarting the problem with the original board, but it doesn't seem to be working regardless of the amount of times I restart, since the queens are all stuck in the minimum conflicted spots, even though they still conflict. How can I improve solve to successfully place the 8 queens in cells where they do not threaten each other?

To run the program:

(setf board (make-board 8))
(solve board 10)

where the 10 represents the amount of times solve gets recalled on the original board.

I did not include my functions as they are self-explanatory but if they will help, I will be happy to include them.

brienna
  • 1,415
  • 1
  • 18
  • 45

1 Answers1

0

I tried to overcome this by restarting the problem with the original board, but it doesn't seem to be working regardless of the amount of times I restart, since the queens are all stuck in the minimum conflicted spots, even though they still conflict

I believe that simply means the initial position given by you can't be 'repaired' at all by the heuristic. In that case, you need to a new 'seed', which you can get by randomly choosing a row in all 8 columns, and doing that (if it turns out it's a bad seed) until you get a good one.
Since the solution space increases asymptotically, in a n*n board there are increasingly more 'good' initial positions/seeds the higher 'n' is.

Here is a Java class with these considerations (mostly at the main and shuffle methods): https://github.com/danielbmancini/JHTP8_JCP8_Sol._Comentadas/blob/master/7/src/EightQueensHeuristic.java

I hope this can be helpful to you. If i am wrong in any way, criticism is welcome.