Hi all!

This is my first partecipation to Ruby Q… I developed a pretty messy

solution for clockwise (ck) solution. When I started to tackle the

counter-ck solution I started messing around with lambdas everywhere,

but eventually I found out that I just could reverse each line of a ck

solution to have the correct output. Also I didnt code the ck/cck

picking part, so you need to change it manually in initialize

My approach is still of the kind “over-use all the power of the

language” to crack the solution instead of a more reccomendable

mathematical one. But there is time to it.

I tried to comment my code extensively, maybe to understand it you need

to go through the example spiral output and check what it does …

I loved all the really compact solutions that have been posted so far,

keep them coming!

This community just rocks!

Take care you all!

Francesco Levorato aka flevour

#! /usr/bin/env ruby

# Francesco Levorato aka flevour <flevour ^a-t^ gmaildotcom>

# Sunday, 14 January 2007

# Solution for Ruby Q. number 109 - Number Spiral

class Array

def decrease_all

self.map! { |x| x = x - 1}

end

def increase_all

self.map! { |x| x = x + 1}

end

def enqueue(x)

self.insert(0, x)

end

# sort of a hackish method to remove unwanted numbers from @left and

@right

# i haven’t figured out a valid reason to explain why i need to

remove these values

# but otherwise things won’t work and I haven’t time to think more on

the topic

def delete_invalid

self.map! {|x| (x > 1) ? x : nil}

self.compact!

end

end

class NumberSpiral

# this solution addresses clockwise from center to outside filling

method

# my approach is based on the observation that each row of the matrix

is composed

# of 3 parts: 0 or more columns, a series of consecutive numbers, 0

or more columns

def initialize(n, direction = :ck)

@n = n

@dim = @n*@n

# left contains the first part of a row

# right contains the third part of a row

# in a 8x8: if the row is 54,29,12,13,14,15,16,37

# left: [54, 29], right: [37]

@left = []

@right = []

# just wanted to try out this block thingie Ruby is so famous about

@format = Proc.new { |x| print sprintf("%3s", x.to_s + " ") }

@direction = direction # :ck or :cck

end

# the 3 following methods, h,l,d are were the funniest part of the

quiz: finding

# the relationships intercurring between special elements of the

spiral.

# they are used to build only the first (N/2 + 1) rows, as the other

ones are

# built according only to the data structures @left and @right

# to explain these 3 methods, define the following function

# pivot(row): returns the number at given row just before the start

of the second part

# of the row (the part containing the consecutive

numbers)

# given a row number

# returns the distance from the pivot to the first “spiral wall”

below it

# subtracts 1 not to overlap with l(x) results

# in a 8x8: given row 7 returns length from 54 down to 50

def h(x)

2*x - @n - 1

end

# given a row number

# returns the width of the next horizontal segment going from pivot

toward

# the center of the spiral

# in a 8x8: given row 6 returns length from 25 to 20

def l(x)

2 * ( x + 1 ) - @n

end

# given a row number, returns the difference between the pivot and

the number

# just at its right

# in a 8x8: given 7 returns the difference between 55 and 30

def d(x)

2 * ( l(x) + h(x) ) - 1

end

def print_me

row = @n

start = @dim - @n

# prints first row

print_row(consecutive_numbers(start))

print “\n”

```
# prepare for loop
pivot = start - 1
@left << pivot
# prints the top rows, it stops after printing the row containing
```

the zero

while(pivot >= 0) do

row = row - 1

pivot = pivot - d(row)

```
# gets middle consecutive numbers
middle = consecutive_numbers(pivot)
print_row(middle)
@left << pivot
@left.decrease_all
@right.enqueue(middle.last) # last number of consecutive series
```

will be in the right part in next iteration

@right.increase_all

```
pivot = @left.last
print "\n"
end
@left.delete_invalid
@right.delete_invalid
row = row -1
# prints the remainder of the spiral
while(row > 0) do
from= @left.pop
middle = consecutive_numbers(from, :down)
last_printed = middle.last
print_row(middle)
@right.delete_at(0)
@left.decrease_all
@right.increase_all
row = row - 1
print "\n"
end
```

end

def consecutive_numbers(n, go = :up)

array = []

(@n - @left.size - @right.size).times do

array << n

if go == :up

n = n + 1

else # go == :down

n = n - 1

end

end

array

end

def print_row(middle)

if @direction == :ck

(@left + middle + @right).each(&@format)

else

(@left + middle + @right).reverse.each(&@format)

end

end

end

if ARGV[0]

NumberSpiral.new(ARGV[0].to_i).print_me

else

puts “Call me: #{$0} <matrix_dim>\n”

end