Here's the solution I came up with before submitting this idea:
# spiral.rb
# RubyQuiz #109
# Bob Showalter
class Integer
def odd?
self % 2 == 1
end
end
class Spiral
# order must be > 0
def initialize(order)
raise ArgumentError, "order must be > 0" unless order.to_i > 0
@order = order
end
# writes the spiral to stdout
def output
puts "\n"
0.upto(@order - 1) do |r|
row_for(@order, r)
puts "\n\n"
end
end
private
# emits row r for spiral of order p
def row_for(p, r)
if p <= 1
cell(0)
elsif p.odd?
if r == p - 1
row(p)
else
row_for(p - 1, r)
col(p, r)
end
else
if r == 0
row(p)
else
col(p, r)
row_for(p - 1, r - 1)
end
end
end
# emits the full row (top or bottom) for spiral of order p
def row(p)
x = p * (p - 1)
y = x + p - 1
x.upto(y) {|i| cell(p.odd? ? x - i + y : i) }
end
# emits the single column cell for row r of spiral of order p
def col(p, r)
x = p * (p - 1)
r = p - r - 1 if p.odd?
cell(x - r)
end
# emits a single cell
def cell(i)
printf ' %3d ', i
end
end
n = (ARGV.first || 3).to_i
Spiral.new(n).output