This week’s quiz received several interesting solutions. Summary also
available at http://rubyquiz.strd6.com/quizzes/197/#summary
Sandro’s solution uses the Shoes graphical toolkit. I hadn’t
played around with Shoes before, but it is basically awesome. It is
very simple to get going and well worth exploring.
Here is the entire display logic for Sandro’s App:
Shoes.app(:title=>'Dreaming mountains', :resizable=>false,
:width=>app[:width], :height=>app[:height]) do
stroke white
strokewidth 2
background black
segments.each_with_index do |b,i|
next if i == 0; a = segments[i-1]
line (f = (segment_width*(i-1) + boundary)), a +
app[:height]/2.0, (f + segment_width), b + app[:height]/2.0
end
end
After setting up a few application parameters and creating the height
values it is super easy to display the segments, and makes a cool
looking screenshot:
Michael L. provided a solution using RMagick that generates an
animated gif of the whole process as well as each step. This clearly
illustrates the algorithm in action; it’s neat to see how it
progresses at each step.
Michael uses some clever techniques to pack a thorough solution into a
small amount of code. The perform_iterations
method accepts a block
which it uses to pass the current state of the simulation back, to
make it easy to capture the output on every step. Another cool
technique is using the width of the image to determine how many
iterations to run, with the idea being that once we get to sub-pixel
midpoints it is ok to stop.
# set iterations to be enough to get "full resolution" for image
but no higher
iterations = (Math.log(width) / Math.log(2)).to_i
Matthias’s solution has some useful techniques as well, such as using
of the :each_cons
enumerator. This yields consecutive elements in
the array, for example:
>> [1, 2, 3].enum_for(:each_cons, 2).to_a
=> [[1, 2], [2, 3]]
This makes mapping inserting the midpoints a little easier, observe:
# Midpoint displacement
heights = [0.0, 0.0]
iterations.times do
heights = heights.enum_for(:each_cons, 2).map do |left, right|
mid = (left + right) / 2
mid += (rand * 2 - 1) * max_offset
[left, mid]
end.flatten << heights[-1]
max_offset *= roughness
end
The last height is appended to the end because it would otherwise be
lost and replaced by a midpoint.
Matthias’ solutions output is in SVG format using builder
to create
the xml.
There are useful bits that can be learned from each solution. So
please check them all out on the mailing list. Additionally the output
strategies of Shoe’s, RMagick, and SVG demonstrate what great options
we have in Ruby.
Thank you Sandro, Michael, and Matthias for your solutions this week!
Keep 'em coming!
– Daniel
http://rubyquiz.strd6.com