#!/usr/bin/ruby
define w = Number(`tput cols` || 80)
define h = Number(`tput lines` || 24)
define r = "\033[H"
define red = "\033[31m"
define green = "\033[32m"
define yellow = "\033[33m"
define chars = [' ', green+'*', yellow+'&', red+'&']
define tree_prob = 0.05f
define burn_prob = 0.0002f
enum |Empty, Tree, Heating, Burning|
define dirs = [
%n(-1 -1), %n(-1 0), %n(-1 1), %n(0 -1),
%n(0 1), %n(1 -1), %n(1 0), %n(1 1),
]
var forest = h.of { w.of { 1.rand < tree_prob ? Tree : Empty } }
var range_h = h.range
var range_w = w.range
func iterate {
var new_forest = h.of{ w.of(0) }
for i = range_h, j = range_w {
given (new_forest[i][j] = forest[i][j]) {
when (Tree) {
1.rand < burn_prob && (new_forest[i][j] = Heating; next)
for y,x in (dirs) {
y += i; x += j
range_h.contains(y) || next
range_w.contains(x) || next
new_forest[i][j] = Heating if (forest[y][x] == Heating)
}
}
when (Heating) { new_forest[i][j] = Burning }
when (Burning) { new_forest[i][j] = Empty }
case (1.rand < tree_prob) { new_forest[i][j] = Tree }
}
}
forest = new_forest
}
STDOUT.autoflush(true)
func init_forest {
print r
forest.each { |row|
print chars[row...]
print "\033[E\033[1G"
}
iterate()
}
loop { init_forest() }