197 lines
4.2 KiB
Plaintext
197 lines
4.2 KiB
Plaintext
class FORESTFIRE is
|
|
private attr fields:ARRAY{ARRAY{INT}};
|
|
private attr swapu:INT;
|
|
private attr rnd:RND;
|
|
private attr verbose:BOOL;
|
|
private attr generation:INT;
|
|
readonly attr width, height:INT;
|
|
const empty:INT := 0;
|
|
const tree:INT := 1;
|
|
const burning:INT := 2;
|
|
|
|
attr prob_tree, prob_p, prob_f :FLT;
|
|
|
|
create(w, h:INT, v:BOOL):SAME is
|
|
res:FORESTFIRE := new;
|
|
res.fields := #(2);
|
|
res.fields[0] := #(w*h);
|
|
res.fields[1] := #(w*h);
|
|
res.width := w; res.height := h;
|
|
res.swapu := 0;
|
|
res.prob_tree := 0.55;
|
|
res.prob_p := 0.001;
|
|
res.prob_f := 0.00001;
|
|
res.rnd := #RND;
|
|
res.verbose := v;
|
|
res.generation := 0;
|
|
res.initfield;
|
|
return res;
|
|
end;
|
|
|
|
-- to give variability
|
|
seed(i:INT) is
|
|
rnd.seed(i);
|
|
end;
|
|
|
|
create(w, h:INT):SAME is
|
|
res ::= create(w, h, false);
|
|
return res;
|
|
end;
|
|
|
|
initfield is
|
|
n ::= 0;
|
|
swapu := 0;
|
|
if verbose and generation > 0 then
|
|
#ERR + "Previous generation " + generation + "\n";
|
|
end;
|
|
generation := 0;
|
|
loop i ::= 0.upto!(width-1);
|
|
loop j ::= 0.upto!(height-1);
|
|
if rnd.uniform > prob_tree.fltd then
|
|
cset(i, j, empty);
|
|
else
|
|
n := n + 1;
|
|
cset(i, j, tree);
|
|
end;
|
|
end;
|
|
end;
|
|
if verbose then
|
|
#ERR + #FMT("Field size is %dx%d (%d)", width, height, size) + "\n";
|
|
#ERR + "There are " + n + " trees (" + (100.0*n.flt/size.flt) + "%)\n";
|
|
#ERR + "prob_tree = " + prob_tree + "\n";
|
|
#ERR + "prob_f = " + prob_f + "\n";
|
|
#ERR + "prob_p = " + prob_p + "\n";
|
|
#ERR + "ratio = " + prob_p/prob_f + "\n";
|
|
end;
|
|
end;
|
|
|
|
field:ARRAY{INT} is
|
|
return fields[swapu];
|
|
end;
|
|
|
|
ofield:ARRAY{INT} is
|
|
return fields[swapu.bxor(1)];
|
|
end;
|
|
|
|
size:INT is
|
|
return width*height;
|
|
end;
|
|
|
|
set(i, j, t:INT)
|
|
pre bcheck(i, j)
|
|
is
|
|
ofield[j*width + i] := t;
|
|
end;
|
|
|
|
cset(i, j, t:INT)
|
|
pre bcheck(i, j)
|
|
is
|
|
field[j*width + i] := t;
|
|
end;
|
|
|
|
private bcheck(i, j:INT):BOOL is
|
|
if i.is_between(0, width-1) and j.is_between(0, height-1) then
|
|
return true; -- is inside
|
|
else
|
|
return false; -- is outside
|
|
end;
|
|
end;
|
|
|
|
get(i, j:INT):INT is
|
|
if ~bcheck(i, j) then
|
|
return empty;
|
|
end;
|
|
return field[j*width + i];
|
|
end;
|
|
|
|
oget(i, j:INT):INT is
|
|
if ~bcheck(i, j) then
|
|
return empty;
|
|
end;
|
|
return ofield[j*width + i];
|
|
end;
|
|
|
|
burning_neighbor(i, j:INT):BOOL is
|
|
loop x ::= (-1).upto!(1);
|
|
loop y ::= (-1).upto!(1);
|
|
if x /= y then
|
|
if get(i+x, j+y) = burning then return true; end;
|
|
end;
|
|
end;
|
|
end;
|
|
return false;
|
|
end;
|
|
|
|
evolve is
|
|
bp ::= 0;
|
|
loop i ::= 0.upto!(width-1);
|
|
loop j ::= 0.upto!(height-1);
|
|
case get(i, j)
|
|
when burning then set(i, j, empty); bp := bp + 1;
|
|
when empty then
|
|
if rnd.uniform > prob_p.fltd then
|
|
set(i, j, empty);
|
|
else
|
|
set(i, j, tree);
|
|
end;
|
|
when tree then
|
|
if burning_neighbor(i, j) then
|
|
set(i, j, burning);
|
|
else
|
|
if rnd.uniform > prob_f.fltd then
|
|
set(i, j, tree);
|
|
else
|
|
set(i, j, burning);
|
|
end;
|
|
end;
|
|
else
|
|
#ERR + "corrupted field\n";
|
|
end;
|
|
end;
|
|
end;
|
|
generation := generation + 1;
|
|
if verbose then
|
|
if bp > 0 then
|
|
#ERR + #FMT("Burning at gen %d: %d\n", generation-1, bp);
|
|
end;
|
|
end;
|
|
swapu := swapu.bxor(1);
|
|
end;
|
|
|
|
str:STR is
|
|
s ::= "";
|
|
loop j ::= 0.upto!(height -1);
|
|
loop i ::= 0.upto!(width -1);
|
|
case get(i, j)
|
|
when empty then s := s + ".";
|
|
when tree then s := s + "Y";
|
|
when burning then s := s + "*";
|
|
end;
|
|
end;
|
|
s := s + "\n";
|
|
end;
|
|
s := s + "\n";
|
|
return s;
|
|
end;
|
|
|
|
end;
|
|
|
|
class MAIN is
|
|
|
|
main is
|
|
forestfire ::= #FORESTFIRE(74, 40);
|
|
-- #FORESTFIRE(74, 40, true) to have some extra info
|
|
-- (redirecting stderr to a file is a good idea!)
|
|
|
|
#OUT + forestfire.str;
|
|
-- evolve 1000 times
|
|
loop i ::= 1000.times!;
|
|
forestfire.evolve;
|
|
-- ANSI clear screen sequence
|
|
#OUT + 0x1b.char + "[H" + 0x1b.char + "[2J";
|
|
#OUT + forestfire.str;
|
|
end;
|
|
end;
|
|
|
|
end;
|