[QUIZ][SOLUTION] Mexican Blanket (#127)

Here is my solution for the Mexican Blanket Quiz.
It's also available here:
http://code.rendale.com/svn/RubyQuiz/MexicanBlanket_127/Mexican_Blanket.html<http://code.rendale.com/svn/RubyQuiz/MexicanBlanket>

I was having a hard time seeing the pattern in the ascii so I added a
feature to convert the ascii string into an html image composed of colored
divs.

The colors in the blanket are randomly selected from an array of possible
colors and gradients are alternately separated by Mexican flag bands and
black bands. The technique I use is to create a string with enough of the
pattern to fill the entire blanket and then shift back by one unit per row.

Any feedback on how I can improve this code would be much appreciated.

···

-------------------------------------------------------------------------------------------------------------
#!/usr/local/bin/ruby
module RubyQuiz

  #creates the pattern
  class Pattern
    attr_reader :colors
    attr_reader :value

    def initialize(length)
      @length = length
      @color_count = {:color1=>5, :color2=>1}
      @colors =
Hash["0","black","1","red","2","orange","3","yellow","4","green","5","blue","6","indigo","7","violet","8","white","9","grey"]

      @value=""
      @flag_switch = true
      generate
    end

    def generate
      pick_new_colors
        (0..(@length.to_f/6).ceil).each do |i|
          @value += (@color1.to_s * @color_count[:color1]) + (@color2.to_s *
@color_count[:color2])
        update_colors
        end
    end

    private
      def update_colors
        if @color_count[:color1] > 1
          @color_count[:color1]-=1
          @color_count[:color2]+=1
        else
          @color_count[:color1],@color_count[:color2]=5,1
          @flag_switch ? add_flag : add_seperator
          pick_new_colors
        end
      end

      def add_flag
        @value += "01840"
        @flag_switch = false
      end

      def add_seperator
        @value += "000"
        @flag_switch = true
      end

      def pick_new_colors
        @color1 = (rand*9).ceil
        @color2 = @color1 < 2 ? @color1 + 1 : @color1 - 1
      end
  end

  # composes the pattern into a blanket
  class Blanket
    attr_reader :ascii
    attr_accessor :scale
    def initialize(width=75,height=100, scale=2)
      @width, @height, @scale = width.to_i, height.to_i, scale.to_i
      @ascii, @html = ["",""]
      @pattern = Pattern.new(@width+@height)
      weave
    end

    private
      def weave
        0.upto(@height) do |i|
          @ascii += (@pattern.value[0 + i,@width])[0,@width] + "\n"
        end
        puts @ascii + "\n"
        puts "open Mexican_Blanket.html in your interweb browser to see it
in full color"
        html
      end

      def html
        @html = "<html>\n<head>\n<title>Mexican Blanket
Solution</title>\n</head>\n"
        @html +="<body>\n"
        @html
+="<style>\nbody{background:#ccc;font-weight:bold;text-align:center}\ndiv.pixel{float:left;
width:#{@scale}px; height:#{@scale}px;}\n.wrapper{border:2px solid #fff;
width:#{@width*@scale}px; margin:auto;}\n</style>\n"
        @html +="<div class=\"wrapper\">\n"
        @ascii.split("\n").each do |line|
          line.gsub (/(.)/) do |char|
            @html += "<div class=\"pixel\" style=\"
background:#{@pattern.colors[char]}\"></div>"
          end
        end
        @html += "\n<div style=\"clear:both\"></div>\n</div>"
        @html += "\n<div><pre>\n#{@ascii}\n</pre></div>\n"
        @html += "</body>\n</html>"
        to_file
      end

      def to_file
        output_file = File.open("Mexican_Blanket.html","w")do |f|
          f.write(@html)
        end
      end
  end
end

# Blanket.new accepts height, width, and scale (used for html version)
if __FILE__ == $0
  blanket = RubyQuiz::Blanket.new(*ARGV)
end

-------------------------------------------------------------------------------------------------------------

I noticed there are some line wraps if you cut and paste from the email so
here is the source file.

MexicanBlanket.rb (2.93 KB)

···

On 6/10/07, Will Bailey < will.bailey@gmail.com> wrote:

Here is my solution for the Mexican Blanket Quiz.
It's also available here:

http://code.rendale.com/svn/RubyQuiz/MexicanBlanket_127/Mexican_Blanket.html
< http://code.rendale.com/svn/RubyQuiz/MexicanBlanket&gt;

I was having a hard time seeing the pattern in the ascii so I added a
feature to convert the ascii string into an html image composed of colored
divs.

The colors in the blanket are randomly selected from an array of possible
colors and gradients are alternately separated by Mexican flag bands and
black bands. The technique I use is to create a string with enough of the

pattern to fill the entire blanket and then shift back by one unit per
row.

Any feedback on how I can improve this code would be much appreciated.

-------------------------------------------------------------------------------------------------------------

#!/usr/local/bin/ruby
module RubyQuiz

  #creates the pattern
  class Pattern
    attr_reader :colors
    attr_reader :value

    def initialize(length)
      @length = length
      @color_count = {:color1=>5, :color2=>1}
      @colors =
Hash["0","black","1","red","2","orange","3","yellow","4","green","5","blue","6","indigo","7","violet","8","white","9","grey"]

      @value=""
      @flag_switch = true
      generate
    end

    def generate
      pick_new_colors
        (0..(@length.to_f/6).ceil).each do |i|
          @value += (@color1.to_s * @color_count[:color1]) + (@color2.to_s*
@color_count[:color2])
        update_colors
        end
    end

    private
      def update_colors
        if @color_count[:color1] > 1
          @color_count[:color1]-=1
          @color_count[:color2]+=1
        else
          @color_count[:color1],@color_count[:color2]=5,1
          @flag_switch ? add_flag : add_seperator
          pick_new_colors
        end
      end

      def add_flag
        @value += "01840"
        @flag_switch = false
      end

      def add_seperator
        @value += "000"
        @flag_switch = true
      end

      def pick_new_colors
        @color1 = (rand*9).ceil
        @color2 = @color1 < 2 ? @color1 + 1 : @color1 - 1
      end
  end

  # composes the pattern into a blanket
  class Blanket
    attr_reader :ascii
    attr_accessor :scale
    def initialize(width=75,height=100, scale=2)
      @width, @height, @scale = width.to_i, height.to_i, scale.to_i
      @ascii, @html = ["",""]
      @pattern = Pattern.new(@width+@height)
      weave
    end

    private
      def weave
        0.upto(@height) do |i|
          @ascii += (@pattern.value[0 + i,@width])[0,@width] + "\n"
        end
        puts @ascii + "\n"
        puts "open Mexican_Blanket.html in your interweb browser to see it
in full color"
        html
      end

      def html
        @html = "<html>\n<head>\n<title>Mexican Blanket
Solution</title>\n</head>\n"
        @html +="<body>\n"
        @html

+="<style>\nbody{background:#ccc;font-weight:bold;text-align:center}\ndiv.pixel{float:left;
width:#{@scale}px; height:#{@scale}px;}\n.wrapper{border:2px solid #fff;
width:#{@width*@scale}px; margin:auto;}\n</style>\n"
        @html +="<div class=\"wrapper\">\n"
        @ ascii.split("\n").each do |line|
          line.gsub (/(.)/) do |char|
            @html += "<div class=\"pixel\" style=\"
background:#{@pattern.colors[char]}\"></div>"
          end
        end
        @html += "\n<div style=\"clear:both\"></div>\n</div>"
        @html += "\n<div><pre>\n#{@ascii}\n</pre></div>\n"
        @html += "</body>\n</html>"
        to_file
      end

      def to_file
        output_file = File.open("Mexican_Blanket.html","w")do |f|
           f.write(@html)
        end
      end
  end
end

# Blanket.new accepts height, width, and scale (used for html version)
if __FILE__ == $0
  blanket = RubyQuiz::Blanket.new(*ARGV)
end

-------------------------------------------------------------------------------------------------------------

--
will bailey
towers perrin
804.852.6758

--
will bailey
towers perrin
804.852.6758

Any feedback on how I can improve this code would be much appreciated.

One idea came to me on a quick glance at the code...

-------------------------------------------------------------------------------------------------------------
     @colors =
Hash["0","black","1","red","2","orange","3","yellow","4","green","5","blue","6","indigo","7","violet","8","white","9","grey"]

First, you can drop a lot of punctuation from a line like this using Ruby's word Array syntax:

   @colors = Hash[ *%w[ 0 black 1 red 2 orange 3 yellow
                       4 green 5 blue 6 indigo 7 violet
                       8 white 9 grey ] ]

Of course, those keys are just indices, and we should probably treat them as such:

   require "enumerator"
   @color = Hash[ *%w[ black red orange yellow green
                       blue indigo violet white gray ].
                  enum_with_index.to_a.flatten.reverse ]

I do realize that's not quite as readable though.

James Edward Gray II

···

On Jun 10, 2007, at 10:39 AM, Will Bailey wrote:

cool...I was trying to figure out how to use %w but was missing the leading
*.

Now it seems like I could have just used an array. Originally I was looking
at using the letters to key the colors, which is why I was thinking hash.
Isn't the result of your second suggestion almost an array in hash clothing?

Thanks for the tips
Will

···

On 6/11/07, James Edward Gray II <james@grayproductions.net> wrote:

On Jun 10, 2007, at 10:39 AM, Will Bailey wrote:

> Any feedback on how I can improve this code would be much appreciated.

One idea came to me on a quick glance at the code...

> ----------------------------------------------------------------------
> ---------------------------------------
> @colors =
> Hash
> ["0","black","1","red","2","orange","3","yellow","4","green","5","blue
> ","6","indigo","7","violet","8","white","9","grey"]

First, you can drop a lot of punctuation from a line like this using
Ruby's word Array syntax:

   @colors = Hash[ *%w[ 0 black 1 red 2 orange 3 yellow
                       4 green 5 blue 6 indigo 7 violet
                       8 white 9 grey ] ]

Of course, those keys are just indices, and we should probably treat
them as such:

   require "enumerator"
   @color = Hash[ *%w[ black red orange yellow green
                       blue indigo violet white gray ].
                  enum_with_index.to_a.flatten.reverse ]

I do realize that's not quite as readable though.

James Edward Gray II

--
will bailey
towers perrin
804.852.6758

It is. That's a very good point.

James Edward Gray II

···

On Jun 11, 2007, at 9:44 AM, Will Bailey wrote:

Now it seems like I could have just used an array. Originally I was looking
at using the letters to key the colors, which is why I was thinking hash.
Isn't the result of your second suggestion almost an array in hash clothing?