> The three rules of Ruby Quiz: Hello, everypeoples. First time here; please bear with me. My solution class is at the bottom of this message. One could run the sim with something as simple as this: frost = SimFrost.new(80,24) puts frost while frost.step but this will cause jerkiness due to the sheer mass of text. So, in my solution script, quiz117.rb, I used curses instead: require 'simfrost' require 'curses' win = Curses.init_screen columns = win.maxx lines = win.maxy # ensure even numbers columns -= columns % 2 lines -= lines % 2 frost = SimFrost.new(columns, lines) while frost.step win.setpos(0,1) win << frost.to_s win.refresh end Of course, one could also use frost.to_a and translate frost symbols (:vapor, :ice, :vacuum) into pixels, but I haven't had the time to play with a Ruby graphics library yet. Anyway, this is the class: # SimFrost, solution to RubyQuiz #117 # by Harrison Reiser 2007-03-10 class SimFrost def initialize(width, height, vapor_ratio = 0.25) @height = height.to_i @width = width.to_i vapor_ratio = vapor_ratio.to_f raise "height must be even" if height % 2 == 1 raise "width must be even" if width % 2 == 1 # fill the matrix with random vapor @grid = Array.new(height) do |row| row = Array.new(width) { |x| x = rand < vapor_ratio ? :vapor : :vacuum } end # seed it with an ice particle @grid[height/2][width/2] = :ice @offset = 0 end # advances the frost simulation by one tick # or returns false if it has already finished. def step # confirm the presence of vapor return false if @grid.each do |row| break unless row.each { |sq| break if sq == :vapor } end # for each 2x2 box in the grid (0...@height/2).each do |i| (0...@width/2).each do |j| # get the coordinates of the corners y0 = i + i + @offset x0 = j + j + @offset y1 = (y0 + 1) % @height x1 = (x0 + 1) % @width # check for ice if @grid[y0][x0] == :ice or @grid[y0][x1] == :ice or @grid[y1][x0] == :ice or @grid[y1][x1] == :ice # freeze nearby vapor @grid[y0][x0] = :ice if @grid[y0][x0] == :vapor @grid[y0][x1] = :ice if @grid[y0][x1] == :vapor @grid[y1][x0] = :ice if @grid[y1][x0] == :vapor @grid[y1][x1] = :ice if @grid[y1][x1] == :vapor else if rand < 0.5 # rotate right-hand temp = @grid[y0][x0] @grid[y0][x0] = @grid[y1][x0] @grid[y1][x0] = @grid[y1][x1] @grid[y1][x1] = @grid[y0][x1] @grid[y0][x1] = temp else # rotate left-hand temp = @grid[y0][x0] @grid[y0][x0] = @grid[y0][x1] @grid[y0][x1] = @grid[y1][x1] @grid[y1][x1] = @grid[y1][x0] @grid[y1][x0] = temp end end end end # toggle the offset @offset = @offset ^ 1 true # report that progress has been made end def to_a; @grid; end def to_s @grid.map { |row| row.map { |sq| @@asciifrost[sq] }.join }.join end # maps frost symbols to characters @@asciifrost = { :vapor => '.', :ice => '*', :vacuum => ' ' } end