Jump to content

Forest fire: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
m (→‎{{header|Haskell}}: Dropped one (now redundant) import.)
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 612:
Y YYY# # YY Y # #Y
</pre>
 
=={{header|ALGOL 68}}==
===Textual version===
Line 2,018 ⟶ 2,019:
# T T T #
</pre>
 
 
=={{header|C}}==
Line 2,340:
 
evolve(w, h);
}</lang>
 
=={{header|C sharp|C#}}==
 
<lang csharp>using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;
 
namespace ForestFire
{
class Program : Form
{
private static readonly Random rand = new Random();
private Bitmap img;
 
public Program(int w, int h, int f, int p)
{
Size = new Size(w, h);
StartPosition = FormStartPosition.CenterScreen;
 
Thread t = new Thread(() => fire(f, p));
t.Start();
 
FormClosing += (object sender, FormClosingEventArgs e) => { t.Abort(); t = null; };
}
 
private void fire(int f, int p)
{
int clientWidth = ClientRectangle.Width;
int clientHeight = ClientRectangle.Height;
int cellSize = 10;
 
img = new Bitmap(clientWidth, clientHeight);
Graphics g = Graphics.FromImage(img);
 
CellState[,] state = InitializeForestFire(clientWidth, clientHeight);
 
uint generation = 0;
 
do
{
g.FillRectangle(Brushes.White, 0, 0, img.Width, img.Height);
state = StepForestFire(state, f, p);
 
for (int y = 0; y < clientHeight - cellSize; y += cellSize)
{
for (int x = 0; x < clientWidth - cellSize; x += cellSize)
{
switch (state[y, x])
{
case CellState.Empty:
break;
case CellState.Tree:
g.FillRectangle(Brushes.DarkGreen, x, y, cellSize, cellSize);
break;
case CellState.Burning:
g.FillRectangle(Brushes.DarkRed, x, y, cellSize, cellSize);
break;
}
}
}
 
Thread.Sleep(500);
 
Invoke((MethodInvoker)Refresh);
 
} while (generation < uint.MaxValue);
 
g.Dispose();
}
 
private CellState[,] InitializeForestFire(int width, int height)
{
// Create our state array, initialize all indices as Empty, and return it.
var state = new CellState[height, width];
state.Initialize();
return state;
}
 
private enum CellState : byte
{
Empty = 0,
Tree = 1,
Burning = 2
}
 
private CellState[,] StepForestFire(CellState[,] state, int f, int p)
{
/* Clone our old state, so we can write to our new state
* without changing any values in the old state. */
var newState = (CellState[,])state.Clone();
 
int numRows = state.GetLength(0);
int numCols = state.GetLength(1);
 
for (int r = 1; r < numRows - 1; r++)
{
for (int c = 1; c < numCols - 1; c++)
{
/*
* Check the current cell.
*
* If it's empty, give it a 1/p chance of becoming a tree.
*
* If it's a tree, check to see if any neighbors are burning.
* If so, set the cell's state to burning, otherwise give it
* a 1/f chance of combusting.
*
* If it's burning, set it to empty.
*/
switch (state[r, c])
{
case CellState.Empty:
if (rand.Next(0, p) == 0)
newState[r, c] = CellState.Tree;
break;
 
case CellState.Tree:
if (NeighborHasState(state, r, c, CellState.Burning) || rand.Next(0, f) == 0)
newState[r, c] = CellState.Burning;
break;
 
case CellState.Burning:
newState[r, c] = CellState.Empty;
break;
}
}
}
 
return newState;
}
 
private bool NeighborHasState(CellState[,] state, int x, int y, CellState value)
{
// Check each cell within a 1 cell radius for the specified value.
for (int r = -1; r <= 1; r++)
{
for (int c = -1; c <= 1; c++)
{
if (r == 0 && c == 0)
continue;
 
if (state[x + r, y + c] == value)
return true;
}
}
 
return false;
}
 
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawImage(img, 0, 0);
}
 
[STAThread]
static void Main(string[] args)
{
Application.Run(new Program(w: 500, h: 500, f: 2, p: 5));
}
}
}</lang>
 
Line 2,626 ⟶ 2,790:
//--------------------------------------------------------------------------------------------------
</lang>
 
=={{header|C sharp|C#}}==
 
<lang csharp>using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;
 
namespace ForestFire
{
class Program : Form
{
private static readonly Random rand = new Random();
private Bitmap img;
 
public Program(int w, int h, int f, int p)
{
Size = new Size(w, h);
StartPosition = FormStartPosition.CenterScreen;
 
Thread t = new Thread(() => fire(f, p));
t.Start();
 
FormClosing += (object sender, FormClosingEventArgs e) => { t.Abort(); t = null; };
}
 
private void fire(int f, int p)
{
int clientWidth = ClientRectangle.Width;
int clientHeight = ClientRectangle.Height;
int cellSize = 10;
 
img = new Bitmap(clientWidth, clientHeight);
Graphics g = Graphics.FromImage(img);
 
CellState[,] state = InitializeForestFire(clientWidth, clientHeight);
 
uint generation = 0;
 
do
{
g.FillRectangle(Brushes.White, 0, 0, img.Width, img.Height);
state = StepForestFire(state, f, p);
 
for (int y = 0; y < clientHeight - cellSize; y += cellSize)
{
for (int x = 0; x < clientWidth - cellSize; x += cellSize)
{
switch (state[y, x])
{
case CellState.Empty:
break;
case CellState.Tree:
g.FillRectangle(Brushes.DarkGreen, x, y, cellSize, cellSize);
break;
case CellState.Burning:
g.FillRectangle(Brushes.DarkRed, x, y, cellSize, cellSize);
break;
}
}
}
 
Thread.Sleep(500);
 
Invoke((MethodInvoker)Refresh);
 
} while (generation < uint.MaxValue);
 
g.Dispose();
}
 
private CellState[,] InitializeForestFire(int width, int height)
{
// Create our state array, initialize all indices as Empty, and return it.
var state = new CellState[height, width];
state.Initialize();
return state;
}
 
private enum CellState : byte
{
Empty = 0,
Tree = 1,
Burning = 2
}
 
private CellState[,] StepForestFire(CellState[,] state, int f, int p)
{
/* Clone our old state, so we can write to our new state
* without changing any values in the old state. */
var newState = (CellState[,])state.Clone();
 
int numRows = state.GetLength(0);
int numCols = state.GetLength(1);
 
for (int r = 1; r < numRows - 1; r++)
{
for (int c = 1; c < numCols - 1; c++)
{
/*
* Check the current cell.
*
* If it's empty, give it a 1/p chance of becoming a tree.
*
* If it's a tree, check to see if any neighbors are burning.
* If so, set the cell's state to burning, otherwise give it
* a 1/f chance of combusting.
*
* If it's burning, set it to empty.
*/
switch (state[r, c])
{
case CellState.Empty:
if (rand.Next(0, p) == 0)
newState[r, c] = CellState.Tree;
break;
 
case CellState.Tree:
if (NeighborHasState(state, r, c, CellState.Burning) || rand.Next(0, f) == 0)
newState[r, c] = CellState.Burning;
break;
 
case CellState.Burning:
newState[r, c] = CellState.Empty;
break;
}
}
}
 
return newState;
}
 
private bool NeighborHasState(CellState[,] state, int x, int y, CellState value)
{
// Check each cell within a 1 cell radius for the specified value.
for (int r = -1; r <= 1; r++)
{
for (int c = -1; c <= 1; c++)
{
if (r == 0 && c == 0)
continue;
 
if (state[x + r, y + c] == value)
return true;
}
}
 
return false;
}
 
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawImage(img, 0, 0);
}
 
[STAThread]
static void Main(string[] args)
{
Application.Run(new Program(w: 500, h: 500, f: 2, p: 5));
}
}
}</lang>
 
=={{header|Ceylon}}==
Line 4,830:
 
Finally note that the grid size includes the one cell "border" which are blank. If the border cells are meant to be outside of the represented dimensions, you can add 2 to them (or change the code to do so).
 
=={{header|JAMES II/Rule-based Cellular Automata}}==
<lang j2carules>@caversion 1;
 
dimensions 2;
 
state EMPTY, TREE, BURNING;
 
// an empty cell grows a tree with a chance of p = 5 %
rule{EMPTY} [0.05] : -> TREE;
 
// a burning cell turns to a burned cell
rule{BURNING}: -> EMPTY;
 
// a tree starts burning if there is at least one neighbor burning
rule{TREE} : BURNING{1,} -> BURNING;
 
// a tree is hit by lightning with a change of f = 0.006 %
rule{TREE} [0.00006] : -> BURNING;</lang>
The starting configuration cannot be given in the modeling language since the concepts of the ''model'' and its ''parameters'' (which includes the starting configuration) are separate in JAMES II.
 
=={{header|Java}}==
Line 4,973 ⟶ 4,993:
===Graphics===
See: [[Forest fire/Java/Graphics]]
 
=={{header|JAMES II/Rule-based Cellular Automata}}==
<lang j2carules>@caversion 1;
 
dimensions 2;
 
state EMPTY, TREE, BURNING;
 
// an empty cell grows a tree with a chance of p = 5 %
rule{EMPTY} [0.05] : -> TREE;
 
// a burning cell turns to a burned cell
rule{BURNING}: -> EMPTY;
 
// a tree starts burning if there is at least one neighbor burning
rule{TREE} : BURNING{1,} -> BURNING;
 
// a tree is hit by lightning with a change of f = 0.006 %
rule{TREE} [0.00006] : -> BURNING;</lang>
The starting configuration cannot be given in the modeling language since the concepts of the ''model'' and its ''parameters'' (which includes the starting configuration) are separate in JAMES II.
 
=={{header|JavaScript}} Node ==
Line 5,066:
}, 20);
 
</lang> =={{header|JavaScript}}==
 
=={{header|JavaScript}}==
<lang javascript>var forest = {
X: 50,
Line 5,712 ⟶ 5,710:
select undef, undef, undef, 0.1; # comment out for full speed
}</lang>
=={{header|Perl 6}}==
 
===ANSI graphics===
{{works with|rakudo|2015-10-04}}
This version saves a lot of looking around by using four states instead of three; the <tt>Heating</tt> state does a lookahead to track trees that are being heated up by burning trees, so we only ever have to traverse the neighbors of burning trees, not all trees. Also, by only checking the list of burning trees, we can avoid copying the entire forest each iteration, since real forests are mutable.
<lang perl6>my $RED = "\e[1;31m";
my $YELLOW = "\e[1;33m";
my $GREEN = "\e[1;32m";
my $CLEAR = "\e[0m";
enum Cell-State <Empty Tree Heating Burning>;
my @pix = ' ', $GREEN ~ '木', $YELLOW ~ '木', $RED ~ '木';
class Forest {
has Rat $.p = 0.01;
has Rat $.f = 0.001;
has Int $!height;
has Int $!width;
has @!coords;
has @!spot;
has @!neighbors;
 
method BUILD (Int :$!height, Int :$!width) {
@!coords = ^$!height X ^$!width;
@!spot = [ (Bool.pick ?? Tree !! Empty) xx $!width ] xx $!height;
self!init-neighbors;
}
method !init-neighbors {
for @!coords -> ($i, $j) {
@!neighbors[$i][$j] = eager gather for
[-1,-1],[+0,-1],[+1,-1],
[-1,+0], [+1,+0],
[-1,+1],[+0,+1],[+1,+1]
{
take-rw @!spot[$i + .[0]][$j + .[1]] // next;
}
}
}
method step {
my @heat;
for @!coords -> ($i, $j) {
given @!spot[$i][$j] {
when Empty { $_ = Tree if rand < $!p }
when Tree { $_ = Heating if rand < $!f }
when Heating { $_ = Burning; push @heat, ($i, $j); }
when Burning { $_ = Empty }
}
}
for @heat -> ($i,$j) {
$_ = Heating for @!neighbors[$i][$j].grep(Tree);
}
}
method show {
for ^$!height -> $i {
say @pix[@!spot[$i].list].join;
}
}
}
 
my ($ROWS, $COLS) = qx/stty size/.words;
 
signal(SIGINT).act: { print "\e[H\e[2J"; exit }
 
sub MAIN (Int $height = $ROWS - 2, Int $width = +$COLS div 2 - 1) {
my Forest $forest .= new(:$height, :$width);
print "\e[2J"; # ANSI clear screen
loop {
print "\e[H"; # ANSI home
say $++;
$forest.show;
$forest.step;
}
}</lang>
 
===SDL2 Animation===
An alternate version implemented in SDL2.
 
<lang perl6>use NativeCall;
use SDL2::Raw;
 
my ($width, $height) = 900, 900;
 
SDL_Init(VIDEO);
my SDL_Window $window = SDL_CreateWindow(
"Forest Fire - Perl 6",
SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK,
$width, $height,
RESIZABLE
);
my SDL_Renderer $renderer = SDL_CreateRenderer( $window, -1, ACCELERATED +| PRESENTVSYNC );
 
SDL_ClearError();
 
my int ($w, $h) = 200, 200;
 
my $forest_texture = SDL_CreateTexture($renderer, %PIXELFORMAT<RGB332>, STREAMING, $w, $h);
 
my $pixdatabuf = CArray[int64].new(0, $w, $h, $w);
my $work-buffer = CArray[int64].new(0, $w, $h, $w);
 
my int $bare = 0; # Black
my int $tree = 8; # Green
my int $heating = -120; # Orange ( 132 but it's being passed into an int8 )
my int $burning = 128; # Red
my int $buf = $w * $h;
my $humidity = .7; # Chance that a tree next to a burning tree will resist catching fire
my $tree-spawn = .75; # Initial probability that a space will contain a tree. Probability
# will be adjusted (way down) once rendering starts.
 
sub render {
 
# work-around to pass the pointer-pointer.
my $pixdata = nativecast(Pointer[int64], $pixdatabuf);
SDL_LockTexture($forest_texture, SDL_Rect, $pixdata, my int $pitch);
 
$pixdata = nativecast(CArray[int8], Pointer.new($pixdatabuf[0]));
 
loop (my int $row; $row < $h; $row = $row + 1) {
my int $rs = $row * $w; # row start
my int $re = $rs + $w; # row end
loop (my int $idx = $rs; $idx < $re; $idx = $idx + 1) {
# Skip it if it is a tree
next if $pixdata[$idx] == $tree;
if $pixdata[$idx] == $bare {
# Maybe spawn a tree on bare ground
$work-buffer[$idx] = rand < $tree-spawn ?? $tree !! $bare;
} elsif $pixdata[$idx] == $heating {
# Check if there are trees around a hot spot and light them if humidity is low enough
$work-buffer[$idx - $w - 1] = $heating if rand > $humidity && $pixdata[$idx - $w - 1] && $row > 0;
$work-buffer[$idx - $w ] = $heating if rand > $humidity && $pixdata[$idx - $w ] && $row > 0;
$work-buffer[$idx - $w + 1] = $heating if rand > $humidity && $pixdata[$idx - $w + 1] && $row > 0;
$work-buffer[$idx - 1 ] = $heating if rand > $humidity && $pixdata[$idx - 1 ];
$work-buffer[$idx + $w - 1] = $heating if rand > $humidity && $pixdata[$idx + $w - 1];
$work-buffer[$idx + $w ] = $heating if rand > $humidity && $pixdata[$idx + $w ];
$work-buffer[$idx + $w + 1] = $heating if rand > $humidity && $pixdata[$idx + $w + 1];
$work-buffer[$idx + 1 ] = $heating if rand > $humidity && $pixdata[$idx + 1 ];
 
# Hotspot becomes a flame
$work-buffer[$idx] = $burning
} else {
# Extinguish a flame after fuel is gone
$work-buffer[$idx] = $bare;
}
}
}
# copy working buffer to main texture buffer
loop (my int $i; $i < $buf; $i = $i + 1) { $pixdata[$i] = $work-buffer[$i] }
 
# start a fire maybe
$pixdata[$buf.rand] = $heating if rand < .1;
 
SDL_UnlockTexture($forest_texture);
 
SDL_RenderCopy($renderer, $forest_texture, SDL_Rect, SDL_Rect.new(:x(0), :y(0), :w($width), :h($height)));
SDL_RenderPresent($renderer);
once $tree-spawn = .005;
}
 
my $event = SDL_Event.new;
 
enum KEY_CODES ( K_Q => 20 );
 
main: loop {
 
while SDL_PollEvent($event) {
my $casted_event = SDL_CastEvent($event);
 
given $casted_event {
when *.type == QUIT {
last main;
}
when *.type == KEYDOWN {
if KEY_CODES(.scancode) -> $comm {
given $comm {
when 'K_Q' { last main }
}
}
}
when *.type == WINDOWEVENT {
if .event == RESIZED {
$width = .data1;
$height = .data2;
}
}
}
}
render();
print fps;
}
say '';
 
sub fps {
state $fps-frames = 0;
state $fps-now = now;
state $fps = '';
$fps-frames++;
if now - $fps-now >= 1 {
$fps = [~] "\b" x 40, ' ' x 20, "\b" x 20 ,
sprintf "FPS: %5.2f ", ($fps-frames / (now - $fps-now)).round(.01);
$fps-frames = 0;
$fps-now = now;
}
$fps
}</lang>
 
=={{header|Phix}}==
Line 6,453 ⟶ 6,244:
I'll tweak with the parameters for a bit, and when I have some nice
photos I'll post them!
 
=={{header|Raku}}==
(formerly Perl 6)
 
===ANSI graphics===
{{works with|rakudo|2015-10-04}}
This version saves a lot of looking around by using four states instead of three; the <tt>Heating</tt> state does a lookahead to track trees that are being heated up by burning trees, so we only ever have to traverse the neighbors of burning trees, not all trees. Also, by only checking the list of burning trees, we can avoid copying the entire forest each iteration, since real forests are mutable.
<lang perl6>my $RED = "\e[1;31m";
my $YELLOW = "\e[1;33m";
my $GREEN = "\e[1;32m";
my $CLEAR = "\e[0m";
enum Cell-State <Empty Tree Heating Burning>;
my @pix = ' ', $GREEN ~ '木', $YELLOW ~ '木', $RED ~ '木';
class Forest {
has Rat $.p = 0.01;
has Rat $.f = 0.001;
has Int $!height;
has Int $!width;
has @!coords;
has @!spot;
has @!neighbors;
 
method BUILD (Int :$!height, Int :$!width) {
@!coords = ^$!height X ^$!width;
@!spot = [ (Bool.pick ?? Tree !! Empty) xx $!width ] xx $!height;
self!init-neighbors;
}
method !init-neighbors {
for @!coords -> ($i, $j) {
@!neighbors[$i][$j] = eager gather for
[-1,-1],[+0,-1],[+1,-1],
[-1,+0], [+1,+0],
[-1,+1],[+0,+1],[+1,+1]
{
take-rw @!spot[$i + .[0]][$j + .[1]] // next;
}
}
}
method step {
my @heat;
for @!coords -> ($i, $j) {
given @!spot[$i][$j] {
when Empty { $_ = Tree if rand < $!p }
when Tree { $_ = Heating if rand < $!f }
when Heating { $_ = Burning; push @heat, ($i, $j); }
when Burning { $_ = Empty }
}
}
for @heat -> ($i,$j) {
$_ = Heating for @!neighbors[$i][$j].grep(Tree);
}
}
method show {
for ^$!height -> $i {
say @pix[@!spot[$i].list].join;
}
}
}
 
my ($ROWS, $COLS) = qx/stty size/.words;
 
signal(SIGINT).act: { print "\e[H\e[2J"; exit }
 
sub MAIN (Int $height = $ROWS - 2, Int $width = +$COLS div 2 - 1) {
my Forest $forest .= new(:$height, :$width);
print "\e[2J"; # ANSI clear screen
loop {
print "\e[H"; # ANSI home
say $++;
$forest.show;
$forest.step;
}
}</lang>
 
===SDL2 Animation===
An alternate version implemented in SDL2.
 
<lang perl6>use NativeCall;
use SDL2::Raw;
 
my ($width, $height) = 900, 900;
 
SDL_Init(VIDEO);
my SDL_Window $window = SDL_CreateWindow(
"Forest Fire - Perl 6",
SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK,
$width, $height,
RESIZABLE
);
my SDL_Renderer $renderer = SDL_CreateRenderer( $window, -1, ACCELERATED +| PRESENTVSYNC );
 
SDL_ClearError();
 
my int ($w, $h) = 200, 200;
 
my $forest_texture = SDL_CreateTexture($renderer, %PIXELFORMAT<RGB332>, STREAMING, $w, $h);
 
my $pixdatabuf = CArray[int64].new(0, $w, $h, $w);
my $work-buffer = CArray[int64].new(0, $w, $h, $w);
 
my int $bare = 0; # Black
my int $tree = 8; # Green
my int $heating = -120; # Orange ( 132 but it's being passed into an int8 )
my int $burning = 128; # Red
my int $buf = $w * $h;
my $humidity = .7; # Chance that a tree next to a burning tree will resist catching fire
my $tree-spawn = .75; # Initial probability that a space will contain a tree. Probability
# will be adjusted (way down) once rendering starts.
 
sub render {
 
# work-around to pass the pointer-pointer.
my $pixdata = nativecast(Pointer[int64], $pixdatabuf);
SDL_LockTexture($forest_texture, SDL_Rect, $pixdata, my int $pitch);
 
$pixdata = nativecast(CArray[int8], Pointer.new($pixdatabuf[0]));
 
loop (my int $row; $row < $h; $row = $row + 1) {
my int $rs = $row * $w; # row start
my int $re = $rs + $w; # row end
loop (my int $idx = $rs; $idx < $re; $idx = $idx + 1) {
# Skip it if it is a tree
next if $pixdata[$idx] == $tree;
if $pixdata[$idx] == $bare {
# Maybe spawn a tree on bare ground
$work-buffer[$idx] = rand < $tree-spawn ?? $tree !! $bare;
} elsif $pixdata[$idx] == $heating {
# Check if there are trees around a hot spot and light them if humidity is low enough
$work-buffer[$idx - $w - 1] = $heating if rand > $humidity && $pixdata[$idx - $w - 1] && $row > 0;
$work-buffer[$idx - $w ] = $heating if rand > $humidity && $pixdata[$idx - $w ] && $row > 0;
$work-buffer[$idx - $w + 1] = $heating if rand > $humidity && $pixdata[$idx - $w + 1] && $row > 0;
$work-buffer[$idx - 1 ] = $heating if rand > $humidity && $pixdata[$idx - 1 ];
$work-buffer[$idx + $w - 1] = $heating if rand > $humidity && $pixdata[$idx + $w - 1];
$work-buffer[$idx + $w ] = $heating if rand > $humidity && $pixdata[$idx + $w ];
$work-buffer[$idx + $w + 1] = $heating if rand > $humidity && $pixdata[$idx + $w + 1];
$work-buffer[$idx + 1 ] = $heating if rand > $humidity && $pixdata[$idx + 1 ];
 
# Hotspot becomes a flame
$work-buffer[$idx] = $burning
} else {
# Extinguish a flame after fuel is gone
$work-buffer[$idx] = $bare;
}
}
}
# copy working buffer to main texture buffer
loop (my int $i; $i < $buf; $i = $i + 1) { $pixdata[$i] = $work-buffer[$i] }
 
# start a fire maybe
$pixdata[$buf.rand] = $heating if rand < .1;
 
SDL_UnlockTexture($forest_texture);
 
SDL_RenderCopy($renderer, $forest_texture, SDL_Rect, SDL_Rect.new(:x(0), :y(0), :w($width), :h($height)));
SDL_RenderPresent($renderer);
once $tree-spawn = .005;
}
 
my $event = SDL_Event.new;
 
enum KEY_CODES ( K_Q => 20 );
 
main: loop {
 
while SDL_PollEvent($event) {
my $casted_event = SDL_CastEvent($event);
 
given $casted_event {
when *.type == QUIT {
last main;
}
when *.type == KEYDOWN {
if KEY_CODES(.scancode) -> $comm {
given $comm {
when 'K_Q' { last main }
}
}
}
when *.type == WINDOWEVENT {
if .event == RESIZED {
$width = .data1;
$height = .data2;
}
}
}
}
render();
print fps;
}
say '';
 
sub fps {
state $fps-frames = 0;
state $fps-now = now;
state $fps = '';
$fps-frames++;
if now - $fps-now >= 1 {
$fps = [~] "\b" x 40, ' ' x 20, "\b" x 20 ,
sprintf "FPS: %5.2f ", ($fps-frames / (now - $fps-now)).round(.01);
$fps-frames = 0;
$fps-now = now;
}
$fps
}</lang>
 
=={{header|REXX}}==
Line 6,831:
T # # TT TT ##TTT
</pre>
 
=={{header|Rust}}==
Inspired by the perl6 implementation, this runs in the terminal, printing a colored ASCII rendition of the forest (and it's fires!). You can configure the size of the forest, frame delay, and various probabilities.
10,343

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.