Forum: Ruby The Golden Fibbonacci Ratio (#69)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2006-03-05 20:48
(Received via mailing list)
Here's my solution.  It's fairly pedestrian, although the size and
aspect ratio of the ASCII-art squares are configurable.

It builds the picture as an array of strings, appending alternately to
the end of the array and to the end of each string.  The dimensions of
each added box are taken from the length of the edge to which it is to
be added.

It takes one optional argument on the commandline: an iteration count.

-mental

--- 8< ----

#!/usr/bin/ruby

CELL_WIDTH = 5
CELL_HEIGHT = 3

def box( size )
  width = size * CELL_WIDTH
  height = size * CELL_HEIGHT
  lines = ["#" * width] + ["##{ " " * ( width - 1 ) }"] * ( height - 1 )
  lines.map! { |line| line.dup }
end

lines = box( 1 )
$*[0].to_i.times do
  width = lines.first.size * CELL_HEIGHT
  height = lines.size * CELL_WIDTH
  if width > height
    lines.concat box( width / CELL_WIDTH / CELL_HEIGHT )
  else
    lines.zip box( height / CELL_WIDTH / CELL_HEIGHT ) do |line, box|
      line << box
    end
  end
end
lines.each { |line| puts "#{ line }#" }
puts "#{ lines.first }#"
5c841628b56df3a68984986e9f095d01?d=identicon&s=25 Andrew Johnson (andrew)
on 2006-03-05 21:16
(Received via mailing list)
No fancy output here, just a simple recursive version -- build the
largest
rectangle as a matrix of characters, then recursively overwrite each
smaller rectangle (from the origin).

----andrew

#!/usr/bin/ruby -w

Fib = Hash.new{|h,n|n<2?h[n]=n:h[n]=h[n-1]+h[n-2]}

def fibicle(n,dia=[])
  return dia if n == 0
  cols, rows = Fib[n+1], Fib[n]
  cols, rows = rows, cols if n%2 != 0
  cols *= 2
  (0..rows).each{dia << [" "]*cols} if dia.empty?
  (0..cols).each{|i|dia[0][i]    = i%2!=0?"_":" "}    # top
  (0..cols).each{|i|dia[rows][i] = i%2!=0?"_":" "}    # bottom
  dia[1..rows].each{|row| row[0],row[cols] = "|","|"} # sides
  fibicle(n-1,dia)
end

fibicle(ARGV[0].to_i).each{|r|puts r.join}

__END__
B88adfae2d92df54499e483e6514d90a?d=identicon&s=25 Geoff Lane (Guest)
on 2006-03-06 00:42
(Received via mailing list)
Here's my solution. Pretty standard output, I didn't try and do anything
fancy like PostScript or OpenGL. I thought I ended up with a pretty good
class design though.

#!/bin/env ruby

class Fibonacci
    DIRS = [:left, :down, :right, :up]

    def initialize(num)
        @values = []
        Fibonacci.calc(num) { |x| @values << x }
    end

    def draw
        current_dir = 0
        main = nil
        @values.each do |v|
            next if 0 == v
            b = block_for(v)
            if ! main
                main = b
                next
            end
            main = add_block(main, b, DIRS[current_dir])
            current_dir = current_dir == 3 ? 0 : current_dir + 1
        end

        print_block(main)
    end

    # Linear Fibonacci calculation
    def Fibonacci.calc(num)
        prev, result = -1, 1
        (0..num).each do
            yield sum = result + prev
            prev = result
            result = sum
        end
    end

    private
    def block_for(num)
        return [] if num == 0

        top = []
        0.upto(num * 2) { top << "#" }

        middle = ["#"]
        2.upto(num * 2) { middle << " " }
        middle << "#"

        b = []
        b  << top
        2.upto(num * 2) { b << middle }
        b << top
    end

    def add_block(main, b, dir)
        if :left == dir
            return add_left(b, main)
        elsif :right == dir
            return add_left(main, b)
        elsif :down == dir
            return add_bottom(main, b)
        elsif :up == dir
            return add_bottom(b, main)
        end
    end

    def add_left(left, right)
        0.upto(left.length - 1) { |i| left[i] = left[i].slice(0..-2) +
right[i] if right[i] }
        return left
    end

    def add_bottom(top, bottom)
        1.upto(bottom.length - 1) { |i| top << bottom[i] }
        return top
    end

    def print_block(b)
        b.each { |x| print x; print "\n" }
    end
end

if __FILE__ == $0
    0.upto(ARGV.length - 1) do |i|
        puts "Fibonacci for: " + ARGV[i]
        f = Fibonacci.new(ARGV[i].to_i)
        f.draw
        puts
    end
end
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-03-06 02:30
(Received via mailing list)
On Mar 5, 2006, at 6:40 PM, Geoff Lane wrote:

> if __FILE__ == $0
>    0.upto(ARGV.length - 1) do |i|
>        puts "Fibonacci for: " + ARGV[i]
>        f = Fibonacci.new(ARGV[i].to_i)
>        f.draw
>        puts
>    end
> end


EEEK! ;)

if __FILE__ == $0
     ARGV.each do |i|
       puts "Fibonacci for: #{i}"
       f = Fibonacci.new(i.to_i)
       f.draw
       puts
   end
end
Da914f265213ce31c7d22195ef178d15?d=identicon&s=25 gordon (Guest)
on 2006-03-06 03:15
(Received via mailing list)
Here is my solution.  I decided to go with RMagick for my output, since
I figured it would be easier than ascii.  Then I got the idea to write
an ascii "Magick" module to do the output in ascii. It is pretty
limited, but it has enough functionality to handle this quiz. Just
change "require 'RMagick'" to "require 'asciiMagick'".

# file: golden_fibbonacci.rb

require 'RMagick'
#require 'asciiMagick'
include Magick

def fib(n)
  x,y = 1,1
   n.times do
     yield x
     x, y = y, x + y
   end
end

def points(n,multiplier=2)
  x1,y1 = 0,0

  fib(n) do |fib|
    fib *= multiplier
    x2,y2 = (fib + x1),(fib + y1)
      yield x1,y1,x2, y2
    if x1 == 0
      x1,y1 = fib,0
    else
      x1,y1 = 0,fib
    end
  end
end

img = Draw.new
img.stroke('black')
img.fill= 'white'
points(9){|x,y,@x,@y| img.rectangle(x,y,@x,@y)}
canvas = Image.new(@x + 1,@y + 1)
img.draw(canvas)

canvas.write('golden_fibbonacci.jpg')

# file: asciiMagick.rb

module Magick
  class Image
    attr_accessor :args

    def initialize(x,y)
      @a = Array.new(y)
      @a.map! do |i|
        i = Array.new(x,' ')
      end
      @a
    end

    def draw_rectangle
      x1,y1,x2,y2 = @args
      x1.upto(x2) do |i|
        @a[y1][i] = '#'
        @a[y2][i] = '#'
      end
      y1.upto(y2) do |i|
        @a[i][x1] = '#'
        @a[i][x2] = '#'
      end
    end

    def write(string)
      puts @a.map!{|i| i.join('')}
    end

  end

  class Draw

    def initialize
      @cache = Array.new
    end

    def stroke(str)
      ## this isn't used
    end

    def fill=(str)
      ## this isn't used
    end

    def draw(canvas)
      @cache.each do |hash|
        hash.each do|method_name,args|
          canvas.args = args
          canvas.method(method_name).call
        end
      end
    end

    def rectangle(x1,y1,x2,y2)
      @cache << {:draw_rectangle => [x1,y1,x2,y2]}
    end

    end

end
B88adfae2d92df54499e483e6514d90a?d=identicon&s=25 Geoffrey Lane (Guest)
on 2006-03-06 03:25
(Received via mailing list)
Heh, good catch.
245cfab887781bdf3f53178b794c42dc?d=identicon&s=25 Alexandru E. Ungur (Guest)
on 2006-03-06 10:03
(Received via mailing list)
Hi all,

Nothing fancy here either, I just tried to solve this in the simplest
way
I could (first). Then I tried 'the Ruby way' (at least how I see it
after
only 10 hours of playing with Ruby...).

The output uses a two characters to display one cell of data, that is
"##" not "#". Since a single character is 8x16 bits, two chars together
make a pretty good square, and thus the proportions in the final output
are more close to the reality. The blue rectangle is the current
rectangle, while the white square is the part that gets cut from it.

Needs ANSI capable terminal, don't know if it would work or not on
Windows...


--- cut here ---
cell, blank, clear = "\033[34;1m##", "\033[37;1m##", "\033[30;0m"

next_rect = lambda { |a,b| [[a,b].max, [a,b].min + [a,b].max] }
rect = next_rect

res = [1, 1]
(1..6).each do
  p res
  side = ''
  res[0].times { side = side + cell }
  res[1].times { side = side + blank }
  res[1].times { puts side }
  puts clear
  res = rect.call(res[0], res[1])
end
--- cut here ---



the OO solution, using recursion

--- cut here ---
class GoldenRectangles
  def initialize
    @cell, @blank, @clear = "\033[34;1m##", "\033[37;1m##", "\033[30;0m"
  end

  def next_rectangle(a, b)
    [[a,b].max, [a,b].min + [a,b].max]
  end

  def show_rectangles(rect, count)
    if count > 0
      p rect
      side = ''
      rect[0].times { side = side + @cell }
      rect[1].times { side = side + @blank }
      rect[1].times { puts side }
      puts @clear
      rect = next_rectangle(rect[0], rect[1])
      show_rectangles(rect, count - 1)
    end
  end
end

GoldenRectangles.new.show_rectangles([1,1], 5)
--- cut here ---


Have a nice day all,
Alex
This topic is locked and can not be replied to.