```---i,

here is my solution. Runs in a Terminal.
A copy can be viewed here: http://sec.modprobe.de/quiz117.rb.html

Tom

---Content-Type: text/x-ruby; charset=iso-8859-1
Content-Disposition: inline; filename=frost2.rb
Content-Transfer-Encoding: quoted-printable

#!/usr/bin/env ruby

# frost.rb
# see http://rubyquiz.com/quiz117.html for details
# Author: Tom Rauchenwald <its.sec / gmx.net>

class Cell

def initialize kind
if kind!=:vapor && kind !=:ice && kind != :vacuum
raise "Cell has to be either :ice, :water or :vacuum!"
end
@kind=kind
end

def kind=(kind)
if kind!=:vapor && kind !=:ice && kind != :vacuum
raise "Cell has to be either :ice, :water or :vacuum!"
end
@kind=kind
end

def kind? kind
kind==@kind
end

def to_s
case kind
when :vacuum; " "
when :ice;    "*"
when :vapor;  "`"
end
end
end

class Board
def initialize x,y,s,pv
@x=x; @y=y; @sleeptime=s.to_f/1000
# create Board and fill it with Cells
@board=Array.new(@x) { Array.new(@y) {Cell.new :vacuum } }
@board[@x]=@board[0]  # Make last and first column the same object
# same for last and first row
(@x+1).times do |x|
@board[x][@y]=@board[x][0]
end
# this will track how man vapor particles are on the board
# scanning the board each tick would be a waste of time
@n_vapor=0
if pv < 100 && pv > 0
@p_vapor=pv.to_f/100
else
@p_vapor=0.3
end
# this will toggle between 0 and 1, more is not necessary as
# outlined in the quiz description
@tick=0
end

def init_board
# clear board
@x.times do |x|
@y.times do |y|
@board[x][y].kind=:vacuum
end
end
@n_vapor=0;
# place the ice at the center
@board[@x/2][@y/2].kind=:ice
# place vapor randomly
while @n_vapor.to_f/(@x*@y) < @p_vapor
x,y = rand(@x), rand(@y)
if @board[x][y].kind?(:vacuum)
@board[x][y].kind=:vapor; @n_vapor += 1
end
end
end

def to_s
res = " + "-"*@x + "`\n"
(@y).times do |y|
res << "|"
(@x).times do |x|
res << @board[x][y].to_s
end
res << "|\n"
end
res += "`" + "_"*@x + "¥¨\n"
return res
end

def tick
# copy first column to last column
(@tick...(@y+@tick)).step(2) do |y|
(@tick...(@x+@tick)).step(2) do |x|
# check if ice is in the neighbourhood
if [@board[x][y], @board[x+1][y], @board[x][y+1], @board[x+1][y+1]].any? { |i| i.kind? :ice }
# there is, change vapor to ice
[@board[x][y], @board[x+1][y], @board[x][y+1], @board[x+1][y+1]].each do |i|
if i.kind? :vapor
i.kind=:ice
@n_vapor-=1
end
end
else
# no ice, rotate neighbourhood clockwise or counter clockwise
if rand(2)==0
@board[x][y].kind, @board[x+1][y].kind, @board[x+1][y+1].kind, @board[x][y+1].kind =
@board[x][y+1].kind, @board[x][y].kind, @board[x+1][y].kind, @board[x+1][y+1].kind
else
@board[x][y].kind, @board[x+1][y].kind, @board[x+1][y+1].kind, @board[x][y+1].kind =
@board[x+1][y].kind, @board[x+1][y+1].kind, @board[x][y+1].kind, @board[x][y].kind
end
end
end
end
@tick=(@tick+1)%2 # toggle tick
end

def start
puts "\033[2J"  # clear terminal and move cursor to upper left
while @n_vapor>0
puts "\033[0;0f" # move cursor to upper left
puts self.to_s
tick
sleep @sleeptime
end
puts "\033[0;0f"
puts self.to_s
end
end

if ARGV.length<2
puts "Usage: " + __FILE__ + " <sizeX> <sizeY> <sleeptime>"
puts "Sleeptime is optional (in milliseconds). X and Y must be even numbers."
exit 1
end

x = ARGV[0].to_i;
y = ARGV[1].to_i;
s = !ARGV[2] ? 20 : ARGV[2].to_i;
pv = !ARGV[3] ? 30 : ARGV[3].to_i;

b=Board.new(x, y, s, pv)
loop do
b.init_board
b.start
print "Again? (y/n): "
break if STDIN.gets.chomp.downcase != "y"
end

---

```