--k+w/mQv8wyuph6w0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On 2007-05-25 22:18:32 +0900 (Fri, May), Ruby Quiz wrote:
> The goal is to create a ruby program which takes the level as an argumentnd
> then draws the fractal shown below to the specified level. The fractal is
> created by drawing the first level, then repeating the pattern such that each
> base piece is replaced with the fractal from the higher level. Thus, to move
> from level 1 to level 2, we replace each line with the shape at level 1. Notice
> that the position changes as well, meaning if the line is vertical we replace it
> with a vertically positioned shape of level 1 (right and left facing also
> matter). I have shown the first 3 levels below (including the base component at
> level 0). Feel free to use the console for output or get fancy with RMagick or
> something similar.
> 
> 	                          _                  <-- Level 0
> 	                          _
> 	                        _| |_                <-- Level 1
> 	                          _
> 	                        _| |_
> 	                      _|     |_              <-- Level 2
> 	                    _|_       _|_
> 	                  _| |_|     |_| |_


#!/usr/bin/ruby -w

# The Fractal objects are a sequence of steps to draw
# an image. In Logo the drawing would be extremely easy.
class Fractal
  attr_reader :path

  # +level+ may be 0 or greater, and should be something like an integer.
  #
  # +seq+ is an array with a sequence of steps (:fw, :right, or :left) which
  # will replace each :fw (means: forward) part of the path.
  # A nice default is provided.
  def initialize level = 1, seq = nil
    super()
    @path = [:fw]
    seq = [:fw, :left, :fw, :right, :fw, :right, :fw, :left, :fw]
    level.times do
      @path.map! { |el| el == :fw ? seq.dup : el }.flatten!
    end
  end
end

# AsciiArtCanvas draws a given Fractal.path on an array of strings.
class AsciiArtCanvas

  def initialize path, initial_dir = :e
    @path = path
    @dir = initial_dir
    @canvas = Hash.new { |h,k| h[k] = Hash.new { |h2,k2| h2[k2] = ' '}
    @x = @y = @min_x = @min_y = @max_x = @max_y = 0
  end

  def paint
    @path.each { |step| step == :fw ? draw : turn(step) }
    (@min_y..@max_y).inject([]) do |arr,y|
      arr << (@min_x..@max_x).inject('') do |row,x|
        row + @canvas[x][y]
      end
    end
  end
  
  private
    def draw
      case @dir
      when :n;  @y -= 1
      when :s;  @y += 1
      when :e;  @x += 1
      when :w;  @x -= 1
      end

      @canvas[@x][@y] = case @canvas[@x][@y]
                        when '+'; '+'
                        when '-'; [:n,:s].include?( @dir ) ? '+' : '-'
                        when '|'; [:w,:e].include?( @dir ) ? '+' : '|'
                        else      [:n,:s].include?( @dir ) ? '|' : '-'
                        end
      case @dir
      when :n;  @y -= 1; @min_y = @y if @y < @min_y
      when :s;  @y += 1; @max_y = @y if @y > @max_y
      when :e;  @x += 1; @max_x = @x if @x > @max_x
      when :w;  @x -= 1; @min_x = @x if @x < @min_x
      end
    end

    TURNS = {
      :n => { :left => :w, :right => :e },
      :w => { :left => :s, :right => :n },
      :s => { :left => :e, :right => :w },
      :e => { :left => :n, :right => :s },
    }
    def turn dir
      @dir = TURNS[@dir][dir]
    end
      
end

if __FILE__ == $0
  level = ARGV[0] ? ARGV[0].to_i.abs : 3

  t = Fractal.new level
  puts( *AsciiArtCanvas.new(t.path, :e).paint )
end


It's terribly inefficient for high levels:

$ time ./fract.rb 4
[...]
real    0m0.297s

for level 4:  0.297s
for level 5:  1.917s
for level 6: 37.449s
I'm too scared to run it with level 7 :-)

-- 
No virus found in this outgoing message.
Checked by 'grep -i virus $MESSAGE'
Trust me.

--k+w/mQv8wyuph6w0
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7-ecc0.1.6 (GNU/Linux)

iD8DBQFGWZDDsnU0scoWZKARAghFAKDOmQ9rFq4FPhq3mpaNACVkQ+LRdwCeOtFH
7Xvp1dPsQ5OU8y0Bylsyzg8g+
-----END PGP SIGNATURE-----

--k+w/mQv8wyuph6w0--