```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 <chubas7 / gmail.com>
# 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 && ARGV.to_i || 100
\$HEIGHT = ARGV && ARGV.to_i || 100

\$WIDTH += 1 if \$WIDTH % 2 != 0
\$HEIGHT += 1 if \$HEIGHT % 2 != 0

\$DENSITY = ARGV && ARGV.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')

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/.

```