Forest fire: Difference between revisions

m
fixed "copy pasta" link in Commodore BASIC
(Added ZX81 BASIC)
m (fixed "copy pasta" link in Commodore BASIC)
 
(43 intermediate revisions by 18 users not shown)
Line 26:
 
=={{header|6502 Assembly}}==
<langsyntaxhighlight lang="asm"> ORG $4357
; SYS 17239 or CALL 17239
 
Line 447:
; end COMMODORE 64 specific
 
</syntaxhighlight>
</lang>
 
=={{header|8086 Assembly}}==
 
This program expects to run on an IBM PC with a CGA-compatible video card.
It uses a field size of 320x200 (the CGA screen) and runs at about one frame per second on a 20mhz 286.
 
<syntaxhighlight lang="asm"> ;;; Simulation settings (probabilities are P/65536)
probF: equ 7 ; P(spontaneous combustion) ~= 0.0001
probP: equ 655 ; P(spontaneous growth) ~= 0.01
HSIZE: equ 320 ; Field width (320x200 fills CGA screen)
VSIZE: equ 200 ; Field height
FSIZE: equ HSIZE*VSIZE ; Field size
FPARA: equ FSIZE/16+1 ; Field size in paragraphs
;;; Field values
EMPTY: equ 0 ; Empty cell (also CGA black)
TREE: equ 1 ; Tree cell (also CGA green)
FIRE: equ 2 ; Burning cell (also CGA red)
;;; MS-DOS system calls and values
TOPSEG: equ 2 ; First unavailable segment
puts: equ 9 ; Print a string
time: equ 2Ch ; Get system time
exit: equ 4Ch ; Exit to DOS
;;; BIOS calls and values
palet: equ 0Bh ; Set CGA color pallette
vmode: equ 0Fh ; Get current video mode
keyb: equ 1 ; Get keyboard status
CGALO: equ 4 ; Low-res (4-color) CGA graphics mode
MDA: equ 7 ; MDA monochrome text mode
CGASEG: equ 0B800h ; CGA memory segment
cpu 8086
org 100h
section .text
;;; Program set-up (check memory size and set video mode)
mov sp,stack.top ; Move stack inwards
mov bp,sp ; Set BP to first available paragraph
mov cl,4
shr bp,cl
inc bp
mov dx,cs
add bp,dx
mov bx,[TOPSEG] ; Get first unavailable segment
sub bx,bp ; Get amount of available memory
cmp bx,FPARA*2 ; Enough to fit two fields?
ja mem_ok
mov dx,errmem ; If not, print error message
err: mov ah,puts
int 21h
mov ah,exit ; And stop
int 21h
mem_ok: mov ah,vmode ; Get current video mode
int 10h
push ax ; Keep on stack for later retrieval
cmp al,MDA ; MDA card does not support CGA graphics,
mov dx,errcga ; so print an error and quit.
je err
mov ax,CGALO ; Otherwise, switch to 320x200 CGA mode
int 10h
mov ah,palet ; And set the black/green/red/brown palette
mov bx,0100h
int 10h
mov ah,time ; Get the system time
int 21h
mov [rnddat],cx ; Use it as the RNG seed
mov [rnddat+2],dx
;;; Initialize the field (place trees randomly)
mov es,bp ; ES = field segment
xor di,di ; Start at first field
mov cx,FSIZE ; CX = how many cells to initialize
mov ah,TREE
ptrees: call random ; Get random byte
and al,ah ; Place a tree 50% of the time
stosb
loop ptrees
mov ds,bp ; DS = field segment
;;; Write field to CGA display
disp: xor si,si ; Start at beginning
mov dx,CGASEG ; ES = CGA memory segment
.scrn: mov es,dx
xor di,di ; Start of segment
.line: mov cx,HSIZE/8 ; 8 pixels per word
.word: xor bx,bx ; BX will hold CGA word
xor ah,ah ; Set high byte to zero
%rep 7 ; Unroll this loop for speed
lodsb ; Get cell
or bx,ax ; Put it in low 2 bits of BX
shl bx,1 ; Shift BX to make room for next field
shl bx,1
%endrep
lodsb ; No shift needed for final cell
or ax,bx
stosw ; Store word in CGA memory
loop .word ; Do next byte of line
add si,HSIZE ; Even and odd lines stored separately
cmp si,FSIZE ; Done yet?
jb .line ; If not, do next line
add dx,200h ; Move to next segment
cmp dx,CGASEG+200h ; If we still need to do the odd lines,
mov si,HSIZE ; then do them
jbe .scrn
;;; Stop the program if a key is pressed
mov ah,1 ; Check if a key is pressed
int 16h
jz calc ; If not, calculate next field state
pop ax ; Otherwise, restore the old video mode,
cbw
int 10h
mov ah,exit ; and exit to DOS.
int 21h
;;; Calculate next field state
calc: mov ax,ds ; Set ES = new field segment
add ax,FPARA
mov es,ax
xor di,di ; Start at beginning
xor si,si
.cell: lodsb ; Get cell
dec al ; A=1 = tree
jz .tree
dec al ; A=2 = fire
jz .fire
call rand16 ; An empty space fills with a tree
cmp ax,probP ; with probability P.
jc .mtree ; Otherwise it stays empty
.fire: xor al,al ; A burning tree turns into an empty cell
stosb
jmp .cnext
.mtree: mov al,TREE
stosb
.cnext: cmp si,FSIZE ; Are we there yet?
jne .cell ; If not, do next cell
push es ; Done - set ES=old field, DS=new field,
push ds
pop es
pop ds
mov cx,FSIZE/2
xor si,si
xor di,di
rep movsw ; copy the new field to the old field,
push es ; set DS to be the field to draw,
pop ds
xor di,di ; Instead of doing edge case handling in the
xor ax,ax ; Moore neighbourhood calculation, just zero
mov cx,HSIZE/2 ; out the borders for a slightly smaller image
rep stosw ; Upper border,
mov di,FSIZE-HSIZE
mov cx,HSIZE/2
rep stosw ; lower border,
mov di,HSIZE-5 ; right border.
mov cx,VSIZE-1
.bordr: stosb
add di,HSIZE-1
loop .bordr
jmp disp ; and update the display.
.tree: mov ax,[si-HSIZE-2] ; Load Moore neighbourhood
or al,[si-HSIZE]
or ax,[si-2]
or al,[si]
or ax,[si+HSIZE-2]
or al,[si+HSIZE]
or al,ah
test al,FIRE ; Are any of the trees on fire?
jnz .tburn ; Then set this tree on fire too
call rand16 ; Otherwise, spontaneous combustion?
cmp ax,probF
jc .tburn
mov al,TREE ; If not, the tree remains a tree
stosb
jmp .cnext
.tburn: mov al,FIRE ; Set the tree on fire
stosb
jmp .cnext
;;; Get a random word in AX
rand16: call random
xchg al,ah
;;; Get a random byte in AL. BX and DX destroyed.
random: mov bx,[cs:rnddat] ; BL=X BH=A
mov dx,[cs:rnddat+2] ; DL=B DH=C
inc bl ; X++
xor bh,dh ; A ^= C
xor bh,bl ; A ^= X
add dl,bh ; B += A
mov al,dl ; C' = B
shr al,1 ; C' >>= 1
add al,dh ; C' += C
xor al,bh ; C' ^= A
mov dh,al ; C = C'
mov [cs:rnddat+2],dx ; Update RNG state
mov [cs:rnddat],bx
ret
section .data
errcga: db 'CGA mode not supported.$'
errmem: db 'Not enough memory.$'
section .bss
rnddat: resb 4 ; RNG state
stack: resw 128 ; Stack space
.top: equ $</syntaxhighlight>
 
 
=={{header|Ada}}==
<langsyntaxhighlight Adalang="ada">with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
with Ada.Text_IO; use Ada.Text_IO;
 
Line 518 ⟶ 714:
Put (Forest);
end loop;
end Forest_Fire;</langsyntaxhighlight>
Sample output:
<pre style="height:30ex;overflow:scroll">
Line 612 ⟶ 808:
Y YYY# # YY Y # #Y
</pre>
 
=={{header|ALGOL 68}}==
===Textual version===
Line 618 ⟶ 815:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny].}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
<langsyntaxhighlight lang="algol68">LONG REAL tree prob = 0.55, # original tree probability #
f prob = 0.01, # new combustion probability #
p prob = 0.01; # tree creation probability #
Line 676 ⟶ 873:
printf(($gl$, 2 UPB world * "-"))
OD
)</langsyntaxhighlight>
Output:
<pre>
Line 719 ⟶ 916:
This implementation uses AutoHotkey's pseudo-arrays to contain each cell.
The size of the (square) map, probabilities, and characters which correspond to burning, tree, or empty can be edited at the beginning of the script.
<syntaxhighlight lang="autohotkey">
<lang AutoHotkey>
; The array Frame1%x%_%y% holds the current frame. frame2%x%_%y%
; is then calculated from this, and printed. frame2 is then copied to frame1.
Line 872 ⟶ 1,069:
return 0
}
</syntaxhighlight>
</lang>
Sample Output using the default settings:
<pre style="height:35ex;overflow:scroll;">
Line 933 ⟶ 1,130:
 
=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
{{trans|6502 Assembly}}
<syntaxhighlight lang="gwbasic"> 100 FOR I = 17239 TO 17493
110 READ B
120 POKE I,B
130 NEXT
140 CALL 17239
150 END
160 DATA162,23,138,32,71,248,165,38,157,60,3,165,39,157,84,3,202,16,239,162,96
170 DATA134,249,134,1,160,0,132,0,152,145,0,200,208,251,232,134,1,224,128,208
180 DATA244,44,86,192,44,82,192,44,84,192,44,80,192,32,50,248,162,0,134,0,169
190 DATA41,133,2,133,254,169,83,133,4,165,249,133,1,133,3,133,5,73,16,133,255
200 DATA133,249,138,134,45,74,168,169,15,144,2,105,224,133,46,185,60,3,133,38
210 DATA185,84,3,133,39,160,1,132,44,177,2,145,254,240,79,16,93,169,0,164,44
220 DATA145,254,136,81,38,37,46,81,38,145,38,164,44,200,192,41,208,224,165,2
230 DATA133,0,165,3,133,1,165,4,133,2,133,254,24,105,42,133,4,165,5,73,16
240 DATA133,255,73,16,133,3,105,0,133,5,166,45,232,224,48,208,159,44,0,192
250 DATA48,3,76,144,67,44,16,192,44,81,192,96,198,8,208,190,169,101,133,8,169
260 DATA68,208,169,169,153,208,165,198,6,208,14,198,7,208,10,169,23,133,6,169
270 DATA39,133,7,208,234,177,0,17,4,136,17,0,17,2,17,4,200,200,17,0,17,2,17,4
280 DATA48,213,16,137,41</syntaxhighlight>
 
==={{header|BASIC256}}===
[[File:Forest fire BASIC-256.gif|right|thumb|Forest fire animation: p=0.03, p/f=1000]]
<langsyntaxhighlight lang="basic256">N = 150 : M = 150 : P = 0.03 : F = 0.00003
 
dim f(N+2,M+2) # 1 tree, 0 empty, 2 fire
Line 972 ⟶ 1,191:
next y
next x
end while</langsyntaxhighlight>
 
==={{header|BBC BASIC}}===
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> VDU 23,22,400;400;16,16,16,128
OFF
Line 1,011 ⟶ 1,230:
NEXT x%
old&() = new&()
UNTIL FALSE</langsyntaxhighlight>
Output:
<p>
[[File:Forestbbc.gif|200px]]
 
==={{header|Commodore BASIC}}===
{{trans|6502 Assembly}}
With the keyword CALL changed to SYS, the [[Forest_fire#Applesoft_BASIC|Applesoft BASIC]] code works in Commodore BASIC.
<syntaxhighlight lang="gwbasic"> 100 FOR I = 17239 TO 17493
110 READ B
120 POKE I,B
130 NEXT
140 SYS 17239
150 END
160 DATA162,23,138,32,71,248,165,38,157,60,3,165,39,157,84,3,202,16,239,162,96
170 DATA134,249,134,1,160,0,132,0,152,145,0,200,208,251,232,134,1,224,128,208
180 DATA244,44,86,192,44,82,192,44,84,192,44,80,192,32,50,248,162,0,134,0,169
190 DATA41,133,2,133,254,169,83,133,4,165,249,133,1,133,3,133,5,73,16,133,255
200 DATA133,249,138,134,45,74,168,169,15,144,2,105,224,133,46,185,60,3,133,38
210 DATA185,84,3,133,39,160,1,132,44,177,2,145,254,240,79,16,93,169,0,164,44
220 DATA145,254,136,81,38,37,46,81,38,145,38,164,44,200,192,41,208,224,165,2
230 DATA133,0,165,3,133,1,165,4,133,2,133,254,24,105,42,133,4,165,5,73,16
240 DATA133,255,73,16,133,3,105,0,133,5,166,45,232,224,48,208,159,44,0,192
250 DATA48,3,76,144,67,44,16,192,44,81,192,96,198,8,208,190,169,101,133,8,169
260 DATA68,208,169,169,153,208,165,198,6,208,14,198,7,208,10,169,23,133,6,169
270 DATA39,133,7,208,234,177,0,17,4,136,17,0,17,2,17,4,200,200,17,0,17,2,17,4
280 DATA48,213,16,137,41</syntaxhighlight>
 
==={{header|FreeBASIC}}===
<langsyntaxhighlight lang="freebasic">'[RC] Forest Fire
'written for FreeBASIC
'Program code based on BASIC256 from Rosettacode website
Line 1,124 ⟶ 1,366:
Print " You entered ESC - goodbye "
Print " Press any key to exit "
Sleep</langsyntaxhighlight>
 
==={{header|GFA Basic}}===
 
<langsyntaxhighlight lang="basic">
width%=80
height%=50
Line 1,267 ⟶ 1,509:
CLOSEW 1
RETURN
</syntaxhighlight>
</lang>
 
==={{header|PureBasic}}===
<langsyntaxhighlight PureBasiclang="purebasic">; Some systems reports high CPU-load while running this code.
; This may likely be due to the graphic driver used in the
; 2D-function Plot().
Line 1,436 ⟶ 1,678:
ForEver
EndIf
EndIf</langsyntaxhighlight>
[[Image:Forest_Fire_in_PureBasic,_frame_300.png]]
 
==={{header|REALbasic}}===
This example puts all of the forestry logic into a Thread class. This allows the UI to remain responsive while the Thread does all the work in the background. We create a Thread by subclassing the Thread object in the IDE, in this case creating ''forestfire'' as a subclass of the Thread object and put the following code in its ''Run()'' event:
<langsyntaxhighlight lang="realbasic">
Sub Run()
//Handy named constants
Line 1,507 ⟶ 1,749:
Wend
End Sub
</syntaxhighlight>
</lang>
As you can see, this Thread is expecting a Window object called Window1 with several other objects within it. The IDE will automatically create a Window object called Window1 when a new GUI application is created. Our Window1 has 5 objects (widgets) in it: a Canvas (for displaying graphics), three sliders, and a pushbutton.
<langsyntaxhighlight lang="realbasic">
Sub Open()
//First method to run on the creation of a new Window. We instantiate an instance of our forestFire thread and run it.
Line 1,521 ⟶ 1,763:
stop = True
End Sub
</syntaxhighlight>
</lang>
[[Image:ForestFireRB.PNG]]
 
==={{header|Run BASIC}}===
<langsyntaxhighlight lang="runbasic">graphic #g, 200,200
dim preGen(200,200)
dim newGen(200,200)
Line 1,549 ⟶ 1,791:
next x
next gen
render #g</langsyntaxhighlight>
[[File:ForestFire.png]]
 
Line 1,564 ⟶ 1,806:
 
(2) this program differs from most BASIC examples on Rosetta Code, but resembles most real BASIC programs of more than about 20 lines, in that the line numbers do not always go up smoothly in multiples of ten.
<langsyntaxhighlight lang="basic"> 10 DIM F$(20,30)
20 DIM N$(20,30)
30 LET INIT=.5
Line 1,635 ⟶ 1,877:
1030 LET I$=I$+CHR$ (128+CODE S$(K))
1040 NEXT K
1050 RETURN</langsyntaxhighlight>
{{out}}
Screenshot [http://www.edmundgriffiths.com/zx81forest.jpg here].
Line 1,643 ⟶ 1,885:
This program sits behind a Windows form with fixed borders, the only component of which is a timer (named Timer1, set to something like 50 or 100ms depending on the speed the user wants to see it). Other constant values (the probabilities and the window dimensions) can be set at the top of the code.
 
<langsyntaxhighlight lang="vbnet">Public Class ForestFire
Private _forest(,) As ForestState
Private _isBuilding As Boolean
Line 1,746 ⟶ 1,988:
Me.Text = "Gen " & _gen.ToString() & " @ " & (_gen / (_sw.ElapsedMilliseconds / 1000)).ToString("F02") & " FPS: Forest Fire"
End Sub
End Class</langsyntaxhighlight>
 
==={{header|ZX Spectrum Basic}}===
Line 1,752 ⟶ 1,994:
 
A screenshot of the program running can be found [http://www.edmundgriffiths.com/spectrumforestfire.jpg here].
<langsyntaxhighlight lang="zxbasic"> 10 PAPER 6: CLS
20 DIM n$(20,30)
30 LET init=.5
Line 1,807 ⟶ 2,049:
540 NEXT j
550 NEXT i
560 GO TO 260</langsyntaxhighlight>
 
=={{header|Batch File}}==
Line 1,818 ⟶ 2,060:
</pre>
Default is <code> 10 50 5 5 </code>
<langsyntaxhighlight lang="dos">
@echo off
setlocal enabledelayedexpansion
Line 1,935 ⟶ 2,177:
)
exit /b
</syntaxhighlight>
</lang>
{{out}}
'''Sample Default Output'''
Line 2,018 ⟶ 2,260:
# T T T #
</pre>
 
 
=={{header|C}}==
Line 2,025 ⟶ 2,266:
{{libheader|SDL}}
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
Line 2,272 ⟶ 2,513:
free(field[0]); free(field[1]);
exit(EXIT_SUCCESS);
}</langsyntaxhighlight>
===Console version===
C99. Uncomment srand() for variaty, usleep() for slower speed.
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Line 2,340 ⟶ 2,581:
 
evolve(w, h);
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
 
<syntaxhighlight 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));
}
}
}</syntaxhighlight>
 
=={{header|C++}}==
[[File:ForestFireCpp.png|300px]]
<langsyntaxhighlight lang="cpp">
#include <windows.h>
#include <string>
Line 2,625 ⟶ 3,030:
}
//--------------------------------------------------------------------------------------------------
</syntaxhighlight>
</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}}==
<langsyntaxhighlight lang="ceylon">import ceylon.random { DefaultRandom }
 
abstract class Cell() of tree | dirt | burning {}
Line 2,915 ⟶ 3,156:
forest.evolve();
}
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">
<lang Clojure>
(def burn-prob 0.1)
(def new-tree-prob 0.5)
Line 2,997 ⟶ 3,238:
(forest-fire)
 
</syntaxhighlight>
</lang>
 
example output
Line 3,016 ⟶ 3,257:
=={{header|COBOL}}==
{{works with|OpenCOBOL}}
<langsyntaxhighlight lang="cobol"> IDENTIFICATION DIVISION.
PROGRAM-ID. forest-fire.
 
Line 3,183 ⟶ 3,424:
COMPUTE rand-num =
FUNCTION MOD(FUNCTION RANDOM * 100000, 10000)
.</langsyntaxhighlight>
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defvar *dims* '(10 10))
(defvar *prob-t* 0.5)
(defvar *prob-f* 0.1)
Line 3,259 ⟶ 3,500:
(progn (format t "~%------ Generation ~d ------~%" (1+ i))
(print-forest forest)))))
</syntaxhighlight>
</lang>
Example results:
<langsyntaxhighlight lang="lisp">CL-USER>(defparameter *forest* (make-new-forest))
CL-USER>(simulate *forest* 5)
------ Initial forest ------
Line 3,335 ⟶ 3,576:
TTT TTT T
NIL
</syntaxhighlight>
</lang>
 
=={{header|D}}==
===Textual Version===
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.string, std.algorithm;
 
enum treeProb = 0.55; // Original tree probability.
Line 3,392 ⟶ 3,633:
world.swap(nextWorld);
}
}</langsyntaxhighlight>
{{out}}
<pre> T T T#TT T TT TT TTTT TT TTT T TT T# T T TT TT TTTTT
Line 3,433 ⟶ 3,674:
===Graphical Version===
{{libheader|simpledisplay}}
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.algorithm, std.typetuple,
simpledisplay;
 
Line 3,500 ⟶ 3,741:
painter.drawImage(Point(0, 0), img);
});
}</langsyntaxhighlight>
 
=={{header|Déjà Vu}}==
<langsyntaxhighlight lang="dejavu">#chance of empty->tree
set :p 0.004
#chance of spontaneous tree combustion
Line 3,579 ⟶ 3,820:
step
 
run</langsyntaxhighlight>
{{out}}
<pre>T.T.T...T..T..TT.T.T.
Line 3,616 ⟶ 3,857:
..TTTB....TTTTTT..T.T
TT..T....T..T..TTTT..</pre>
 
=={{header|EasyLang}}==
 
[https://easylang.dev/apps/forest-fire.html Run it]
 
<syntaxhighlight lang="text">
p_fire = 0.00002
p_tree = 0.002
#
len f[] 102 * 102
len p[] len f[]
background 100
clear
for r = 0 to 99
for c = 0 to 99
i = r * 102 + c + 104
if randomf < 0.5
f[i] = 1
.
.
.
timer 0
#
subr show
for r = 0 to 99
for c = 0 to 99
i = r * 102 + c + 104
h = f[i]
if h <> p[i]
move c + 0.5 r + 0.5
if h = 0
color 100
circle 0.6
elif h = 1
color 151
circle 0.5
else
color 9 * 100 + (18 - 2 * h) * 10
circle 0.5
.
.
.
.
.
subr update
swap f[] p[]
for r = 0 to 99
for c = 0 to 99
i = r * 102 + c + 104
if p[i] = 0
f[i] = 0
if randomf < p_tree
f[i] = 1
.
elif p[i] = 1
f[i] = 1
s = p[i - 103] + p[i - 102] + p[i - 101]
s += p[i - 1] + p[i + 1]
s += p[i + 101] + p[i + 102] + p[i + 103]
if s >= 9 or randomf < p_fire
f[i] = 9
.
elif p[i] = 4
f[i] = 0
else
f[i] = p[i] - 1
.
.
.
.
on timer
show
update
timer 0.2
.
</syntaxhighlight>
 
=={{header|Emacs Lisp}}==
<langsyntaxhighlight lang="lisp">#!/usr/bin/env emacs -script
;; -*- lexical-binding: t -*-
;; run: ./forest-fire forest-fire.config
Line 3,714 ⟶ 4,032:
 
(simulate-forest (elt command-line-args-left 0))
</syntaxhighlight>
</lang>
 
The configuration file controls the simulation.
<langsyntaxhighlight lang="lisp">((rows . 10)
(cols . 45)
(time . 100)
Line 3,723 ⟶ 4,041:
(f . 0.001) ;; probability tree ignites
(p . 0.01) ;; probability empty space fills with a tree
(tree . 0.5)) ;; initial probability of tree in a new world</langsyntaxhighlight>
 
{{out}}
Line 3,842 ⟶ 4,160:
Not even text graphics. Notice the use of random:seed/1 when creating a tree. Without it all calls to random:uniform/1 gave the same result for each tree.
 
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( forest_fire ).
 
Line 3,915 ⟶ 4,233:
tree_init( Tree_probalility, Random ) when Tree_probalility > Random -> tree;
tree_init( _Tree_probalility, _Random ) -> empty.
</syntaxhighlight>
</lang>
 
{{out}}
Line 3,998 ⟶ 4,316:
{burning,{5,5}}]
</pre>
 
 
=={{header|Evaldraw}}==
 
[[File:Evaldrawforest.gif|right|thumb|Forest fire animation]]
 
Creates a 256x256 pixel forest, try adjusting the probability for ignite, spread, sprout and max neighbors.
 
<syntaxhighlight lang="c">
enum{XSIZ=255, YSIZ=XSIZ} // size of forest
enum{EMPTY=0, TREE=1, BURN=2} // possible states of a cell
static prob_ignite = .000001; // very rare, but remember we have many trees.
static prob_spread = .25; // Fire spread speed/probability if neighbor on fire
static prob_sprout = 0.25; // probability of new tree to sprout
static MAX_NEIGHBORS = 6; // tree refuses to sprout if overcrowded
static forest[2][YSIZ][XSIZ]; // state of pixel
static fuel[2][YSIZ][XSIZ]; // stores fuel (wood) 0-255
static heat[2][YSIZ][XSIZ]; // tree refuses to spout if heat!=0, also, sets draw color.
static arr_numburn[YSIZ][XSIZ]; // number of burning trees for this cell
static arr_numtree[YSIZ][XSIZ]; // number of neighbor trees for this cell
static xoff[8] = {-1,+0,+1,-1,/*NA*/1,-1,+0,+1}; // offsets to find 8-connected neighbors
static yoff[8] = {-1,-1,-1,+0,/*NA*/0,+1,+1,+1};
() { // Main in evaldraw scripts is a unnamed function.
static otim;
tim = klock(); // Time since program start in seconds.
dt=tim-otim; // Deltatime. 1/dt is FPS. 0 in first frame.
otim=tim; // store old time for next dt.
simulate(); // simulate and draw are coupled, since draw also ping-pongs state.
draw();
setcol(0); fillrect(0,YSIZ,XSIZ,15);
setcol(0xffffff); moveto(0,YSIZ); printf("%4.0ffps generation %5.0f", 1 /dt, numframes);
if (bstatus>0) setFire(mousx,mousy);
}// end main
 
draw() {
for(y=0; y<YSIZ; y++)
for(x=0; x<XSIZ; x++)
{
cell = forest[1][y][x];
if (cell == EMPTY) setcol(0);
else if(cell==BURN) setcol(511-.25*fuel[0][y][x],255-3*heat[0][y][x],33);
else if(cell==TREE) setcol(0,64+fuel[0][y][x],0);
setpix(x,y);
// Transfer next simulation state into current ready for next frame
forest[0][y][x] = forest[1][y][x];
heat[0][y][x] = heat[1][y][x];
fuel[0][y][x] = fuel[1][y][x];
// Count neighbors burning and not
numburn = 0; numtree = 0;
for(n=0; n<8; n++) {
ypos=y+yoff[n];
xpos=x+xoff[n];
if (xpos<0 || xpos > XSIZ-1)continue;
if (ypos<0 || ypos > YSIZ-1)continue;
cell = forest[1][ypos][xpos];
if (cell==BURN) numburn++;
else if (cell==TREE) numtree++;
}
arr_numburn[y][x] = numburn;
arr_numtree[y][x] = numtree;
}
}
 
fillrect(x0,y0,w,h) {
x0=int(x0); y0=int(y0); w=int(w) + 1; h=int(h);
for(y=y0;y<=y0+h;y++) { moveto(x0,y); lineto(x0+w,y); }
}
 
simulate() {
for(y=0; y<YSIZ; y++)
for(x=0; x<XSIZ; x++) {
cell = forest[0][y][x];
cellfuel = fuel[0][y][x];
celltemp = heat[0][y][x];
rand=rnd;
numburn = arr_numburn[y][x];
numtree = arr_numtree[y][x];
if (cell == BURN) {
if (cellfuel <= 0) {
forest[1][y][x] = EMPTY;
}
else {
fuel[1][y][x] = cellfuel - 1;
heat[1][y][x] = celltemp + 1;
}
}
else if (cell == TREE) {
if (numburn == 0 && rand < prob_ignite) setFire(x,y);
else if (numburn > 0 && rand < prob_spread) setFire(x,y);
else if(cellfuel < 255) fuel[1][y][x] = cellfuel + 1;
}
else if (cell == EMPTY) {
if ( celltemp > 0 ) heat[1][y][x] = celltemp - 1;
else if (numburn==0 && rand < prob_sprout && numtree <= MAX_NEIGHBORS) setTree(x,y);
}
}
} // end sim
 
setFire(x,y) {
forest[1][y][x] = BURN;
}
 
setTree(x,y) {
forest[1][y][x] = TREE;
}
</syntaxhighlight>
 
=={{header|F_Sharp|F#}}==
This implementation can be compiled or run in the interactive F# shell.
<langsyntaxhighlight lang="fsharp">open System
open System.Diagnostics
open System.Drawing
Line 4,090 ⟶ 4,517:
[<EntryPoint>]
let main args = ForestFire.main args
#endif</langsyntaxhighlight>
[[File:ForestFire-FSharp.png]]
 
=={{header|Factor}}==
{{works with|Factor|0.99 Development version 2019-07-10}}
<syntaxhighlight lang="factor">USING: combinators grouping kernel literals math math.matrices
math.vectors prettyprint random raylib.ffi sequences ;
IN: rosetta-code.forest-fire
 
! The following private vocab builds up to a useful combinator,
! matrix-map-neighbors, which takes a matrix, a quotation, and
! inside the quotation makes available each element of the
! matrix as well as its neighbors, mapping the result of the
! quotation to a new matrix.
 
<PRIVATE
 
CONSTANT: neighbors {
{ -1 -1 } { -1 0 } { -1 1 }
{ 0 -1 } { 0 1 }
{ 1 -1 } { 1 0 } { 1 1 }
}
 
: ?i,j ( i j matrix -- elt/f ) swapd ?nth ?nth ;
 
: ?i,jths ( seq matrix -- newseq )
[ [ first2 ] dip ?i,j ] curry map ;
 
: neighbor-coords ( loc -- seq )
[ neighbors ] dip [ v+ ] curry map ;
 
: get-neighbors ( loc matrix -- seq )
[ neighbor-coords ] dip ?i,jths ;
 
: matrix>neighbors ( matrix -- seq )
dup dim matrix-coordinates concat
[ swap get-neighbors sift ] with map ;
 
: matrix-map-neighbors ( ... matrix quot: ( ... neighbors elt -- ... newelt ) -- ... newmatrix )
[ [ dim first ] [ matrix>neighbors ] [ concat ] tri ] dip
2map swap group ; inline
 
PRIVATE>
 
 
! ##### Simulation code #####
 
! In our forest,
! 0 = empty
! 1 = tree
! 2 = fire
 
CONSTANT: ignite-probability 1/12000
CONSTANT: grow-probability 1/100
 
: make-forest ( m n probability -- matrix )
[ random-unit > 1 0 ? ] curry make-matrix ;
 
: ?ignite ( -- 1/2 ) ignite-probability random-unit > 2 1 ? ;
: ?grow ( -- 0/1 ) grow-probability random-unit > 1 0 ? ;
 
: next-plot ( neighbors elt -- n )
{
{ [ dup 2 = ] [ 2drop 0 ] }
{ [ 2dup [ [ 2 = ] any? ] [ 1 = ] bi* and ] [ 2drop 2 ] }
{ [ 1 = ] [ drop ?ignite ] }
[ drop ?grow ]
} cond ;
 
: next-forest ( forest -- newforest )
[ next-plot ] matrix-map-neighbors ;
 
 
! ##### Display code #####
 
CONSTANT: colors ${ GRAY GREEN RED }
 
: draw-forest ( matrix -- )
dup dim matrix-coordinates [ concat ] bi@ swap [
[ first2 [ 5 * ] bi@ 5 5 ] dip colors nth draw-rectangle
] 2each ;
 
500 500 "Forest Fire" init-window 100 100 1/2 make-forest
60 set-target-fps
[ window-should-close ] [
begin-drawing
BLACK clear-background dup draw-forest
end-drawing
next-forest
] until drop close-window</syntaxhighlight>
{{out}}
[https://gfycat.com/boilingenviousboto]
 
=={{header|Forth}}==
{{works with|Gforth|0.7.3}}
<langsyntaxhighlight lang="forth">30 CONSTANT WIDTH
30 CONSTANT HEIGHT
WIDTH HEIGHT * CONSTANT SIZE
Line 4,158 ⟶ 4,675:
DUP .FOREST \ print the current state
SWAP ; \ prepare for next iteration
: GO A B BEGIN (GO) AGAIN ;</langsyntaxhighlight>
 
=={{header|Fortran}}==
{{works with|Fortran|95 and later}}
 
<langsyntaxhighlight lang="fortran">module ForestFireModel
implicit none
 
Line 4,345 ⟶ 4,862:
end subroutine forestfire_print
 
end module ForestFireModel</langsyntaxhighlight>
 
<langsyntaxhighlight lang="fortran">program ForestFireTest
use ForestFireModel
implicit none
Line 4,364 ⟶ 4,881:
call forestfire_destroy(f)
 
end program ForestFireTest</langsyntaxhighlight>
 
=={{header|Go}}==
Text. The program prints the configuration, waits for the Enter key, and prints the next. It makes a pretty good animation to just hold down the Enter key.
<langsyntaxhighlight lang="go">package main
 
import (
Line 4,451 ⟶ 4,968:
}
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import SystemControl.RandomMonad (randomRIOreplicateM, unless)
import Data.List (tails, transpose)
import ControlSystem.MonadRandom (liftM2, replicateM, unlessrandomRIO)
 
data Cell
Line 4,463 ⟶ 4,980:
| Fire
deriving (Eq)
 
instance Show Cell where
show Empty = " "
show Tree = "T"
show Fire = "$"
 
randomCell :: IO Cell
randomCell = fmap ([Empty, Tree] !!) (randomRIO (0, 1) :: IO Int)
 
randomChance :: IO Double
randomChance = randomRIO (0, 1.0) :: IO Double
 
rim :: a -> [[a]] -> [[a]]
rim b = fmap (fb b) . (fb =<< rb)
where
fb = liftM2 (.) <$> (:) <*> (flip (++) . return)
rb = fst . unzip . zip (repeat b) . head
 
take3x3 :: [[a]] -> [[[a]]]
take3x3 = concatMap (transpose . fmap take3) . take3
where
take3 = init . init . takeWhile (not . null) . fmap (take 3) . tails
 
list2Mat :: Int -> [a] -> [[a]]
list2Mat n = takeWhile (not . null) . fmap (take n) . iterate (drop n)
 
evolveForest :: Int -> Int -> Int -> IO ()
evolveForest m n k = do
Line 4,510 ⟶ 5,027:
nfs >>= evolve (i + 1)
evolve 1 fs
 
main :: IO ()
main = evolveForest 6 50 3</langsyntaxhighlight>
{{Out}} Sample:
<pre>>>>>>> 1:
Line 4,539 ⟶ 5,056:
=={{header|Icon}} and {{header|Unicon}}==
[[File:Forestfire-Unicon.png|400px|thumb|right|Forest fire 400 x 400 rounds=500 p.initial=0.100000 p/f=0.010000/0.000200 fps=1.495256]]
<langsyntaxhighlight Iconlang="icon">link graphics,printf
 
$define EDGE 0
Line 4,611 ⟶ 5,128:
procedure probability(P) #: succeed with probability P
if ?0 <= P then return
end</langsyntaxhighlight>
 
{{libheader|Icon Programming Library}}
Line 4,618 ⟶ 5,135:
 
=={{header|J}}==
<langsyntaxhighlight lang="j">NB. states: 0 empty, 1 tree, _1 fire
dims =:10 10
 
Line 4,638 ⟶ 5,155:
smoutput ' #o' {~ forest=. step forest
end.
)</langsyntaxhighlight>
 
Example use:
 
<langsyntaxhighlight lang="j"> run 2
##### #
Line 4,661 ⟶ 5,178:
## # #
o #
o# # </langsyntaxhighlight>
 
Note that I have used an artificially small grid here, and that I ran this several times until I could find one that had a fire from the start. Also, the current revision of this code does not show the starting state, though that would be easily changed.
Line 4,668 ⟶ 5,185:
 
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}}==
<syntaxhighlight 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;</syntaxhighlight>
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}}==
{{works with|Java|1.5+}}
===Text===
<langsyntaxhighlight lang="java5">import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
Line 4,808 ⟶ 5,345:
processNPrint(land, 10);
}
}</langsyntaxhighlight>
===Graphics===
See: [[Forest fire/Java/Graphics]]
 
=={{header|JAMES II/Rule-based Cellular AutomataJavaScript}}==
<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 ===
 
Functional approach using [https://lodash.com/ lodash]
 
<langsyntaxhighlight lang="javascript">"use strict"
 
const _ = require('lodash');
Line 4,904 ⟶ 5,423:
}, 20);
 
</syntaxhighlight>
</lang>
 
 
=={{header|JavaScript}}==
===JavaScript===
<lang javascript>var forest = {
<syntaxhighlight lang="javascript">var forest = {
X: 50,
Y: 50,
Line 4,970 ⟶ 5,490:
afterLoad(forest);
}, 100);
</syntaxhighlight>
</lang>
 
To actually see it work we need a small demo page with HTML5 compliant code:
 
<langsyntaxhighlight lang="html5"><!DOCTYPE html>
<html>
<head>
Line 4,988 ⟶ 5,508:
</body>
</html>
</syntaxhighlight>
</lang>
 
The output is a (mostly fluent) animation of the area.
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">#using v0.6Printf
 
@enum State empty tree fire
Line 5,012 ⟶ 5,532:
end
end
for i in linearindicesLinearIndices(forest)
# A burning cell turns into an empty cell
if forest[i] == fire forest[i] = empty end
Line 5,053 ⟶ 5,573:
end
 
evolution()</langsyntaxhighlight>
 
{{out}}
Line 5,092 ⟶ 5,612:
=={{header|Lua}}==
This program uses the Lua Curses library for graphics, although changing the code to avoid such dependency is easy.
<syntaxhighlight lang="lua">
<lang Lua>
-- ForestFire automaton implementation
-- Rules: at each step:
Line 5,190 ⟶ 5,710:
socket.sleep(naptime)
until false
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
Mathematica is good at working with cellular automata -- especially 2-color 1-dimensional cellular automata. The automaton function is awkward yet very powerful. This code implements a 3-color 2-dimensional cellular automaton with 9-cell neighbourhoods using a custom cell evolution function. There is probably a rule number specification that can replace the custom evolution function and make this simpler and faster. But this works well enough. The last line of code plots the state of the forest after the 300th step.
 
<langsyntaxhighlight Mathematicalang="mathematica">evolve[nbhd_List, k_] := 0 /; nbhd[[2, 2]] == 2 (*burning->empty*)
evolve[nbhd_List, k_] := 2 /; nbhd[[2, 2]] == 1 && Max@nbhd == 2 (*near_burning&nonempty->burning*)
evolve[nbhd_List, k_] := RandomChoice[{f, 1 - f} -> {2, nbhd[[2, 2]]}] /; nbhd[[2, 2]] == 1 && Max@nbhd < 2 (*spontaneously combusting tree*)
Line 5,202 ⟶ 5,722:
r = 100; c = 100; p = 10^-2; f = 10^-4;
init = RandomInteger[BernoulliDistribution[0.05], {r, c}];
MatrixPlot[CellularAutomaton[{evolve, {}, {1, 1}}, {init, 0}, {{{300}}}], ColorRules -> {0 -> White, 1 -> Green, 2 -> Red}, Frame -> False]</langsyntaxhighlight>
[[File:ForestFire-Mathematica.png]]
 
=={{header|MATLAB}} / {{header|Octave}}==
<langsyntaxhighlight MATLABlang="matlab">function forest_fire(f,p,N,M)
% Forest fire
if nargin<4;
Line 5,234 ⟶ 5,754:
G = G + (F==3); % empty after burn
F = G;
end; </langsyntaxhighlight>
 
=={{header|Nim}}==
{{trans|C}}
<langsyntaxhighlight lang="nim">import mathrandom, os, sequtils, strutils
 
randomize()
 
type State {.pure.} = enum Empty, Tree, Fire
 
const
dispDisp: array[State, string] = [" ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
treeProbTreeProb = 0.01
burnProbBurnProb = 0.001
 
proc chance(prob: float): bool {.inline.} = randomrand(1.0) < prob
 
# Set the size
var w, h: int
if paramCount() >= 2:
w = parseInt paramStr (1).parseInt
h = parseInt paramStr (2).parseInt
if w <= 0: w = 30
if h <= 0: h = 30
 
iterator fields(a = (0, 0), b = (h-1, w-1)): tuple[y, x: int] =
# Iterate over fields in the universe
## Iterate over fields in the universe
iterator fields(a = (0,0), b = (h-1,w-1)) =
for y in max(a[0], 0) .. min(b[0], h-1):
for x in max(a[1], 0) .. min(b[1], w-1):
yield (y, x)
 
# Create a sequence with an initializer
proc newSeqWith[T](len: int, init: T): seq[T] =
result = newSeq[T] len
for i in 0 .. <len:
result[i] = init
 
# Initialize
var univ, univNew = newSeqWith(h, newSeq[State] (w))
 
while true:
 
# Show
# Show.
stdout.write "\e[H"
for y, x in fields():
stdout.write dispDisp[univ[y][x]]
if x == 0: stdout.write "\e[E"
stdout.flushFile
 
# Evolve.
for y, x in fields():
case univ[y][x]
of Fire:
univNew[y][x] = Empty
of Empty:
if chance treeProb(TreeProb): univNew[y][x] = Tree
of Tree:
for y1, x1 in fields((y-1, x-1), (y+1, x+1)):
if univ[y1][x1] == Fire: univNew[y][x] = Fire
if chance burnProb: univNew[y][x] = Fire
break
if chance(BurnProb): univNew[y][x] = Fire
univ = univNew
sleep 200</langsyntaxhighlight>
 
=={{header|OCaml}}==
Line 5,300 ⟶ 5,818:
This example uses a curses display (with the [http://www.nongnu.org/ocaml-tmk/ ocaml-curses] bindings).
 
<langsyntaxhighlight lang="ocaml">open Curses
 
let ignite_prob = 0.02
Line 5,372 ⟶ 5,890:
Unix.sleep 1;
done;
endwin()</langsyntaxhighlight>
 
You can execute this script with:
$ ocaml unix.cma -I +curses curses.cma forest.ml
 
=={{header|Ol}}==
<syntaxhighlight lang="scheme">
(import (lib gl))
(import (otus random!))
 
(define WIDTH 170)
(define HEIGHT 96)
 
; probabilities
(define p 20)
(define f 1000)
 
(gl:set-window-title "Drossel and Schwabl 'forest-fire'")
(import (OpenGL version-1-0))
 
(glShadeModel GL_SMOOTH)
(glClearColor 0.11 0.11 0.11 1)
(glOrtho 0 WIDTH 0 HEIGHT 0 1)
 
(gl:set-userdata (make-vector (map (lambda (-) (make-vector (map (lambda (-) (rand! 2)) (iota WIDTH)))) (iota HEIGHT))))
 
(gl:set-renderer (lambda (mouse)
(let ((forest (gl:get-userdata))
(step (make-vector (map (lambda (-) (make-vector (repeat 0 WIDTH))) (iota HEIGHT)))))
(glClear GL_COLOR_BUFFER_BIT)
 
(glPointSize (/ 854 WIDTH))
(glBegin GL_POINTS)
(for-each (lambda (y)
(for-each (lambda (x)
(case (ref (ref forest y) x)
(0 ; An empty space fills with a tree with probability "p"
(if (zero? (rand! p))
(set-ref! (ref step y) x 1)))
(1
(glColor3f 0.2 0.7 0.2)
(glVertex2f x y)
; A tree will burn if at least one neighbor is burning
; A tree ignites with probability "f" even if no neighbor is burning
(if (or (eq? (ref (ref forest (- y 1)) (- x 1)) 2) (eq? (ref (ref forest (- y 1)) x) 2) (eq? (ref (ref forest (- y 1)) (+ x 1)) 2)
(eq? (ref (ref forest y ) (- x 1)) 2) (eq? (ref (ref forest y ) (+ x 1)) 2)
(eq? (ref (ref forest (+ y 1)) (- x 1)) 2) (eq? (ref (ref forest (+ y 1)) x) 2) (eq? (ref (ref forest (+ y 1)) (+ x 1)) 2)
(zero? (rand! f)))
(set-ref! (ref step y) x 2)
(set-ref! (ref step y) x 1)))
(2
(glColor3f 0.7 0.7 0.1)
(glVertex2f x y))
; A burning cell turns into an empty cell
(set-ref! (ref step y) x 0)))
(iota WIDTH)))
(iota HEIGHT))
(glEnd)
(gl:set-userdata step))))
</syntaxhighlight>
 
=={{header|PARI/GP}}==
<langsyntaxhighlight lang="parigp">step(M,p,f)={
my(m=matsize(M)[1],n=matsize(M)[2]);
matrix(m,n,i,j,
Line 5,402 ⟶ 5,976:
while(1,print(M=step(M,p,f)))
};
burn(5,.1,.03)</langsyntaxhighlight>
 
 
=={{header|Perl}}==
Requires terminal that understands ANSI escape sequences:<langsyntaxhighlight Perllang="perl">
use 5.10.0;
 
Line 5,469 ⟶ 6,042:
}
 
forest while (1);</langsyntaxhighlight>
 
=={{header|=Alternate Perl 6}}Solution===
<syntaxhighlight lang="perl">use strict;
{{works with|rakudo|2015-10-04}}
use warnings;
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.
use feature 'bitwise';
<lang perl6>my $RED = "\e[1;31m";
 
my $YELLOW = "\e[1;33m";
my $p = 0.01; # probability of empty -> tree
my $GREEN = "\e[1;32m";
my $f = 0.0001; # probability of tree -> burning
my $CLEAR = "\e[0m";
 
my ($high, $wide) = split ' ', qx(stty size); # 135 174 tiny font in xterm
my $mask = 0 x $wide . (0 . 7 x ($wide - 2) . 0) x ($high - 5) . 0 x $wide;
my $forest = $mask =~ s/7/ rand() < 0.5 ? 2 : 1 /ger;
 
for( 1 .. 1e3 )
{ # 0=border 1=empty 2=tree 3=burning
print "\e[H", $forest =~ tr/0123/ ^#/r, "\n"; # ^=tree #=burning tree
my $n = $forest =~ tr/123/004/r; # 4=a neighbor is burning
$forest |.= 0 x $_ . $n |. substr $n, $_ for 1, $wide - 1 .. $wide + 1;
$forest &.= $mask; # clear borders and trim
$forest =~ tr/1-7/et10e31/; # step to next generation
$forest =~ s/t/ rand() < $f ? 3 : 2 /ge; # rule 3) tree cell to burning
$forest =~ s/e/ rand() < $p ? 2 : 1 /ge; # rule 4) empty cell to tree
select undef, undef, undef, 0.1; # comment out for full speed
}</syntaxhighlight>
 
=={{header|Phix}}==
{{libheader|Phix/pGUI}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Forest_fire.exw
-- ============================
--
-- A burning cell turns into an empty cell
-- A tree will burn if at least one neighbor is burning
-- A tree ignites with probability F even if no neighbor is burning
-- An empty space fills with a tree with probability P
--
-- Draws bigger "pixels" when it feels the need to.
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hTimer</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Forest Fire"</span><span style="color: #0000FF;">,</span>
enum Cell-State <Empty Tree Heating Burning>;
<span style="color: #000000;">P</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.03</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- probability of new tree growing</span>
my @pix = ' ', $GREEN ~ '木', $YELLOW ~ '木', $RED ~ '木';
<span style="color: #000000;">F</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.00003</span> <span style="color: #000080;font-style:italic;">-- probability of new fire starting</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">EMPTY</span><span style="color: #0000FF;">,</span><span style="color: #000000;">TREE</span><span style="color: #0000FF;">,</span><span style="color: #000000;">FIRE</span> <span style="color: #000080;font-style:italic;">-- (1,2,3)</span>
class Forest {
<span style="color: #008080;">constant</span> <span style="color: #000000;">colours</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #004600;">CD_BLACK</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_GREEN</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_YELLOW</span><span style="color: #0000FF;">}</span>
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;
}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- the forest</span>
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;
}
}
}
<span style="color: #008080;">function</span> <span style="color: #000000;">randomf</span><span style="color: #0000FF;">()</span>
method step {
<span style="color: #008080;">return</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1000000</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">1000000</span> <span style="color: #000080;font-style:italic;">-- returns 0.000001..1.000000</span>
my @heat;
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
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);
}
}
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
method show {
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">),</span>
for ^$!height -> $i {
<span style="color: #000080;font-style:italic;">-- limit to 40K cells, otherwise it gets too slow.
say @pix[@!spot[$i].list].join;
-- n here is the cell size in pixels (min of 1x1)
}
-- Note you still get some setTimeout violations
}
-- in js even with the limit reduced to just 5K..</span>
}
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">ceil</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">*</span><span style="color: #000000;">height</span><span style="color: #0000FF;">/</span><span style="color: #000000;">40000</span><span style="color: #0000FF;">)),</span>
 
<span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">/</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- (see cx below)</span>
my ($ROWS, $COLS) = qx/stty size/.words;
<span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">height</span><span style="color: #0000FF;">/</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">2</span>
 
signal(SIGINT).act: { print "\e[H\e[2J"; exit }
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
 
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">w</span>
sub MAIN (Int $height = $ROWS - 2, Int $width = +$COLS div 2 - 1) {
<span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])!=</span><span style="color: #000000;">h</span> <span style="color: #008080;">then</span>
my Forest $forest .= new(:$height, :$width);
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_rand</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">),</span><span style="color: #000000;">w</span><span style="color: #0000FF;">))</span> <span style="color: #000080;font-style:italic;">-- (EMPTY or TREE)</span>
print "\e[2J"; # ANSI clear screen
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
loop {
<span style="color: #004080;">sequence</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
print "\e[H"; # ANSI home
<span style="color: #000080;font-style:italic;">--
say $++;
-- There is a "dead border" of 1 cell all around the edge of f (& fn) which
$forest.show;
-- we never display or update. If we have got this right/an exact fit, then
$forest.step;
-- w*n should be exactly 2n too wide, whereas in the worst case there is an
}
-- (2n-1) pixel border, which we split between left and right, ditto cy.
}</lang>
--</span>
 
<span style="color: #004080;">integer</span> <span style="color: #000000;">cx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">width</span><span style="color: #0000FF;">-</span><span style="color: #000000;">w</span><span style="color: #0000FF;">*</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
=={{header|Phix}}==
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
{{libheader|pGUI}}
<span style="color: #004080;">integer</span> <span style="color: #000000;">cy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">height</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">*</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<lang Phix>--
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
-- demo\rosetta\Forest_fire.exw
<span style="color: #004080;">integer</span> <span style="color: #000000;">fnxy</span>
--
<span style="color: #008080;">switch</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
include pGUI.e
<span style="color: #008080;">case</span> <span style="color: #000000;">EMPTY</span><span style="color: #0000FF;">:</span>
 
<span style="color: #000000;">fnxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">EMPTY</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">randomf</span><span style="color: #0000FF;">()<</span><span style="color: #000000;">P</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (EMPTY or TREE)</span>
Ihandle dlg, canvas, hTimer
<span style="color: #008080;">case</span> <span style="color: #000000;">TREE</span><span style="color: #0000FF;">:</span>
cdCanvas cddbuffer, cdcanvas
<span style="color: #000000;">fnxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">TREE</span>
 
<span style="color: #008080;">if</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span>
constant TITLE = "Forest Fire"
<span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span> <span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">randomf</span><span style="color: #0000FF;">()<</span><span style="color: #000000;">F</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span> <span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span>
 
<span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">or</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">FIRE</span> <span style="color: #008080;">then</span>
sequence f = {} -- the forest
<span style="color: #000000;">fnxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">FIRE</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
atom P = 0.03 -- probability of new tree growing
<span style="color: #008080;">case</span> <span style="color: #000000;">FIRE</span><span style="color: #0000FF;">:</span>
atom F = 0.00003 -- probability of new fire starting
<span style="color: #000000;">fnxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">EMPTY</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span>
enum EMPTY,TREE,FIRE -- (1,2,3)
<span style="color: #000000;">fn</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fnxy</span>
constant colours = {CD_BLACK,CD_GREEN,CD_YELLOW}
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fnxy</span><span style="color: #0000FF;">])</span>
 
<span style="color: #7060A8;">cdCanvasBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
function randomf()
<span style="color: #000000;">cy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">n</span>
return rand(1000000)/1000000 -- returns 0.000001..1.000000
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #000000;">cx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">n</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fn</span>
integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE")
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
cdCanvasActivate(cddbuffer)
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
if length(f)!=w+2
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
or length(f[1])!=h+2 then
f = sq_rand(repeat(repeat(2,h+2),w+2)) -- (EMPTY or TREE)
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
sequence fn = f
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
for x = 2 to w+1 do
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
for y = 2 to h+1 do
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
integer fnxy
switch f[x,y] do
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
case EMPTY:
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
fnxy = EMPTY+(randomf()<P) -- (EMPTY or TREE)
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
case TREE:
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
fnxy = TREE
if f[x-1,y-1]=FIRE or f[x,y-1]=FIRE or f[x+1,y-1]=FIRE
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
or f[x-1,y ]=FIRE or (randomf()<F) or f[x+1,y ]=FIRE
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
or f[x-1,y+1]=FIRE or f[x,y+1]=FIRE or f[x+1,y+1]=FIRE then
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=225x100"</span><span style="color: #0000FF;">)</span>
fnxy = FIRE
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
end if
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">)})</span>
case FIRE:
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">`TITLE="%s", MINSIZE=245x140`</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">TITLE</span><span style="color: #0000FF;">})</span>
fnxy = EMPTY
<span style="color: #000080;font-style:italic;">-- (above MINSIZE prevents the title from getting squished)</span>
end switch
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
fn[x,y] = fnxy
<span style="color: #000000;">hTimer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (10 fps)</span>
cdCanvasPixel(cddbuffer, x-2, y-2, colours[fnxy])
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
end for
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
end for
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
f = fn
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
cdCanvasFlush(cddbuffer)
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
return IUP_DEFAULT
end function
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
 
<!--</syntaxhighlight>-->
function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih)
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
return IUP_DEFAULT
end function
 
function key_cb(Ihandle /*ih*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
return IUP_CONTINUE
end function
 
function timer_cb(Ihandle /*ih*/)
IupUpdate(canvas)
return IUP_IGNORE
end function
 
procedure main()
IupOpen()
 
canvas = IupCanvas(NULL)
IupSetAttribute(canvas, "RASTERSIZE", "200x200") -- initial size
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
 
dlg = IupDialog(canvas)
IupSetAttribute(dlg, "TITLE", TITLE)
IupSetAttribute(dlg, "MAXSIZE", "800x400") -- (too slow any bigger)
IupSetCallback(dlg, "K_ANY", Icallback("key_cb"))
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
 
hTimer = IupTimer(Icallback("timer_cb"), 100)
 
IupMap(dlg)
IupSetAttribute(canvas, "RASTERSIZE", NULL) -- release min limitation
IupShow(dlg)
IupMainLoop()
IupClose()
end procedure
 
main()</lang>
 
=={{header|PHP}}==
<langsyntaxhighlight PHPlang="php"><?php
 
define('WIDTH', 10);
Line 5,756 ⟶ 6,294:
return rand(0, 100) < $prob;
}
</syntaxhighlight>
</lang>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(load "@lib/simul.l")
 
(scl 3)
Line 5,801 ⟶ 6,339:
(put This @ T)
(=: burn)
(=: tree) ) ) ) ) ) )</langsyntaxhighlight>
Use:
<pre>(forestFire 26 0.5 0.01 0.001)</pre>
 
=={{header|PostScript}}==
<langsyntaxhighlight PostScriptlang="postscript">%!PS-Adobe-3.0
%%BoundingBox: 0 0 400 400
 
Line 5,869 ⟶ 6,407:
 
1000 { drawforest showpage iter } repeat
%%EOF</langsyntaxhighlight>
 
=={{header|Python}}==
Just hit return to advance the simulation, or enter an integer to advance that integer amount of 'frames'.
Entering 'p' will print the grid, and 'q' will quit. A summary of the grids status is printed before each prompt for input.
<langsyntaxhighlight lang="python">'''
Forest-Fire Cellular automation
See: http://en.wikipedia.org/wiki/Forest-fire_model
Line 5,956 ⟶ 6,494:
break
grid = gnew(grid)
iter +=1</langsyntaxhighlight>
 
'''Sample output'''
Line 6,016 ⟶ 6,554:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(require 2htdp/universe)
(require 2htdp/image)
Line 6,075 ⟶ 6,613:
[to-draw render-forest]))
 
(forest-fire 0 1/8 1/1024 50)</langsyntaxhighlight>
 
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.
<syntaxhighlight lang="raku" line>constant $RED = "\e[1;31m";
constant $YELLOW = "\e[1;33m";
constant $GREEN = "\e[1;32m";
constant $CLEAR = "\e[0m";
# make sure we clear colors at the end
END print $CLEAR;
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;
}
}</syntaxhighlight>
 
===SDL2 Animation===
An alternate version implemented in SDL2.
 
<syntaxhighlight lang="raku" line>use NativeCall;
use SDL2::Raw;
 
my ($width, $height) = 900, 900;
 
SDL_Init(VIDEO);
my SDL_Window $window = SDL_CreateWindow(
"Forest Fire - Raku",
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
}</syntaxhighlight>
 
=={{header|REXX}}==
Line 6,087 ⟶ 6,836:
 
Glyphs were chosen in an attempt to pictorialize a tree &nbsp; (<big>↑</big>) &nbsp; and also a fire &nbsp; (<big>▒</big>).
<br>The choice of glyphs within the code page '''437''' &nbsp; (DOS and/or under Windows) is rather limited.
 
ThereThe ischoice oneof (OS)glyphs dependency:within &nbsp;the usecode of the &nbsp;page '''CLS437''' &nbsp; (DOS) commandand/or whichunder Windows) is usedrather tolimited. clear the screen.
 
There is one (OS) dependency: &nbsp; use of the &nbsp; '''CLS''' &nbsp; (DOS) command which is used to clear the screen &nbsp; (the original
<br>version examined the host environment and used the correct command to clear the terminal screen).
<pre>
┌───────────────────────────elided version──────────────────────────┐
Line 6,095 ⟶ 6,846:
└───────────────────────────────────────────────────────────────────┘
</pre>
<langsyntaxhighlight lang="rexx">/*REXX program grows and displays a forest (with growth and fires caused by lightning).*/
parse value scrSize() with sd sw . /*the size of the terminal display. */
parse arg generations birth lightning rSeed . /*obtain the optional arguments from CL*/
Line 6,144 ⟶ 6,895:
return random(1, field) <= lightning /*lightning ignition*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
p: return word(arg(1), 1) /*pick─a─word: first or second word.*/</langsyntaxhighlight>
This REXX program makes use of &nbsp; '''scrSize''' &nbsp; REXX program (or BIF) &nbsp; which is used to determine the screen size of the terminal (console).
<br>The &nbsp; '''SCRSIZE.REX''' &nbsp; REXX program is included here &nbsp; ──► &nbsp; &nbsp;[[SCRSIZE.REX]]. <br><br>
Line 6,207 ⟶ 6,958:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Forest fire
# Date : 2018/01/13
# Author : Gal Zsolt (~ CalmoSoft ~)
# Email : <calmosoft@gmail.com>
 
 
load "guilib.ring"
Line 6,296 ⟶ 7,043:
label1 { setpicture(p1) show() }
return
</syntaxhighlight>
</lang>
Output:
 
Line 6,302 ⟶ 7,049:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">class Forest_Fire
Neighborhood = [-1,0,1].product([-1,0,1]) - [0,0]
States = {empty:" ", tree:"T", fire:"#"}
Line 6,345 ⟶ 7,092:
forest.evolve
forest.display
end</langsyntaxhighlight>
Sample Output:
<pre style="height:64ex;overflow:scroll">
Line 6,459 ⟶ 7,206:
T # # TT TT ##TTT
</pre>
 
=={{header|Rust}}==
Inspired by the perl6Raku 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.
{{libheader|rand}}
{{libheader|ansi_term}}
<langsyntaxhighlight lang="rust">extern crate rand;
extern crate ansi_term;
 
Line 6,621 ⟶ 7,369:
write!(writer, "{}", String::from_utf8_lossy(&output.stdout)).unwrap();
}
</syntaxhighlight>
</lang>
 
=={{header|Sather}}==
<langsyntaxhighlight lang="sather">class FORESTFIRE is
private attr fields:ARRAY{ARRAY{INT}};
private attr swapu:INT;
Line 6,819 ⟶ 7,567:
end;
 
end;</langsyntaxhighlight>
 
=={{header|Scala}}==
<langsyntaxhighlight lang="scala">import scala.util.Random
 
class Forest(matrix:Array[Array[Char]]){
Line 6,849 ⟶ 7,597:
val EMPTY='.'
def apply(x:Int=30, y:Int=15)=new Forest(Array.tabulate(y, x)((y,x)=> if (Random.nextDouble<0.5) TREE else EMPTY))
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="scala">object ForestFire{
def main(args: Array[String]): Unit = {
var l=Forest()
Line 6,859 ⟶ 7,607:
}
}
}</langsyntaxhighlight>
Sample output:
<pre>.T..TTT.TT .T..TTT.TT TT..TTT.TT TT..TTTTTT TT..TTTTTT
Line 6,874 ⟶ 7,622:
=={{header|Sidef}}==
{{trans|Perl}}
<langsyntaxhighlight lang="ruby">define w = `tput cols`.to_i-1
define h = `tput lines`.to_i-1
define r = "\033[H"
Line 6,934 ⟶ 7,682:
}
 
loop { init_forest() }</langsyntaxhighlight>
 
{{trans|Perl 6Raku}}
OO approach:
<langsyntaxhighlight lang="ruby">define RED = "\e[1;31m"
define YELLOW = "\e[1;33m"
define GREEN = "\e[1;32m"
Line 7,009 ⟶ 7,757:
forest.show
forest.step
}</langsyntaxhighlight>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
# Build a grid
Line 7,089 ⟶ 7,837:
printGrid
if {[gets stdin line] < 0} break
}</langsyntaxhighlight>
Sample output:
<pre>
Line 7,140 ⟶ 7,888:
=={{header|uBasic/4tH}}==
It's a small forest, since it's a small interpreter.
<syntaxhighlight lang="text">B = 1 ' A burning tree
E = 16 ' An empty space
T = 256 ' A living tree
Line 7,246 ⟶ 7,994:
Next ' Try next row
 
Return (T) ' No burning trees found</langsyntaxhighlight>
{{out}}
<pre> @ @ @ @
Line 7,283 ⟶ 8,031:
 
Note: In order to display the graphics characters correctly, use DOS (OEM) font such as "Terminal".
<langsyntaxhighlight lang="vedit">#1 = 25 // height of the grid
#2 = 60 // width of the grid
#3 = 2 // probability of random fire, per 1000
Line 7,357 ⟶ 8,105:
#93 = 0x7fffffff % 48271
#90 = (48271 * (#90 % #92) - #93 * (#90 / #92)) & 0x7fffffff
return ((#90 & 0xffff) * #91 / 0x10000)</langsyntaxhighlight>
 
Sample output, 10th generation:
Line 7,389 ⟶ 8,137:
--------------------------------------------------------------
</pre>
 
=={{header|V (Vlang)}}==
Text. The program prints the configuration, waits for enter key, and prints the next. It makes a pretty good animation to just hold down the enter key.
{{trans|go}}
<syntaxhighlight lang="v (vlang)">import rand
import strings
import os
const (
rows = 20
cols = 30
p = .01
f = .001
)
const rx = rows + 2
const cx = cols + 2
fn main() {
mut odd := []string{len: rx*cx}
mut even := []string{len: rx*cx}
for r := 1; r <= rows; r++ {
for c := 1; c <= cols; c++ {
if rand.intn(2) or {1} == 1 {
odd[r*cx+c] = 'T'
}
}
}
mut _ := ''
for {
print_row(odd)
step(mut even, odd)
_ = os.input('')
print_row(even)
step(mut odd, even)
_ = os.input('')
}
}
fn print_row(model []string) {
println(strings.repeat_string("__", cols))
println('')
for r := 1; r <= rows; r++ {
for c := 1; c <= cols; c++ {
if model[r*cx+c] == '0' {
print(" ")
} else {
print(" ${model[r*cx+c]}")
}
}
println('')
}
}
fn step(mut dst []string, src []string) {
for r := 1; r <= rows; r++ {
for c := 1; c <= cols; c++ {
x := r*cx + c
dst[x] = src[x]
match dst[x] {
'#' {
// rule 1. A burning cell turns into an empty cell
dst[x] = '0'
}
'T' {
// rule 2. A tree will burn if at least one neighbor is burning
if src[x-cx-1]=='#' || src[x-cx]=='#' || src[x-cx+1]=='#' ||
src[x-1] == '#' || src[x+1] == '#' ||
src[x+cx-1]=='#' || src[x+cx]=='#' || src[x+cx+1] == '#' {
dst[x] = '#'
 
// rule 3. A tree ignites with probability f
// even if no neighbor is burning
} else if rand.f64() < f {
dst[x] = '#'
}
}
else {
// rule 4. An empty space fills with a tree with probability p
if rand.f64() < p {
dst[x] = 'T'
}
}
}
}
}
}</syntaxhighlight>
 
=={{header|Wren}}==
{{trans|Go}}
<syntaxhighlight lang="wren">import "random" for Random
import "io" for Stdin
 
var rand = Random.new()
var rows = 20
var cols = 30
var p = 0.01
var f = 0.001
var rx = rows + 2
var cx = cols + 2
 
var step = Fn.new { |dst, src|
for (r in 1..rows) {
for (c in 1..cols) {
var x = r*cx + c
dst[x] = src[x]
if (dst[x] == "#") {
// rule 1. A burning cell turns into an empty cell
dst[x] = " "
} else if(dst[x] == "T") {
// rule 2. A tree will burn if at least one neighbor is burning
if (src[x-cx-1] == "#" || src[x-cx] == "#" || src[x-cx+1] == "#" ||
src[x-1] == "#" || src[x+1] == "#" ||
src[x+cx-1] == "#" || src[x+cx] == "#" || src[x+cx+1] == "#") {
dst[x] = "#"
// rule 3. A tree ignites with probability f
// even if no neighbor is burning
} else if (rand.float() < f) {
dst[x] = "#"
}
} else {
// rule 4. An empty space fills with a tree with probability p
if (rand.float() < p) dst[x] = "T"
}
}
}
}
 
var print = Fn.new { |model|
System.print("__" * cols)
System.print()
for (r in 1..rows) {
for (c in 1..cols) System.write(" %(model[r*cx+c])")
System.print()
}
}
 
var odd = List.filled(rx*cx, " ")
var even = List.filled(rx*cx, " ")
for (r in 1 ..rows) {
for (c in 1..cols) {
if (rand.int(2) == 1) odd[r*cx+c] = "T"
}
}
while (true) {
print.call(odd)
step.call(even, odd)
Stdin.readLine()
 
print.call(even)
step.call(odd, even)
Stdin.readLine()
}</syntaxhighlight>
413

edits