Solving 4-queen problem: Translate my logic to code? Unable to do so

I don't think I am obseeed with ChatGPT; but I like using it. After all, I already know how to write algorithms and code, and have done that for more than 50 years; so it is not interesting to me.

However, mastering a powerful LLM is new to me; not old. I especially like learning how to use such a powerful tool in ways I never used it before, with an open mind.

(Note: I disagree with you @Ihattaren that ChatGPT is "stupid", because I use ChatGPT daily, and it is much smarter than most people I know (as far an LLM goes), with less ego and emotional baggage,, as far as how an LLM is designed to work. ChatGPT is just an LLM and I would never call it "stupid", to be honest).

Yes, I have a monthly subscription; and was also on top of the OpenAI ChatGPT forum developers leaderboard back in the beginning, helping people develop using the API. Since the new models have matured a lot, I have been experimenting with ChatGPT 4o across many domains.

As metioned, the only reason I replied back in this topic was to test to see if I could get ChatGPT 4o to generate the positional arrays - because I was pretty sure after generating these arrays, the code to hunt for the solutions would be pretty simple and fast (using this method, I made up off the top-of-my-head)..

:slight_smile:

Yes, it's correct. So, I completed the code using this method:

ruby method using a hash of positional arrays:

# Queen movement arrays as 1D arrays (Ruby hash)
queen_moves = {
  'Position 0' => [1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1],
  'Position 1' => [1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0],
  'Position 2' => [1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0],
  'Position 3' => [1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1],
  'Position 4' => [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0],
  'Position 5' => [1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1],
  'Position 6' => [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0],
  'Position 7' => [0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1],
  'Position 8' => [1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
  'Position 9' => [0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0],
  'Position 10' => [1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
  'Position 11' => [0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1],
  'Position 12' => [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1],
  'Position 13' => [0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1],
  'Position 14' => [0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1],
  'Position 15' => [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1]
}

# Define a function to check if placing a queen at a certain position is safe
def is_safe(position, queens)
  row, col = position / 4, position % 4
  
  queens.each do |q|
    q_row, q_col = q / 4, q % 4
    
    # Check for conflicts in the same row, column, and diagonals
    return false if q_row == row || q_col == col || (q_row - row).abs == (q_col - col).abs
  end
  
  true
end

# Recursive function to solve the 4-queens problem
def solve_4_queens(queens = [], row = 0, solutions = [])
  if queens.size == 4  # All queens placed
    solutions << queens.dup  # Store the solution
    return
  end

  (0..15).each do |position|
    next unless position / 4 == row  # Ensure we place one queen per row

    if is_safe(position, queens)
      queens.push(position)  # Place the queen
      solve_4_queens(queens, row + 1, solutions)
      queens.pop  # Backtrack
    end
  end
  
  solutions
end

# Call the function to solve the 4-queens problem
solutions = solve_4_queens

# Print all the solutions
if solutions.empty?
  puts "No solutions found"
else
  solutions.each_with_index do |solution, index|
    puts "Solution #{index + 1}:"
    solution.each do |pos|
      puts "Queen placed at: Position #{pos} (Row #{pos / 4}, Column #{pos % 4})"
    end
    puts "\n"
  end
end

run it:

macos $ ruby four_queens.rb
Solution 1:
Queen placed at: Position 1 (Row 0, Column 1)
Queen placed at: Position 7 (Row 1, Column 3)
Queen placed at: Position 8 (Row 2, Column 0)
Queen placed at: Position 14 (Row 3, Column 2)

Solution 2:
Queen placed at: Position 2 (Row 0, Column 2)
Queen placed at: Position 4 (Row 1, Column 0)
Queen placed at: Position 11 (Row 2, Column 3)
Queen placed at: Position 13 (Row 3, Column 1)

ruby four_queens.rb  0.03s user 0.02s system 80% cpu 0.064 total

So, that was kinda fun. I used ChatGPT 4o to generate all 16 positional arrays (finally) and then worked with ChatGPT back-and-forth a bit more to write the Ruby code (as I wanted it to be) to solve this for both solutions.

Also, I did a quick network search before going down this little rabbit hole, and did not find any solution similar to this one; but I probably missed something as I did not search very long; only looking for about 10 minutes.

My last post on this topic, will keep it short and not post the large hash or the code.

I modified my method for an 8x8 board, generating the positional hash first, and then running the same code modified a bit for boards of varying (nxn) sizes:

8x8 has 92 solutions.....

macos $ time ruby eight_by_eight_code.rb
Solution 1:
Queen placed at: Position 0 (Row 0, Column 0)
Queen placed at: Position 12 (Row 1, Column 4)
Queen placed at: Position 23 (Row 2, Column 7)
Queen placed at: Position 29 (Row 3, Column 5)
Queen placed at: Position 34 (Row 4, Column 2)
Queen placed at: Position 46 (Row 5, Column 6)
Queen placed at: Position 49 (Row 6, Column 1)
Queen placed at: Position 59 (Row 7, Column 3)
#....
#....
#....
Solution 92:
Queen placed at: Position 7 (Row 0, Column 7)
Queen placed at: Position 11 (Row 1, Column 3)
Queen placed at: Position 16 (Row 2, Column 0)
Queen placed at: Position 26 (Row 3, Column 2)
Queen placed at: Position 37 (Row 4, Column 5)
Queen placed at: Position 41 (Row 5, Column 1)
Queen placed at: Position 54 (Row 6, Column 6)
Queen placed at: Position 60 (Row 7, Column 4)

ruby eight_by_eight_code.rb 0.04s user 0.02s system 81% cpu 0.074 total

Finally, combining the code to generate the positional hash for the 8x8 board and then find the queens (92 solutions):

ruby find_eight_queens.rb  0.04s user 0.02s system 81% cpu 0.074 total

That's all folks! :slight_smile:

Edit:

Coukd not resist going for nine queens:

#...
#...
#...
Solution 352:
Queen placed at: Position 8 (Row 0, Column 8)
Queen placed at: Position 15 (Row 1, Column 6)
Queen placed at: Position 21 (Row 2, Column 3)
Queen placed at: Position 28 (Row 3, Column 1)
Queen placed at: Position 43 (Row 4, Column 7)
Queen placed at: Position 50 (Row 5, Column 5)
Queen placed at: Position 54 (Row 6, Column 0)
Queen placed at: Position 65 (Row 7, Column 2)
Queen placed at: Position 76 (Row 8, Column 4)

ruby nine_queens.rb  0.07s user 0.02s system 86% cpu 0.105 total

Second Edit: 13 Queens (73,712 solutions)

Ran it as NxN code for a 13x13 board for fun:

macos  $ time ruby n_queens.rb
ruby n_queens.rb  41.28s user 0.15s system 99% cpu 41.466 total
macos $ time ruby n_queens.rb
ruby n_queens.rb  41.23s user 0.15s system 99% cpu 41.450 total

Third Edit: 14 Queens (365,596 solutions)

Ran it as NxN code for a 14x14 board for fun.

macos $ time ruby n_queens.rb
ruby n_queens.rb  290.32s user 0.96s system 99% cpu 4:51.53 total

The Code

Here is the code on GitHub for anyone interested:

Before going to sleep, ran this for 15 queens (2,279,184 solutions):

macos $ time ruby n_queens.rb
ruby n_queens.rb  2145.80s user 6.36s system 16% cpu 3:41:05.54 total

Not optimized, of course..... only the first attempt .... I'm not planning to optimize further as I have too many other practical tasks and projects to do ..... but I may run 16x16 for fun which I estimate will take about 4 hours on my M3,, and over 6 hours on my M1 ...

Can you share some of your project ideas? It'd be interesting to learn myself as well.

Normally, I am busy on non-IT projects which includes (1) charity work helping a 35+ year old building modernize their 8 elevators and (2) optimizing my metabolic health.

The first project is winding down. The second project is my favorite and most important.

However, today I have used ChatGPT 4o to help me to start optimize this N queens problem for faster results (prior code was not optimized at all):

# Choose which method to solve the n-queens problem
# Uncomment one of the following lines to choose the solving method:

# Standard backtracking with pruning (fast for moderate board sizes)
# solutions = solve_n_queens_fast($number_of_queens)

# Optimized bitmask solution (faster for larger board sizes)
# solutions = solve_n_queens_bitmask($number_of_queens)

# Parallel execution (useful for larger board sizes, e.g., 12x12 or greater)
solutions = solve_n_queens_parallel($number_of_queens)

Parallel Optimization with # Threads = Board Size

M1 MacStudio

MacStudio:n_queens tim$ ruby --jit n_queens.rb 15
Number of solutions: 2,279,184 for 15 Queens in 88.56855s

M3 MacBookAir

m3_macos $ ruby --jit n_queens.rb  15
Number of solutions: 2,279,184 for 15 Queens in 2 minutes, 9 seconds

Optimized bitmask solution

M1 MacStudio

MacStudio:n_queens tim$ ruby --jit n_queens.rb 15
Number of solutions: 2,279,184 for 15 Queens in 20.244419s

M3 MacBookAir

m3 macos $ ruby --jit n_queens.rb  15
Number of solutions: 2,279,184 for 15 Queens in 29.293476s

and so forth.

See GitHub Repo (Added ChatGPT Suggestion Optimizations)

AdditionalTesting

M1 MacStudio

MacStudio:n_queens tim$ ruby --jit n_queens.rb 16
Number of solutions: 14,772,512 for 16 Queens in 2 minutes, 29 seconds

M3 MacBookAir

m3 macos $ ruby --jit n_queens.rb 16                                    
Number of solutions: 14,772,512 for 16 Queens in 3 minutes, 26 seconds

17 Queens is running now....

Addressing your actual question: "Why am I unable to translate my logic to code?".

I suspect the issue is in the vagueness of "... reset and start again". Exactly where should you start again?

Obviously, if you start with a blank board, you will keep trying the same thing over and over, which can never succeed. You need to carry forward some "state" information that avoids repeating the same situation again. And you need to be able to continue from the same place, so you don't waste the effort so far.

Suppose you have reached the situation that you have placed Q1 at (1,1) (col,row), and Q2 at (2,3): no conflict there. You start on col 3, placing Q3 at (3,1). Conflict with Q1. You don't discard Q1 and Q2, you try again with Q3 at (3,2), (3,3) etc.

But you find that Q3 has conflicts all the way down. Where do you reset to? The answer is that you have back up just one place, and put Q2 at (2,4), and start column 3 over again. No conflict there. But when you reach column 4, every row conflicts, and you have run out of space.

So you need to keep a history of where all the attempts have reached, and backtrack as far as you need to go to continue, but only that far.

That is very similar to walking a tree structure, except that this is a "virtual" tree -- you are creating the tree from the partial successes. When the tree becomes four levels deep, you don't need to place any more Queens, and you have a valid result.

This is a seriously sub-optimal algorithm which can be optimised in several ways, but the principal message stands: your "reset" needs to retain enough state information to step back through to the last incomplete attempt, and move on from there.

The Eagle has landed!

M3 MacBookAir using Optimized bitmask solution

m3 macos $ ruby --jit n_queens.rb 17
Number of solutions: 95,815,104 for 17 Queens in 4 hours, 8 minutes, 50 seconds using Optimized bitmask solution

I am further optimizing for large n by combining bitmasking with parallelism. Testing now.

N-Queens Optimization (GitHub, Ruby) - New Topic Here:

Dropping out of this thread now that I am fully collaborating with ChatGPT 4o on N-Queens optimizations - sorry for the distraction working on this collaboration with an generative AI; I'm having a blast collaborating with "it" .. :slight_smile:

My last word on this topic (will post updates in another optimization topic)....

@Ihattaren .... my thoughts.

This N- Queens task is not really a project for beginning coders. The coding is not that difficult; but the real purpose of this problem is to experiment and learn optimization methods.

In other words, this is a task for experienced coders who already know how to code and write algorithms, but wish to tweak and optimize a recursive process (using modern processing tools and methods, if they wish of course).

That's my take on the N Queens task after working on it for a few days. It is a fun optimization project, especially as N approaches 20, at least on my desktop machine and notebook.

Currently, I have got the 8 Queens solution down to a bit less than 17 ms on my M3 MacBookAir (parallel bitmasking) without adding optimizations for symmetry and reflection.

Footnote

Did not meet this success collaborating with ChatGPT 4o on trying to combine both parallel processing and symmetry. Combining these methods resulted in missed solutions, perhaps because of symmetry and parallelism conflicts and/or race conditions.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.