From: Raj Sahae Date: 2007-03-12T03:46:10+09:00 Subject: Re: SimFrost (#117) [solution] I'm still working on a version that has fancy graphical output. This is the ascii output version. # # Raj Sahae # RubyQuiz #117 # Frost Simulation # # USAGE: ruby frost.rb [height] [width] [vapor_percentage] class Fixnum def even? self%2 == 0 end def odd? not self.even? end def prev self -1 end end #The order ROWxCOL is kept throughout the program # for any type of matrix/grid format. class Torus attr_reader :width, :height attr_accessor :grid def initialize(row, col) raise "Width and Height must be even integers" unless row.even? and col.even? @width = col @height = row @grid = Array.new(row){Array.new(col)} end def [](row) @grid[row] end def []=(row, value) @grid[row] = value end def next_row(row) row.next == @height ? 0 : row.next end def next_col(col) col.next == @width ? 0 : col.next end def prev_row(row) row == 0 ? @height.prev : row.prev end def prev_col(col) col == 0 ? @width.prev : col.prev end end class FrostSimulation #Initialize with the number of rows and columns # and the percentage of the grid(an Integer from 0-100) # that should be vapor def initialize(rows, cols, percentage) @torus = Torus.new(rows, cols) @torus.grid.each{|row| row.collect!{|n| rand(99) < percentage ?(:vapor):(:vacuum)}} center = [rows/2, cols/2] @torus[center[0]][center[1]] = :ice end def display @torus.width.times{print '#'}; print "\n" @torus.grid.each do |row| row.each do |n| if n == :vapor then print('.') elsif n == :vacuum then print(' ') elsif n == :ice then print('*') end end print "\n" end end def extract_groups_at(tick) ptr = tick.even? ? [0, 0] : [1, 1] width, height = @torus.width/2, @torus.height/2 #Neighborhood array is formatted counterclockwise from starting point #Eg. one element of neighborhood shows [top_left, bottom_left, bottom_right, top_right] groups = Array.new(width*height){Array.new(4)} groups.each_index do |index| groups[index][0] = @torus.grid[ptr[0]][ptr[1]] #set top_left ptr[0] = @torus.next_row(ptr[0]) #move pointer down a row groups[index][1] = @torus.grid[ptr[0]][ptr[1]] #set bottom_left ptr[1] = @torus.next_col(ptr[1]) # move pointer over a col groups[index][2] = @torus.grid[ptr[0]][ptr[1]] # set bottom_right ptr[0] = @torus.prev_row(ptr[0]) # move pointer up a row groups[index][3] = @torus.grid[ptr[0]][ptr[1]] #set top_right ptr[1] = @torus.next_col(ptr[1]) # move pointer over a col #if we are at the end of a row, move the pointer down 2 rows 2.times{ptr[0] = @torus.next_row(ptr[0])} if index.next%width == 0 end end def process_groups(groups) groups.each do |group| if group.include?(:ice) group.collect!{|n| n == :vapor ? :ice : n} else rand(100) < 51 ? group.unshift(group.pop) : group.push(group.shift) end end end def inject_groups(tick, groups) #this is the same algorithm as extraction ptr = tick.even? ? [0, 0] : [1, 1] width, height = @torus.width/2, @torus.height/2 groups.each_index do |index| @torus.grid[ptr[0]][ptr[1]] = groups[index][0] #set top_left ptr[0] = @torus.next_row(ptr[0]) #move pointer down a row @torus.grid[ptr[0]][ptr[1]] = groups[index][1] #set bottom_left ptr[1] = @torus.next_col(ptr[1]) # move pointer over a col @torus.grid[ptr[0]][ptr[1]] = groups[index][2] # set bottom_right ptr[0] = @torus.prev_row(ptr[0]) # move pointer up a row @torus.grid[ptr[0]][ptr[1]] = groups[index][3] #set top_right ptr[1] = @torus.next_col(ptr[1]) # move pointer over a col #if we are at the end of a row, move the pointer down 2 rows 2.times{ptr[0] = @torus.next_row(ptr[0])} if index.next%width == 0 end end def run tick = 0 continue = true display while continue groups = inject_groups(tick, process_groups(extract_groups_at(tick))) display continue = @torus.grid.flatten.detect{|n| n == :vapor} tick = tick.next sleep(0.15) end end end if $0 == __FILE__ rows = ARGV[0].nil? ? 24 : ARGV[0].to_i cols = ARGV[1].nil? ? 40 : ARGV[1].to_i percentage = ARGV[2].nil? ? 30 : ARGV[2].to_i sim = FrostSimulation.new(rows, cols, percentage) sim.run end