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)
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 Gray II
···
On Jun 15, 2006, at 1:34 PM, Logesh Pillay wrote:
I'd appreciate suggestions how to improve it.
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 Yandell
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" }
> 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
def initialize
@n = 8
@board = [nil] * (@n + 1)
enddef 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
# 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)
···
On Fri, 2006-06-16 at 06:05 +0900, James Edward Gray II wrote:
On Jun 15, 2006, at 1:34 PM, Logesh Pillay wrote:
endHope that helps.
James Edward Gray II
--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk