Marcel Ward
1/14/2007 3:13:00 PM
On 12/01/07, Ruby Quiz <james@grayproductions.net> wrote:
> Write a Ruby program to print out a "spiral" of numbers that fill a NxN square.
> Your program will take a single argument to specify the dimensions of the square
> (1 or higher). The number zero represents the center of the spiral, and the
> succeeding integers spiral out in a clockwise (or counterclockwise; your choice)
> direction from the center until the square is filled.
>
> Your program should write the output line by line, without using an array to
> build up the data first.
Ok, I like a challenge and my maths needed some dusting down.
Here is my solution, after a fair bit of scribbling on paper to work
out the formula for sprial_value_at(x,y).
I found it a bit frustrating that ranges in Ruby can only be
ascending; but soon found that we have #downto, which achieves the
desired result.
Thanks to Bob & James for setting this quiz.
Marcel
#! /usr/bin/env ruby
#
# Marcel Ward <wardies ^a-t^ gmaildotcom>
# Sunday, 14 January 2007
# Solution for Ruby Quiz number 109 - Number Spiral
# Prints a clockwise spiral, starting with zero at the centre (0,0).
# Note, here x increases to the east and y increases to the north.
def spiral(size)
# maximum -ve/+ve reach from the centre point "0" at (0,0)
neg_reach = -pos_reach = size/2
# we miss out the bottom/left sides for even-sized spirals
neg_reach += 1 if size % 2 == 0
# Compute width to allocate a cell based on the max value printed
cell_width = (size**2 - 1).to_s.size + 3
pos_reach.downto(neg_reach) do
|y|
spiral_line((neg_reach..pos_reach), y, cell_width)
end
end
def spiral_line(x_range, y, cell_width)
x_range.each do
|x|
print spiral_value_at(x, y).to_s.center(cell_width)
end
puts
end
# calculate the value in the spiral at location (x,y)
def spiral_value_at(x, y)
if x + y > 0 # top/right side
if x > y # right side
4 * x**2 - x - y
else # top side
4 * y**2 - 3 * y + x
end
else # bottom/left side
if x < y # left side
4 * x**2 - 3 * x + y
else # bottom side
4 * y**2 - y - x
end
end
end
spiral(10)