# [QUIZ][SOLUTION] The Golden Fibonacci Ration (#69)

B

#### Brian Mattern

--------------010602090507000003020209
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Here is my text based (and animated) solution.

The parameters are:
ruby 69.rb [number of steps] [scaling factor]

by default, it shows 6 steps with a scaling factor of 2. (The square
with side i is scaled to (m * i + 1) where m is the scaling factor and
the extra +1 accounts for the fact that there are no 0 width lines in
ascii art).
--
Brian Mattern

--------------010602090507000003020209
Content-Type: text/plain;
name="69.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="69.rb"

#
# A helper class to generate the fibonacci sequence
#
# To get the ith fibonacci number simply call Fibonacci
# You can also get a range with Fibonacci[start..finish]
# So, Fibonacci[0..10] = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
#
# The class calculates only those numbers it needs, at caches them for
# future retrieval.
#
class Fibonacci
@@series = [1,1]
@@len = 2

def self.[](i)
val = i

i = val.max if i.class == Range
if i >= @@len
(i - @@len + 1).times { |j|
@@series << @@series[-1] + @@series[-2]
}
@@len = i + 1
end

@@series[val]
end
end

#
# A class to animate the fibonacci sequence
class FibonacciAnimator

# Fetch our series and set up an empty array to draw on
#
# Note that due to the lack of 0 width lines in ascii art,
# we transform x -> mx+1 (where m is a scaling factor)
def initialize(num_steps = 6, scale = 2)
@num_steps = num_steps.to_i
@scale = scale.to_i
@series = Fibonacci[0..(@num_steps-1)].collect{ |x| x*@scale + 1 }

@graph = []
@height = @series[-1]
@width = @height + (@series[-2] || 0)
@height.times do |row|
@graph << Array.new(@width).fill(" ")
end
end

# Calculate the top right location for each square
def build_steps
row = col = 0
dir = -1

prev = 0
@steps = []

# since we don't know where the smallest square should start, we reverse
# and calculate from large to small
@series.reverse.each do |size|
case(dir)
when 0
col += prev - 1
when 1
row += prev - 1
col += prev - size
when 2
row += prev - size
col -= size - 1
when 3
row -= size - 1
end

@steps << [size, row, col]

prev = size
dir += 1
dir %= 4
end

# flip our steps so they run from small to large
@steps.reverse!

@built = true
end

# actually draw (or animate) the fibonacci representation
# for animation, fps == frames per second
def draw(animate = false, fps = 2)
build_steps unless @built
@steps.each do |step|
draw_square(*step)
if animate
print "\033c" # clear the screen
puts self
sleep(1.0 / fps)
end
end

puts self unless animate
end

# draw a size x size square with its top left corner at row, col
def draw_square(size, row, col)
raise "Cannot draw outside graph bounds." if row < 0 or col < 0 or row >= @height or col >= @width or row + size > @height or col + size > @width

size.times do |i|
hor = "-"
vert = "|"
hor = vert = "+" if i == 0 or i + 1 == size

[[row, col + i], [row + size - 1, col + i]].each do |coord|
x, y = coord
@graph[x][y] = hor unless @graph[x][y] == "+"
end

[[row + i, col], [row + i, col + size - 1]].each do |coord|
x, y = coord
@graph[x][y] = vert unless @graph[x][y] == "+"
end
end
end

def to_s
@graph.collect{ |row| row.join("") }.join("\n")
end
end

fp = FibonacciAnimator.new(*ARGV)
fp.draw(true)

--------------010602090507000003020209--