I discovered Ruby this week. I was amazed at how easy it was to program
in it without a book or any real manual.
I’ve written the following program. It looks too much like the python
original to be good idiomatic ruby. I’d appreciate suggestions how to
improve it.
Thanks.
Logesh
#returns the ways one can place n queens on a
#chessboard of size n*n so that no queen is attacking another
#Ruby 1.8.3; 15 June 2006
def nqueens
$n = 8
$board = [nil] * ($n+1)
def choose(k)
if k > $n
print $board, “\n”
else
for i in 1…$n
$board[k] = i
choose(k + 1) if k == 1 or stillgood(k)
end
end
end
def stillgood(k)
for i in 1…k
return false if ($board[k] == $board[i]) or
(k-i == ($board[k] - $board[i]).abs)
end
return true
end
end
nqueens.choose(1)
On Jun 15, 2006, at 1:34 PM, Logesh Pillay wrote:
I’d appreciate suggestions how to improve it.
Well, I’ve tried to Rubify the code a bit. I did these things;
- Stopped defining methods in methods.
- Used a class.
- Switched the global variables to instance variables.
- Used upto() iterators.
- Got rid of print().
- Made stillgood() method name more Rubish.
- Added the application code test at the end.
The thing I think you should still do:
- Pick more meaningful variable names than @n and k.
Here’s the code.
class NQueens
def initialize
@n = 8
@board = [nil] * (@n + 1)
end
def choose(k)
if k > @n
puts @board.join
else
1.upto(@n) do |i|
@board[k] = i
choose(k + 1) if k == 1 or still_good?(k)
end
end
end
def still_good?(k)
1.upto(k - 1) do |i|
return false if (@board[k] == @board[i]) or
(k-i == (@board[k] - @board[i]).abs)
end
true
end
end
if FILE == $PROGRAM_NAME
NQueens.new.choose(1)
end
Hope that helps.
James Edward G. II
On Fri, 2006-06-16 at 06:05 +0900, James Edward G. II wrote:
On Jun 15, 2006, at 1:34 PM, Logesh Pillay wrote:
I’d appreciate suggestions how to improve it.
Well, I’ve tried to Rubify the code a bit.
If I could just make a couple of small extra suggestions,
Here’s the code.
class NQueens
class << self
def choose(k)
new.choose(k)
end
end
@board[k] = i choose(k + 1) if k == 1 or still_good?(k) end end
end
# explicit returns are a pet peeve of mine :)
def still_good(k)
!(1...k).any? do |i|
@board[k] == @board[i] or k-i == (@board[k] - @board[i]).abs
end
end
end
if FILE == $PROGRAM_NAME
NQueens.choose(1)
Just for another data point, here’s a version that I wrote ages ago
that attempts to be as Ruby-ish as possible. The board is stored in
such a way that a single line of Ruby can test if a new queen can be
placed in a given square, and solutions are yielded to a block as
they’re found. (Put a ‘break’ into the block if you only want the
first solution.)
Pete Y.
http://9cays.com
module Queens
Queen = Struct.new(:x, :y)
class Board < Array
def to_s
map {|q| “.“q.x + “X” + “.”(size-q.x-1)}.join(”\n”) + “\n”
end
def add(*q)
Board.new(self + q)
end
end
def self.solve(size = 8, queens = Board.new, &block)
if queens.size == size
yield queens
else
y = queens.size
for x in 0…size
unless queens.any? {|q| x == q.x or (x-q.x).abs == (y-
q.y).abs }
solve(size, queens.add(Queen.new(x,y)), &block)
end
end
end
end
end
Queens::solve {|q| print q.to_s, “\n” }