From: Tom Rauchenwald Date: 2007-03-12T09:11:34+09:00 Subject: Re: [QUIZ] SimFrost (#117) --=-=-= Hi, 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 class Cell attr_reader :kind =20=20 def initialize kind if kind!=3D:vapor && kind !=3D:ice && kind !=3D :vacuum raise "Cell has to be either :ice, :water or :vacuum!" end @kind=3Dkind end def kind=3D(kind) if kind!=3D:vapor && kind !=3D:ice && kind !=3D :vacuum raise "Cell has to be either :ice, :water or :vacuum!" end @kind=3Dkind end =20=20 def kind? kind kind=3D=3D@kind end def to_s case kind when :vacuum; " " when :ice; "*" when :vapor; "`" end end end =20 class Board def initialize x,y,s,pv @x=3Dx; @y=3Dy; @sleeptime=3Ds.to_f/1000 # create Board and fill it with Cells @board=3DArray.new(@x) { Array.new(@y) {Cell.new :vacuum } } @board[@x]=3D@board[0] # Make last and first column the same object # same for last and first row (@x+1).times do |x| @board[x][@y]=3D@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=3D0 if pv < 100 && pv > 0 @p_vapor=3Dpv.to_f/100 else @p_vapor=3D0.3 end # this will toggle between 0 and 1, more is not necessary as # outlined in the quiz description=20 @tick=3D0 end def init_board # clear board @x.times do |x| @y.times do |y| @board[x][y].kind=3D:vacuum end end @n_vapor=3D0; # place the ice at the center @board[@x/2][@y/2].kind=3D:ice # place vapor randomly while @n_vapor.to_f/(@x*@y) < @p_vapor x,y =3D rand(@x), rand(@y) if @board[x][y].kind?(:vacuum) @board[x][y].kind=3D:vapor; @n_vapor +=3D 1 end end end =20=20 def to_s res =3D "=B4" + "-"*@x + "`\n" (@y).times do |y| res << "|" (@x).times do |x| res << @board[x][y].to_s end res << "|\n" end res +=3D "`" + "_"*@x + "=B4\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=3D:ice @n_vapor-=3D1=20 end end else # no ice, rotate neighbourhood clockwise or counter clockwise if rand(2)=3D=3D0 @board[x][y].kind, @board[x+1][y].kind, @board[x+1][y+1].kind, = @board[x][y+1].kind =3D=20 @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 =3D=20 @board[x+1][y].kind, @board[x+1][y+1].kind, @board[x][y+1].ki= nd, @board[x][y].kind end end end end @tick=3D(@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__ + " " puts "Sleeptime is optional (in milliseconds). X and Y must be even numbe= rs." exit 1 end x =3D ARGV[0].to_i;=20 y =3D ARGV[1].to_i; s =3D !ARGV[2] ? 20 : ARGV[2].to_i; pv =3D !ARGV[3] ? 30 : ARGV[3].to_i; b=3DBoard.new(x, y, s, pv) loop do b.init_board b.start print "Again? (y/n): " break if STDIN.gets.chomp.downcase !=3D "y" end --=-=-=--