[QUIZ] The Golden Fibonacci Ratio (#69)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion.

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Enrique Meza C

You may have noticed that if you have a Golden Rectangle and you cut off a
square with side lengths equal to the length shorter rectangle side, then what
remains is another Golden Rectangle.

This could go on forever. You can just keep cutting off these big squares and
getting smaller and smaller Golden rectangles.

The idea with the Fibonacci series is to do the same thing in reverse. So the
quiz:

What you do is start with a square (1 by 1), find the longer side, and add a
square of that size to the whole thing to form a new rectangle.

So when we start with a 1 by 1 square the longest side is one, so we add another
square to it. Now we have a 2 by 1 rectangle

Then the longest side is two, so we connect a 2 by 2 square to our 2 by 1
rectangle to get a 3 by 2 rectangle. This continues, and the sides of the
rectangle will always be a successive Fibonacci number. Eventually the
rectangle will be very close to a Golden Rectangle.

I will do a few steps to let you see it in action:

  ###
  # # 1 by 1, so we add 1 by 1 to get...
  ###
  
  ######
  # ## # Now it is 2 by 1, so we add 2 by 2 to get......
  ######
  
  ######
  # ## #
  ######
  ######
  # # Now it is 2 by 3, so we add a 3 by 3 to get.......
  # #
  # #
  # #
  ######
  
  ###############
  # ## ## #
  ####### #
  # ## #
  # ## # Now it is 3 by 5, so we would add a 5 by 5 square.
  # ## #
  # ## #
  ###############

So the task is visualisation of the Fibonacci series ?

···

On 3/3/06, Ruby Quiz <james@grayproductions.net> wrote:

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Enrique Meza C

You may have noticed that if you have a Golden Rectangle and you cut off a
square with side lengths equal to the length shorter rectangle side, then what
remains is another Golden Rectangle.

This could go on forever. You can just keep cutting off these big squares and
getting smaller and smaller Golden rectangles.

The idea with the Fibonacci series is to do the same thing in reverse. So the
quiz:

What you do is start with a square (1 by 1), find the longer side, and add a
square of that size to the whole thing to form a new rectangle.

So when we start with a 1 by 1 square the longest side is one, so we add another
square to it. Now we have a 2 by 1 rectangle

Then the longest side is two, so we connect a 2 by 2 square to our 2 by 1
rectangle to get a 3 by 2 rectangle. This continues, and the sides of the
rectangle will always be a successive Fibonacci number. Eventually the
rectangle will be very close to a Golden Rectangle.

I will do a few steps to let you see it in action:

        ###
        # # 1 by 1, so we add 1 by 1 to get...
        ###

        ######
        # ## # Now it is 2 by 1, so we add 2 by 2 to get......
        ######

        ######
        # ## #
        ######
        ######
        # # Now it is 2 by 3, so we add a 3 by 3 to get.......
        # #
        # #
        # #
        ######

        ###############
        # ## ## #
        ####### #
        # ## #
        # ## # Now it is 3 by 5, so we would add a 5 by 5 square.
        # ## #
        # ## #
        ###############

Here are my two versions. The first is my first pass. The second is a
minor refactoring; a bit longer but I think expresses intent a bit better.

Harley Pebley

···

#
# Version 1
#
$eol = '~'
$corner = '+'
$horiz = '-'
$vert = '|'
$white = ' '

def gen_fib_box(aStart, aLevel, aCount)
   if aLevel < aCount then
     if aStart.length < 2 then
       lNewBox = $corner
     else
       lLastSize = aStart[aStart.length-1].split($eol).first.length
       lNextToLastSize = aStart[aStart.length-2].split($eol).first.length
       lNewSize = lLastSize + lNextToLastSize
       i = 0
       lNewBox = ''
       lNewSize.times do
         i = i + 1
         if (i == 1) or (i == lNewSize) then
    lNewBox = lNewBox + $corner + $horiz * (lNewSize-2) + $corner + $eol
         else
    lNewBox = lNewBox + $vert + $white * (lNewSize-2) + $vert + $eol
         end
       end
       lNewBox.chop!
     end
     aStart.push(lNewBox)
     gen_fib_box(aStart, aLevel+1, aCount)
     aStart
   end
end

if ARGV.empty? then
   lDepth = rand(10)+1
else
   lDepth = ARGV[0].to_i
end

boxes = gen_fib_box([], 0, lDepth)
output = []
boxes.each do |box|
   lines = box.split($eol)
   if (output.length == 0) or (lines.length == output.first.length) then
     lines.each do |inLine|
       output.push(inLine)
     end
   else
     i = 0
     output.length.times do
       output[i] = output[i]+lines[i]
       i = i + 1
     end
   end
end
puts output

#
# Version 2
#
$eol = '~'
$corner = '+'
$horiz = '-'
$vert = '|'
$white = ' '

def ascii_square(aSize)
   if aSize < 2 then
     result = $corner
   else
     i = 0
     result = ''
     aSize.times do
       i = i + 1
       if (i == 1) or (i == aSize) then
         result = result + $corner + $horiz * (aSize-2) + $corner + $eol
       else
         result = result + $vert + $white * (aSize-2) + $vert + $eol
       end
     end
     result.chop!
   end
   result
end

def gen_squares(aSizes)
   result = []
   aSizes.each do |lSize|
     result.push(ascii_square(lSize))
   end
   result
end

def fibonacci(aFibs, aDepth)
   if aFibs.length < aDepth then
     if aFibs.length < 2 then
       aFibs.push(1)
     else
       aFibs.push(aFibs[aFibs.length-1] + aFibs[aFibs.length-2])
     end
     fibonacci(aFibs, aDepth)
     aFibs
   end
end

if ARGV.empty? then
   lDepth = rand(10)+1
else
   lDepth = ARGV[0].to_i
end

lFibs = fibonacci([], lDepth)
boxes = gen_squares(lFibs)
output = []
boxes.each do |box|
   lines = box.split($eol)
   if (output.length == 0) or (lines.length == output.first.length) then
     lines.each do |inLine|
       output.push(inLine)
     end
   else
     i = 0
     output.length.times do
       output[i] = output[i]+lines[i]
       i = i + 1
     end
   end
end
puts output

I used this quiz as an excuses to get Ncurses-ruby running on my
Windows box. It was fairly painless, once I found PDCurses. I used
panel borders to draw the boxes, and animated the thing as it grows.
I also added a bunch of command line options for windows:
-resize [x y] will change the window size to fit a bigger rectangle.
-newwin [x y] will launch a new window, then resize (if you don't want
to mess up your current command window.
I didn't add the equivalent commands for *nix boxen, it's been too
long since i used one to remember the right commands.
The program works under windows and cygwin. I'd appreciate it if
someone lets me know if it works ok under linux or mac.

-Adam

#----- goldrect.rb

···

On 3/3/06, Ruby Quiz <james@grayproductions.net> wrote:

The idea with the Fibonacci series is to do the same thing in reverse. So the
quiz:

What you do is start with a square (1 by 1), find the longer side, and add a
square of that size to the whole thing to form a new rectangle.

#
# Submission for Ruby Quiz #69
# by Adam Shelly
#
require 'ncurses'

class FibBox
  Direction=[:up,:left,:down,:right]
  @@boxes =

  def self.moveall y,x
    @@boxes.each{|f| f.moverel(y,x,true)}
    @@boxes.each{|b| b.unhide}
  end
  def self.animate isize=1
    size = [isize,isize]
    f = FibBox.new(Direction[dir=2],size,[0,0])
    while true
      n = size.max
      pos = [0,0]
      pos[0]+=size.min if dir==2
      pos[1]+=size.min if dir==3
      n==size[1] ? size[0]+=n : size[1]+=n
      break if (size[0] > Ncurses.LINES) || (size[1] > Ncurses.COLS)
      f = FibBox.new(Direction[dir],[n,n],pos)
      dir=(dir+1)%4
    end
  end

  def initialize dir,size,pos
    @size = size
    @pos = pos
    func = lambda{FibBox.moveall(0,1)} if dir==:left
    func = lambda{FibBox.moveall(1,0)} if dir==:up
    case dir
      when :left, :right
        target = @size[1]
        parms=[@size[0],1]+@pos
        animate=1
      when :down, :up
        target = @size[0]
        parms=[1,@size[1]]+@pos
        animate=0
    end
    func.call if func
    win = Ncurses::WINDOW.new(*parms)
    @panel=win.new_panel
    show
    while parms[animate]!=target
      sleep(0.01)
      parms[animate]+=1
      func.call if func
      Ncurses::Panel.update_panels
      Ncurses.doupdate()
      resize(*parms)
    end
    @@boxes<<self
  end

  def hide
      @panel.window.border(*([' '[0]]*8))
  end
  def unhide
      @panel.window.border(*([0]*8))
  end
  def show
      unhide
      Ncurses::Panel.update_panels
      Ncurses.doupdate()
      sleep(0.1/@size[0]) #sleep less when box takes longer to draw
  end
  def resize(sy,sx,ly,lx)
    nw=Ncurses::WINDOW.new(sy,sx,ly,lx)
    exit(0) if !nw
    w = @panel.window
    @panel.replace(nw)
    w.delete
    show
  end
  def moverel(dy,dx,keephidden=false)
    hide
    @pos[0]+=dy
    @pos[1]+=dx
    @panel.move(*@pos)
    show unless keephidden
  end
end

if __FILE__ == $0
  if (ARGV[0].to_i)>0
    size = ARGV.shift.to_i
  end
  if RUBY_PLATFORM =~ /mswin/
    case ARGV[0]
      when '-h', '-?'
        puts "usage: #{$0} [size] [-newwin||-resize] [x y]"
        puts " size: initial box size (default 1)"
        puts " -resize: resizes your screen to x,y (default 150x90)"
        puts " -newwin: launches program in a new resized window"
        exit
      when '-newwin'
      `start /WAIT ruby #{$0} #{size||1} -resize #{ARGV[1]} #{ARGV[2]}`
       exit
      when '-resize'
        `mode con cols=#{ARGV[1]||150} lines=#{ARGV[2]||90}`
    end
  end
  Ncurses.initscr
  Ncurses.noecho
  FibBox.animate size||1
  Ncurses.stdscr.getch
end

Hi,
the description is really exciting :>
But the main task is for me not clear too.

--verbose please

Correct. In block format.

James Edward Gray II

···

On Mar 3, 2006, at 8:06 AM, Rudolfs Osins wrote:

So the task is visualisation of the Fibonacci series ?

Under linux, I have installed ncurses-ruby-1.0, just now and tried
this program.
The rectangles are drawn fairly satisfactorily , but I loose control
on the xterminal, and the bash prompt ovewrites on the rectangles. I
am forced to close the xterminal. I have to still understand the
program.
Prasad

···

On 3/8/06, Adam Shelly <adam.shelly@gmail.com> wrote:

On 3/3/06, Ruby Quiz <james@grayproductions.net> wrote:
> The idea with the Fibonacci series is to do the same thing in reverse. So the
> quiz:
>
> What you do is start with a square (1 by 1), find the longer side, and add a
> square of that size to the whole thing to form a new rectangle.

I used this quiz as an excuses to get Ncurses-ruby running on my
Windows box. It was fairly painless, once I found PDCurses. I used
panel borders to draw the boxes, and animated the thing as it grows.
I also added a bunch of command line options for windows:
-resize [x y] will change the window size to fit a bigger rectangle.
-newwin [x y] will launch a new window, then resize (if you don't want
to mess up your current command window.
I didn't add the equivalent commands for *nix boxen, it's been too
long since i used one to remember the right commands.
The program works under windows and cygwin. I'd appreciate it if
someone lets me know if it works ok under linux or mac.

-Adam

#----- goldrect.rb
#
# Submission for Ruby Quiz #69
# by Adam Shelly
#
require 'ncurses'

class FibBox
  Direction=[:up,:left,:down,:right]
  @@boxes =

  def self.moveall y,x
    @@boxes.each{|f| f.moverel(y,x,true)}
    @@boxes.each{|b| b.unhide}
  end
  def self.animate isize=1
    size = [isize,isize]
    f = FibBox.new(Direction[dir=2],size,[0,0])
    while true
      n = size.max
      pos = [0,0]
      pos[0]+=size.min if dir==2
      pos[1]+=size.min if dir==3
      n==size[1] ? size[0]+=n : size[1]+=n
      break if (size[0] > Ncurses.LINES) || (size[1] > Ncurses.COLS)
      f = FibBox.new(Direction[dir],[n,n],pos)
      dir=(dir+1)%4
    end
  end

  def initialize dir,size,pos
    @size = size
    @pos = pos
    func = lambda{FibBox.moveall(0,1)} if dir==:left
    func = lambda{FibBox.moveall(1,0)} if dir==:up
    case dir
      when :left, :right
        target = @size[1]
        parms=[@size[0],1]+@pos
        animate=1
      when :down, :up
        target = @size[0]
        parms=[1,@size[1]]+@pos
        animate=0
    end
    func.call if func
    win = Ncurses::WINDOW.new(*parms)
    @panel=win.new_panel
    show
    while parms[animate]!=target
      sleep(0.01)
      parms[animate]+=1
      func.call if func
      Ncurses::Panel.update_panels
      Ncurses.doupdate()
      resize(*parms)
    end
    @@boxes<<self
  end

  def hide
      @panel.window.border(*([' '[0]]*8))
  end
  def unhide
      @panel.window.border(*([0]*8))
  end
  def show
      unhide
      Ncurses::Panel.update_panels
      Ncurses.doupdate()
      sleep(0.1/@size[0]) #sleep less when box takes longer to draw
  end
  def resize(sy,sx,ly,lx)
    nw=Ncurses::WINDOW.new(sy,sx,ly,lx)
    exit(0) if !nw
    w = @panel.window
    @panel.replace(nw)
    w.delete
    show
  end
  def moverel(dy,dx,keephidden=false)
    hide
    @pos[0]+=dy
    @pos[1]+=dx
    @panel.move(*@pos)
    show unless keephidden
  end
end

if __FILE__ == $0
  if (ARGV[0].to_i)>0
    size = ARGV.shift.to_i
  end
  if RUBY_PLATFORM =~ /mswin/
    case ARGV[0]
      when '-h', '-?'
        puts "usage: #{$0} [size] [-newwin||-resize] [x y]"
        puts " size: initial box size (default 1)"
        puts " -resize: resizes your screen to x,y (default 150x90)"
        puts " -newwin: launches program in a new resized window"
        exit
      when '-newwin'
      `start /WAIT ruby #{$0} #{size||1} -resize #{ARGV[1]} #{ARGV[2]}`
       exit
      when '-resize'
        `mode con cols=#{ARGV[1]||150} lines=#{ARGV[2]||90}`
    end
  end
  Ncurses.initscr
  Ncurses.noecho
  FibBox.animate size||1
  Ncurses.stdscr.getch
end

Basically the goal is to visualize the sequence. Perhaps you want to take a parameter and show the blocks that many steps in, or maybe you want to make it more like geek cinema and watch the sequence progress block by block...

James Edward Gray II

···

On Mar 3, 2006, at 8:25 AM, Robert Retzbach wrote:

Hi,
the description is really exciting :>
But the main task is for me not clear too.

Use '#tset -s' to reset the xterminal.

I tried it and works fine.

···

El jue, 09-03-2006 a las 01:35 +0900, G.Durga Prasad escribió:

Under linux, I have installed ncurses-ruby-1.0, just now and tried
this program.
The rectangles are drawn fairly satisfactorily , but I loose control
on the xterminal, and the bash prompt ovewrites on the rectangles. I
am forced to close the xterminal. I have to still understand the
program.
Prasad

Sample output for my solution, this may be a little clearer than
James' (still requires monospace font, of course):

$ ruby fibonacci_block.rb 6

···

On 3/3/06, James Edward Gray II <james@grayproductions.net> wrote:

On Mar 3, 2006, at 8:25 AM, Robert Retzbach wrote:

> Hi,
> the description is really exciting :>
> But the main task is for me not clear too.

Basically the goal is to visualize the sequence. Perhaps you want to
take a parameter and show the blocks that many steps in, or maybe you
want to make it more like geek cinema and watch the sequence progress
block by block...

James Edward Gray II

###########################
# # # # #
##### # #
# # # #
# # # #
# # # #
########### #
# # #
# # #
# # #
# # #
# # #
# # #
# # #
# # #
# # #
###########################

Jacob Fugal

> Under linux, I have installed ncurses-ruby-1.0, just now and tried
> this program.
> The rectangles are drawn fairly satisfactorily ,

I forgot to mention that it looks best if you can set your terminal to
a square font, like Terminal 8x8 under Windows.

but I loose control

> on the xterminal, and the bash prompt ovewrites on the rectangles. I
> am forced to close the xterminal. I have to still understand the
> program.
> Prasad

Use '#tset -s' to reset the xterminal.

When should that be issued? Should the ruby script call it before it exits?

I tried it and works fine.

Cool. Thanks for checking.

···

On 3/8/06, Enrique Meza C <emeza@cdi.gob.mx> wrote:

El jue, 09-03-2006 a las 01:35 +0900, G.Durga Prasad escribió:

It might be good to note that multiple layouts are possible. For example, the above could also spiral as follows:

···

On Mar 3, 2006, at 11:50 AM, Jacob Fugal wrote:

On 3/3/06, James Edward Gray II <james@grayproductions.net> wrote:

On Mar 3, 2006, at 8:25 AM, Robert Retzbach wrote:

Hi,
the description is really exciting :>
But the main task is for me not clear too.

Basically the goal is to visualize the sequence. Perhaps you want to
take a parameter and show the blocks that many steps in, or maybe you
want to make it more like geek cinema and watch the sequence progress
block by block...

James Edward Gray II

Sample output for my solution, this may be a little clearer than
James' (still requires monospace font, of course):

$ ruby fibonacci_block.rb 6

###########################
# # # # #
##### # #
# # # #
########### #
# # #
###########################

###########################
# # #
# ###########
# # # # #
# ##### #
# # # #
###########################

James Edward Gray II

Good point. I actually like that one better, and have altered my code
to produce it. :slight_smile:

Jacob Fugal

···

On 3/3/06, James Edward Gray II <james@grayproductions.net> wrote:

It might be good to note that multiple layouts are possible. For
example, the above could also spiral as follows:

###########################
# # #
# # #
# # #
# # #
# # #
# # #
# # #
# # #
# # #
# ###########
# # # # #
# ##### #
# # # #
# # # #
# # # #
###########################

Jacob Fugal wrote:

···

On 3/3/06, James Edward Gray II <james@grayproductions.net> wrote:

It might be good to note that multiple layouts are possible. For
example, the above could also spiral as follows:

###########################
# # #
# ###########
# # # # #
# ##### #
# # # #
###########################
   
Good point. I actually like that one better, and have altered my code
to produce it. :slight_smile:

Jacob Fugal

Hi, I'm new to the ruby (and the quiz). I did a quick solution that has a little cleaner output like so:

+---------------+---------+

              > >
              +-+-+-----+
              > > > >
              +-+-+ |
              > > >

+---------------+---+-----+

i guess the next step is to animate it.
--
Brian Mattern

Of course, when rendering large numbers of squares it can be nice to
shrink things a bit:

11:02:56 - tora@Eustacia:~/ruby/fibonacci

···

ruby gfr.rb 8 1

+++--+-------+--------------------+
+++ | | |

> > > >

+-+--+ | |

   > > >
   > > >
   > > >
   > > >

+----+-------+ |

           > >
           > >
           > >
           > >
           > >
           > >
           > >
           > >
           > >
           > >
           > >
           > >

+------------+--------------------+

or make them larger...

ruby gfr.rb 3 3

+--+--+

> >
> >

+--+--+

    >
    >
    >
    >
    >

+-----+

(crosses fingers that they render correctly)