How to resolve the algorithm N-queens problem step by step in the Ruby programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm N-queens problem step by step in the Ruby programming language

Table of Contents

Problem Statement

Solve the eight queens puzzle.

You can extend the problem to solve the puzzle with a board of size   NxN. For the number of solutions for small values of   N,   see   OEIS: A000170.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm N-queens problem step by step in the Ruby programming language

The provided Ruby code contains two different solutions for the "N-Queens" problem, where the goal is to place n queens on an n x n chessboard in a way that no two queens threaten each other, meaning they are not in the same row, column, or diagonal.

n_queens Function:

  • This function takes an integer n as input, where n represents the size of the chessboard.
  • It follows a mathematical sequence to generate a list of numbers nums. This list will determine the row placement of queens on the chessboard.
  • The sequence considers various conditions based on the remainder when n is divided by 12.
  • Finally, it returns a string representation of the chessboard with queens placed in the correct positions.

Queen Class:

  • This class uses backtracking to solve the N-Queens problem.
  • It initializes with a num parameter, which defaults to 8 (for an 8x8 chessboard) and an out parameter to control whether the solutions are printed.
  • It defines private helper methods for checking diagonal threats and solving the problem.
  • The solve method recursively tries different row placements for queens and checks for conflicts.
  • When a valid solution is found, it increments a count variable and prints the solution if out is true.

Implementation:

  • The code loops through different values of n and calls either the n_queens function or the Queen class to solve the N-Queens problem.
  • For small values of n (1 to 6), it prints the solutions and counts the total number of solutions.
  • For larger values of n (7 to 12), it disabl es printing and only counts the solutions.

Source code in the ruby programming language

# 1. Divide n by 12. Remember the remainder (n is 8 for the eight queens
#    puzzle).
# 2. Write a list of the even numbers from 2 to n in order.
# 3. If the remainder is 3 or 9, move 2 to the end of the list.
# 4. Append the odd numbers from 1 to n in order, but, if the remainder is 8,
#    switch pairs (i.e. 3, 1, 7, 5, 11, 9, …).
# 5. If the remainder is 2, switch the places of 1 and 3, then move 5 to the
#    end of the list.
# 6. If the remainder is 3 or 9, move 1 and 3 to the end of the list.
# 7. Place the first-column queen in the row with the first number in the
#    list, place the second-column queen in the row with the second number in
#    the list, etc.


def n_queens(n)
  if n == 1
    return "Q"
  elsif n < 4
    puts "no solutions for n=#{n}"
    return ""
  end
 
  evens = (2..n).step(2).to_a
  odds = (1..n).step(2).to_a
 
  rem = n % 12  # (1)
  nums = evens  # (2)
 
  nums.rotate if rem == 3 or rem == 9  # (3)
 
  # (4)
  if rem == 8
    odds = odds.each_slice(2).flat_map(&:reverse)
  end
  nums.concat(odds)
 
  # (5)
  if rem == 2
    nums[nums.index(1)], nums[nums.index(3)] = nums[nums.index(3)], nums[nums.index(1)]
    nums << nums.delete(5)
  end
 
  # (6)
  if rem == 3 or rem == 9
    nums << nums.delete(1)
    nums << nums.delete(3)
  end
 
  # (7)
  nums.map do |q|
    a = Array.new(n,".")
    a[q-1] = "Q"
    a*(" ")
  end
end
 
(1 .. 15).each {|n| puts "n=#{n}"; puts n_queens(n); puts}

class Queen
  attr_reader :count
  
  def initialize(num=8, out=true)
    @num   = num
    @out   = out
    @row   = *0...@num
    @frame = "+-" + "--" * @num + "+"
    @count = 0
    add = Array.new(2 * @num - 1, true)       # \ direction check
    sub = Array.new(2 * @num - 1, true)       # / direction check
    solve([], add, sub)
  end
  
  private
  def solve(row, add, sub)
    y = row.size
    if y == @num
      print_out(row) if @out
      @count += 1
    else
      (@row-row).each do |x|
        next unless add[x+y] and sub[x-y]
        add[x+y] = sub[x-y] = false
        solve(row+[x], add, sub)
        add[x+y] = sub[x-y] = true
      end
    end
  end
  
  def print_out(row)
    puts @frame
    row.each do |i|
      line = @num.times.map {|j| j==i ? "Q " : ". "}.join
      puts "| #{line}|"
    end
    puts @frame
  end
end

(1..6).each do |n|
  puzzle = Queen.new(n)
  puts " #{n} Queen : #{puzzle.count}"
end

(7..12).each do |n|
  puzzle = Queen.new(n, false)                # do not display
  puts " #{n} Queen : #{puzzle.count}"
end

  

You may also check:How to resolve the algorithm Trabb Pardo–Knuth algorithm step by step in the Ksh programming language
You may also check:How to resolve the algorithm Vigenère cipher step by step in the Action! programming language
You may also check:How to resolve the algorithm Add a variable to a class instance at runtime step by step in the Io programming language
You may also check:How to resolve the algorithm Date manipulation step by step in the Lua programming language
You may also check:How to resolve the algorithm Sudoku step by step in the SAS programming language