From: Robert Dober Date: 2007-03-12T16:24:41+09:00 Subject: Re: SimFrost (#117) On 3/12/07, Ruben Medellin wrote: > James Gray wrote: > > The three rules of Ruby Quiz: > > Woah, this quiz was very entertaining. I enjoyed a lot doing it, and > still enjoy watching it every time :D > > As the console version wouldn't let me be happy, I tried to do it using > OpenGL. I got it at the end, although it's pretty slow (runs at decent > speed for size of <200*200, obviously the greater values the slowest), > but I'm happy with it for being my first try using GL. > > I'll probably spend another little time tuning it up (as I stated again > that premature optimization is evil), and perhaps designing the 3D view > someone suggested :O. > > Thanks again for the great quizes! > ____________ > > # Quiz 117 : SimFrost > # Ruben Medellin > # Usage> ruby quiz117.rb width height vapor_density > > #Based on OpenGL > require 'opengl' > require 'glut' > > # Each pixel represents an element. > class Element > > attr_accessor :element > > def initialize(element) > @element = element > end > > #Just a change of state. Don't forget to decrement the vapor number. > def freeze > if @element == :vapor > $VAPOR -= 1 > @element = :ice > end > end > end > > # Main class > class Freeze_Simulator > > #Standard initializer. It prepares the windows to be called. > def initialize > > $WIDTH = ARGV[0] && ARGV[0].to_i || 100 > $HEIGHT = ARGV[1] && ARGV[1].to_i || 100 > > $WIDTH += 1 if $WIDTH % 2 != 0 > $HEIGHT += 1 if $HEIGHT % 2 != 0 > > $DENSITY = ARGV[2] && ARGV[2].to_i || 30 > > $VAPOR = 0 > > # We create a matrix, assigning randomly (according to the > # percentage) the density of vapor. Vacuum is represented by nil. > $GRID = Array.new($HEIGHT) do > Array.new($WIDTH) do > if rand(100) > $DENSITY > nil > else > # We need this counter if we want a nice quick > # checker for all_frozen? method > $VAPOR += 1 > Element.new(:vapor) > end > end > end > > #We set the center to be frozen > ($GRID[$HEIGHT/2][$WIDTH/2] = Element.new(:vapor)).freeze > > $TICK_COUNT = 0 > > $PIXELS = [] > > #Standard GL methods > GLUT.Init > GLUT.InitDisplayMode(GLUT::SINGLE) > GLUT.InitWindowSize($WIDTH, $HEIGHT) > GLUT.InitWindowPosition(100, 100) > GLUT.CreateWindow('SimFrost : Quiz #117 - by CHubas') > GL.ShadeModel(GL::FLAT) > > make_matrix > GLUT.DisplayFunc(method(:display).to_proc) > GLUT.KeyboardFunc(Proc.new{|k, x, y| exit if k == 27}) > GLUT.ReshapeFunc(method(:reshape).to_proc) > > # IdleFunc takes a proc object and calls it continously whenever it > can. > GLUT.IdleFunc(method(:tick).to_proc) > end > > # Here we create the pixel information. > # Open GL takes an array of integers and splits it in groups of three > # that represent one color component each. > def make_matrix > for i in 0..$HEIGHT-1 > for j in 0..$WIDTH-1 > index = (i * $WIDTH + j) * 3 > if particle = $GRID[i][j] > case particle.element > when :vapor > # A blue-ish color > $PIXELS[index] = 50 > $PIXELS[index+1] = 100 > $PIXELS[index+2] = 255 > when :ice > # White ice > $PIXELS[index] = 255 > $PIXELS[index+1] = 255 > $PIXELS[index+2] = 255 > end > else > # Black > $PIXELS[index] = 0 > $PIXELS[index+1] = 0 > $PIXELS[index+2] = 0 > end > end > end > end > > # Some basic window behavior > def reshape(width, height) > GL.PixelZoom(width / $WIDTH.to_f, height / $HEIGHT.to_f) > display > end > > # Draws the pixel bitmap > def display > GL.DrawPixels($WIDTH, $HEIGHT, GL::RGB, GL::UNSIGNED_BYTE, > $PIXELS.pack("C*")) > GL.Flush > end > > # We split the board into 2*2 squares with this method > def each_square( tick_number ) > start = 0 > w_end = $WIDTH > h_end = $HEIGHT > > if tick_number % 2 != 0 #odd > start -= 1 > w_end -= 1 > h_end -= 1 > end > > (start...h_end).step(2) do |row| > (start...w_end).step(2) do |column| > s = yield *get_square_at(row, column) > set_square_at(row, column, s) > end > end > > end > > # Checks for each 2*2 square and does the proper transformation > def tick > each_square( ($TICK_COUNT += 1) ) do |*square| > if square.any?{|e| e != nil && e.element == :ice} > for e in square > e.freeze > end > square > else > rotate(square) > end > end > > # Having modified the matrix, now we have to rebuild the pixel map > make_matrix > GLUT.PostRedisplay > GLUT.SwapBuffers > > #Stop doing this if everything is frozen already > GLUT.IdleFunc(nil) if all_frozen? > end > > # Some dirty methods > def get_square_at(row, column) > [$GRID[row][column],$GRID[row][column+1],$GRID[row+1][column],$GRID[row+1][column+1]] > end > > def set_square_at(row, column, new_square) > $GRID[row][column],$GRID[row][column+1],$GRID[row+1][column],$GRID[row+1][column+1] > = new_square > end > > # Rotates elements in > # | 0 1 | > # | 2 3 | > def rotate(square) > if rand(2) == 0 > square.values_at(1,3,0,2) > else > square.values_at(2,0,3,1) > end > end > > # Validates if there is any vapor particle > def all_frozen? > if $VAPOR > 0 > return false > else > puts "Welcome to the ice age!" > puts "All frozen in #{$TICK_COUNT} thicks" > return true > end > end > > # Starts the main loop > def start > GLUT.MainLoop > end > > end > > #Let the fun begin > Freeze_Simulator.new.start > > ________ > > Now I wonder how to make a movie :O > > -- > Posted via http://www.ruby-forum.com/. > > I eventually used NetPBM on Linux but the mpegs get quite big it seems quite difficult to tune. I have a nice 512**2 movie with the initial freezer up left but it got >30MB brrr. Robert -- We have not succeeded in answering all of our questions. In fact, in some ways, we are more confused than ever. But we feel we are confused on a higher level and about more important things. -Anonymous