Forest fire: Difference between revisions

Content deleted Content added
Tim-brown (talk | contribs)
Added racket implementation
Chkas (talk | contribs)
 
(152 intermediate revisions by 54 users not shown)
Line 1:
{{task|Games}}{{wikipedia|Forest-fire model}}[[Category:Cellular automata]]
 
<br>
;Task:
Implement the Drossel and Schwabl definition of the [[wp:Forest-fire model|forest-fire model]].
 
 
It is basically a 2D [[wp:Cellular automaton|cellular automaton]] where each cell can be in three distinct states (''empty'', ''tree'' and ''burning'') and evolves according to the following rules (as given by Wikipedia)
It is basically a 2D &nbsp; [[wp:Cellular automaton|cellular automaton]] &nbsp; where each cell can be in three distinct states (''empty'', ''tree'' and ''burning'') and evolves according to the following rules (as given by Wikipedia)
 
# A burning cell turns into an empty cell
# A tree will burn if at least one neighbor is burning
# A tree ignites with probability &nbsp; <big>''f'' </big> &nbsp; even if no neighbor is burning
# An empty space fills with a tree with probability &nbsp; <big> ''p'' </big>
 
<br>Neighborhood is the &nbsp; [[wp:Moore neighborhood|Moore neighborhood]]; &nbsp; boundary conditions are so that on the boundary the cells are always empty ("fixed" boundary condition).
 
At the beginning, populate the lattice with empty and tree cells according to a specific probability (e.g. a cell has the probability 0.5 to be a tree). Then, let the system evolve.
 
Task's requirements do not include graphical display or the ability to change parameters (probabilities &nbsp; <big> ''p'' </big> &nbsp; and &nbsp; <big> ''f'' </big>) &nbsp; through a graphical or command line interface.
 
 
;Related tasks:
* &nbsp; See &nbsp; [[Conway's Game of Life]]
* &nbsp; See &nbsp; [[Wireworld]].
<br><br>
 
'''See also''' [[Conway's Game of Life]] and [[Wireworld]].
=={{header|6502 Assembly}}==
<langsyntaxhighlight lang="asm"> ORG $4357
; SYS 17239 or CALL 17239
 
Line 438 ⟶ 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 509 ⟶ 714:
Put (Forest);
end loop;
end Forest_Fire;</langsyntaxhighlight>
Sample output:
<pre style="height:30ex;overflow:scroll">
Line 603 ⟶ 808:
Y YYY# # YY Y # #Y
</pre>
 
=={{header|ALGOL 68}}==
===Textual version===
Line 609 ⟶ 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 667 ⟶ 873:
printf(($gl$, 2 UPB world * "-"))
OD
)</langsyntaxhighlight>
Output:
<pre>
Line 710 ⟶ 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 863 ⟶ 1,069:
return 0
}
</syntaxhighlight>
</lang>
Sample Output using the default settings:
<pre style="height:35ex;overflow:scroll;">
Line 923 ⟶ 1,129:
</pre>
 
=={{header|BASIC256BASIC}}==
==={{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 962 ⟶ 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,001 ⟶ 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}}===
<syntaxhighlight lang="freebasic">'[RC] Forest Fire
'written for FreeBASIC
'Program code based on BASIC256 from Rosettacode website
'http://rosettacode.org/wiki/Forest_fire#BASIC256
'06-10-2016 updated/tweaked the code
'compile with fbc -s gui
 
#Define M 400
#Define N 640
 
Dim As Double p = 0.003
Dim As Double fire = 0.00003
'Dim As Double number1
Dim As Integer gen, x, y
Dim As String press
 
'f0() and fn() use memory from the memory pool
Dim As UByte f0(), fn()
ReDim f0(-1 To N +2, -1 To M +2)
ReDim fn(-1 To N +2, -1 To M +2)
 
Dim As UByte white = 15 'color 15 is white
Dim As UByte yellow = 14 'color 14 is yellow
Dim As UByte black = 0 'color 0 is black
Dim As UByte green = 2 'color 2 is green
Dim As UByte red = 4 'color 4 is red
 
Screen 18 'Resolution 640x480 with at least 256 colors
Randomize Timer
 
Locate 28,1
Beep
Print " Welcome to Forest Fire"
Locate 29,1
Print " press any key to start"
Sleep
'Locate 28,1
'Print " Welcome to Forest Fire"
Locate 29,1
Print " "
 
' 1 tree, 0 empty, 2 fire
Color green ' this is green color for trees
For x = 1 To N
For y = 1 To M
If Rnd < 0.5 Then 'populate original tree density
f0(x,y) = 1
PSet (x,y)
End If
Next y
Next x
 
Color white
Locate 29,1
Print " Press any key to continue "
Sleep
Locate 29,1
Print " Press 'space bar' to continue/pause, ESC to stop "
 
Do
press = InKey
ScreenLock
For x = 1 To N
For y = 1 To M
If Not f0(x,y) And Rnd<P Then fn(x,y)=1
If f0(x,y)=2 Then fn(x,y)=0
If f0(x,y)=1 Then
fn(x,y) = 1
If f0(x-1,y-1)=2 OrElse f0(x,y-1)=2 OrElse f0(x+1,y-1)=2 Then fn(x,y)=2
If f0(x-1,y)=2 OrElse f0(x+1,y)=2 OrElse Rnd<fire Then fn(x,y)=2
If f0(x-1,y+1)=2 OrElse f0(x,y+1)=2 OrElse f0(x+1,y+1)=2 Then fn(x,y)=2
End If
'set up color and drawing
'0 empty (black), 1 tree (green), 2 fire (white)
If fn(x,y)=0 Then Color black 'empty
If fn(x,y)=1 Then Color green 'tree
If fn(x,y)=2 Then Color red 'fire
'plot x-1,y-1
PSet (x-1,y-1)
Next y
Next x
'print generation number
gen = gen + 1
Locate 28,1
Color white 'this is white color
Print " Generation number # ";gen
'transfer new generation to current generation
For x = 1 To N
For y = 1 To M
f0(x,y) = fn(x,y)
Next y
Next x
ScreenUnlock
 
' amount for sleep is in milliseconds, 1 = ignore key press
Sleep 50, 1 ' slow down a little ... goes too fast otherwise
If press = " " Then Sleep : press = InKey
If press = "s" Then Sleep
' return to do loop up top until "esc" key is pressed.
' clicking close windows "X", closes the window immediately
Loop Until press = Chr(27) OrElse press = Chr(255)+"k"
If press = Chr(255) + "k" Then End
 
Locate 28,1
Color white
Print " You entered ESC - goodbye "
Print " Press any key to exit "
Sleep</syntaxhighlight>
 
==={{header|GFA Basic}}===
 
<syntaxhighlight lang="basic">
width%=80
height%=50
DIM world%(width%+2,height%+2,2)
clock%=0
'
empty%=0 ! some mnemonic codes for the different states
burning%=1
tree%=2
'
f=0.0003
p=0.03
max_clock%=100
'
@open_window
@setup_world
DO
clock%=clock%+1
EXIT IF clock%>max_clock%
@display_world
@update_world
LOOP
@close_window
'
' Setup the world
'
PROCEDURE setup_world
LOCAL i%,j%
'
RANDOMIZE 0
ARRAYFILL world%(),empty%
' with Probability 0.5, create tree in cells
FOR i%=1 TO width%
FOR j%=1 TO height%
IF RND>0.5
world%(i%,j%,0)=tree%
ENDIF
NEXT j%
NEXT i%
'
cur%=0
new%=1
RETURN
'
' Display world on window
'
PROCEDURE display_world
LOCAL size%,i%,j%,offsetx%,offsety%,x%,y%
'
size%=5
offsetx%=10
offsety%=20
'
VSETCOLOR 0,15,15,15 ! colour for empty
VSETCOLOR 1,15,0,0 ! colour for burning
VSETCOLOR 2,0,15,0 ! colour for tree
VSETCOLOR 3,0,0,0 ! colour for text
DEFTEXT 3
PRINT AT(1,1);"Clock: ";clock%
'
FOR i%=1 TO width%
FOR j%=1 TO height%
x%=offsetx%+size%*i%
y%=offsety%+size%*j%
SELECT world%(i%,j%,cur%)
CASE empty%
DEFFILL 0
CASE tree%
DEFFILL 2
CASE burning%
DEFFILL 1
ENDSELECT
PBOX x%,y%,x%+size%,y%+size%
NEXT j%
NEXT i%
RETURN
'
' Check if a neighbour is burning
'
FUNCTION neighbour_burning(i%,j%)
LOCAL x%
'
IF world%(i%,j%-1,cur%)=burning%
RETURN TRUE
ENDIF
IF world%(i%,j%+1,cur%)=burning%
RETURN TRUE
ENDIF
FOR x%=-1 TO 1
IF world%(i%-1,j%+x%,cur%)=burning% OR world%(i%+1,j%+x%,cur%)=burning%
RETURN TRUE
ENDIF
NEXT x%
RETURN FALSE
ENDFUNC
'
' Update the world state
'
PROCEDURE update_world
LOCAL i%,j%
'
FOR i%=1 TO width%
FOR j%=1 TO height%
world%(i%,j%,new%)=world%(i%,j%,cur%)
SELECT world%(i%,j%,cur%)
CASE empty%
IF RND>1-p
world%(i%,j%,new%)=tree%
ENDIF
CASE tree%
IF @neighbour_burning(i%,j%) OR RND>1-f
world%(i%,j%,new%)=burning%
ENDIF
CASE burning%
world%(i%,j%,new%)=empty%
ENDSELECT
NEXT j%
NEXT i%
'
cur%=1-cur%
new%=1-new%
RETURN
'
' open and clear window
'
PROCEDURE open_window
OPENW 1
CLEARW 1
VSETCOLOR 4,8,8,0
DEFFILL 4
PBOX 0,0,500,400
RETURN
'
' close the window after keypress
'
PROCEDURE close_window
~INP(2)
CLOSEW 1
RETURN
</syntaxhighlight>
 
==={{header|PureBasic}}===
<syntaxhighlight lang="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().
; If experiencing this problem, please reduce the #Width & #Height
; or activate the parameter #UnLoadCPU below with a parameter 1 or 2.
;
; This code should work with the demo version of PureBasic on both PC & Linux
 
; General parameters for the world
#f = 1e-6
#p = 1e-2
#SeedATree = 0.005
#Width = 400
#Height = 400
 
; Setting up colours
#Fire = $080CF7
#BackGround = $BFD5D3
#YoungTree = $00E300
#NormalTree = $00AC00
#MatureTree = $009500
#OldTree = $007600
#Black = $000000
 
; Depending on your hardware, use this to control the speed/CPU-load.
; 0 = No load reduction
; 1 = Only active about every second frame
; 2 = '1' & release the CPU after each horizontal line.
#UnLoadCPU = 0
 
Enumeration
#Empty =0
#Ignited
#Burning
#Tree
#Old=#Tree+20
EndEnumeration
 
Global Dim Forest.i(#Width, #Height)
Global Title$="Forest fire in PureBasic"
Global Cnt
 
Macro Rnd()
(Random(2147483647)/2147483647.0)
EndMacro
 
Procedure Limit(n, min, max)
If n<min
n=min
ElseIf n>max
n=max
EndIf
ProcedureReturn n
EndProcedure
 
Procedure SpreadFire(x,y)
Protected cnt=0, i, j
For i=Limit(x-1, 0, #Width) To Limit(x+1, 0, #Width)
For j=Limit(y-1, 0, #Height) To Limit(y+1, 0, #Height)
If Forest(i,j)>=#Tree
Forest(i,j)=#Ignited
EndIf
Next
Next
EndProcedure
 
Procedure InitMap()
Protected x, y, type
For y=1 To #Height
For x=1 To #Width
If Rnd()<=#SeedATree
type=#Tree
Else
type=#Empty
EndIf
Forest(x,y)=type
Next
Next
EndProcedure
 
Procedure UpdateMap()
Protected x, y
For y=1 To #Height
For x=1 To #Width
Select Forest(x,y)
Case #Burning
Forest(x,y)=#Empty
SpreadFire(x,y)
Case #Ignited
Forest(x,y)=#Burning
Case #Empty
If Rnd()<=#p
Forest(x,y)=#Tree
EndIf
Default
If Rnd()<=#f
Forest(x,y)=#Burning
Else
Forest(x,y)+1
EndIf
EndSelect
Next
Next
EndProcedure
 
Procedure PresentMap()
Protected x, y, c
cnt+1
SetWindowTitle(0,Title$+", time frame="+Str(cnt))
StartDrawing(ImageOutput(1))
For y=0 To OutputHeight()-1
For x=0 To OutputWidth()-1
Select Forest(x,y)
Case #Empty
c=#BackGround
Case #Burning, #Ignited
c=#Fire
Default
If Forest(x,y)<#Tree+#Old
c=#YoungTree
ElseIf Forest(x,y)<#Tree+2*#Old
c=#NormalTree
ElseIf Forest(x,y)<#Tree+3*#Old
c=#MatureTree
ElseIf Forest(x,y)<#Tree+4*#Old
c=#OldTree
Else ; Tree died of old age
Forest(x,y)=#Empty
c=#Black
EndIf
EndSelect
Plot(x,y,c)
Next
CompilerIf #UnLoadCPU>1
Delay(1)
CompilerEndIf
Next
StopDrawing()
ImageGadget(1, 0, 0, #Width, #Height, ImageID(1))
EndProcedure
 
If OpenWindow(0, 10, 30, #Width, #Height, Title$, #PB_Window_MinimizeGadget)
SmartWindowRefresh(0, 1)
If CreateImage(1, #Width, #Height)
Define Event, freq
If ExamineDesktops() And DesktopFrequency(0)
freq=DesktopFrequency(0)
Else
freq=60
EndIf
AddWindowTimer(0,0,5000/freq)
InitMap()
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
End
Case #PB_Event_Timer
CompilerIf #UnLoadCPU>0
Delay(25)
CompilerEndIf
UpdateMap()
PresentMap()
EndSelect
ForEver
EndIf
EndIf</syntaxhighlight>
[[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:
<syntaxhighlight lang="realbasic">
Sub Run()
//Handy named constants
Const empty = 0
Const tree = 1
Const fire = 2
Const ablaze = &cFF0000 //Using the &c numeric operator to indicate a color in hex
Const alive = &c00FF00
Const dead = &c804040
//Our forest
Dim worldPic As New Picture(480, 480, 32)
Dim newWorld(120, 120) As Integer
Dim oldWorld(120, 120) As Integer
//Initialize forest
Dim rand As New Random
For x as Integer = 0 to 119
For y as Integer = 0 to 119
if rand.InRange(0, 2) = 0 Or x = 119 or y = 119 or x = 0 or y = 0 Then
newWorld(x, y) = empty
worldPic.Graphics.ForeColor = dead
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
Else
newWorld(x, y) = tree
worldPic.Graphics.ForeColor = alive
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Next
Next
oldWorld = newWorld
//Burn, baby burn!
While Window1.stop = False
For x as Integer = 0 To 119
For y As Integer = 0 to 119
Dim willBurn As Integer = rand.InRange(0, Window1.burnProb.Value)
Dim willGrow As Integer = rand.InRange(0, Window1.growProb.Value)
if x = 119 or y = 119 or x = 0 or y = 0 Then
Continue
end if
Select Case oldWorld(x, y)
Case empty
If willGrow = (Window1.growProb.Value) Then
newWorld(x, y) = tree
worldPic.Graphics.ForeColor = alive
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Case tree
if oldWorld(x - 1, y) = fire Or oldWorld(x, y - 1) = fire Or oldWorld(x + 1, y) = fire Or oldWorld(x, y + 1) = fire Or oldWorld(x + 1, y + 1) = fire Or oldWorld(x - 1, y - 1) = fire Or oldWorld(x - 1, y + 1) = fire Or oldWorld(x + 1, y - 1) = fire Or willBurn = (Window1.burnProb.Value) Then
newWorld(x, y) = fire
worldPic.Graphics.ForeColor = ablaze
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Case fire
newWorld(x, y) = empty
worldPic.Graphics.ForeColor = dead
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
End Select
Next
Next
Window1.Canvas1.Graphics.DrawPicture(worldPic, 0, 0)
oldWorld = newWorld
me.Sleep(Window1.speed.Value)
Wend
End Sub
</syntaxhighlight>
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.
<syntaxhighlight 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.
Dim fire As New forestFire
fire.Run()
End Sub
 
stop As Boolean //a globally accessible property of Window1. Boolean properties default to False.
 
Sub Pushbutton1.Action()
stop = True
End Sub
</syntaxhighlight>
[[Image:ForestFireRB.PNG]]
 
==={{header|Run BASIC}}===
<syntaxhighlight lang="runbasic">graphic #g, 200,200
dim preGen(200,200)
dim newGen(200,200)
 
for gen = 1 to 200
for x = 1 to 199
for y = 1 to 199
select case preGen(x,y)
case 0
if rnd(0) > .99 then newGen(x,y) = 1 : #g "color green ; set "; x; " "; y
case 2
newGen(x,y) = 0 : #g "color brown ; set "; x; " "; y
case 1
if preGen(x-1,y-1) = 2 or preGen(x-1,y) = 2 or preGen(x-1,y+1) = 2 _
or preGen(x,y-1) = 2 or preGen(x,y+1) = 2 or preGen(x+1,y-1) = 2 _
or preGen(x+1,y) = 2 or preGen(x+1,y+1) = 2 or rnd(0) > .999 then
#g "color red ; set "; x; " "; y
newGen(x,y) = 2
end if
end select
preGen(x-1,y-1) = newGen(x-1,y-1)
next y
next x
next gen
render #g</syntaxhighlight>
[[File:ForestFire.png]]
 
==={{header|Sinclair ZX81 BASIC}}===
Requires 16k of RAM.
 
In essence this is an enhanced version of my ZX Spectrum implementation (see below). The main improvement is that this version shows the ages of the trees: the age is represented using <code>0</code> to <code>9</code>, then <code>A</code> to <code>Z</code>, followed theoretically by the special characters <code>£$:?()><=+-*/;,.</code> (in that order) and only then cycling back to <code>0</code>. Realistically, no tree is likely to live that long.
 
The subroutine at line 1000 takes a number <code>N</code> and returns its inverse-video string representation as <code>I$</code>.
 
A couple of other notes on the listing:
 
(1) some characters need to be entered in <code>G</code>raphics mode, which is accessed using <code>SHIFT</code><code>9</code>. I have represented this using square brackets: so if the listing says <code>[ROSETTA CODE]</code>, you need to go into <code>G</code> mode and type <code>ROSETTA CODE</code> (which will be displayed on the ZX81 screen in inverse video). As a special case, <code>[a]</code> means for you to go into <code>G</code> mode and then type <code>SHIFT</code><code>A</code>. The ZX81 character set does not include either square brackets or lower-case letters, so I hope this convention will not lead to too much confusion.
 
(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.
<syntaxhighlight lang="basic"> 10 DIM F$(20,30)
20 DIM N$(20,30)
30 LET INIT=.5
40 LET F=.02
50 LET P=.05
60 PRINT AT 0,1;"[FOREST FIRE FOR ROSETTA CODE]"
70 FOR I=0 TO 21
80 PRINT AT I,0;"[ ]"
90 PRINT AT I,31;"[ ]"
100 NEXT I
110 FOR I=1 TO 30
120 PRINT AT 21,I;"[ ]"
130 NEXT I
140 LET G=0
150 LET T=0
160 PRINT AT 21,1;"[GENERATION 0]"
170 PRINT AT 21,20;"[COVER]"
180 FOR I=1 TO 20
190 FOR J=1 TO 30
200 IF RND>=INIT THEN GOTO 240
210 PRINT AT I,J;"0"
220 LET F$(I,J)="0"
230 LET T=T+1
240 NEXT J
250 NEXT I
300 PRINT AT 21,26;"[ ]"
310 LET N=INT (.5+T/6)
320 GOSUB 1000
330 PRINT AT 21,26;I$;"[ PC]"
340 FOR I=1 TO 20
350 PRINT AT I,0;"[>]"
360 FOR J=1 TO 30
380 IF F$(I,J)<>"[a]" THEN GOTO 410
390 LET N$(I,J)=" "
400 GOTO 530
410 IF F$(I,J)<>" " THEN GOTO 433
420 IF RND<=P THEN LET N$(I,J)="0"
430 GOTO 530
433 LET N$(I,J)=CHR$ (1+CODE F$(I,J))
437 IF N$(I,J)>"Z" THEN LET N$(I,J)="£"
440 FOR K=I-1 TO I+1
450 FOR L=J-1 TO J+1
460 IF K=0 OR L=0 OR K=21 OR L=21 THEN GOTO 480
470 IF F$(K,L)="[a]" THEN GOTO 510
480 NEXT L
490 NEXT K
500 GOTO 520
510 LET N$(I,J)="[a]"
520 IF RND<=F THEN LET N$(I,J)="[a]"
530 NEXT J
540 PRINT AT I,0;"[ ]"
550 NEXT I
552 LET G=G+1
554 LET N=G
556 GOSUB 1000
558 PRINT AT 21,12;I$
560 LET T=0
570 FOR I=1 TO 20
575 PRINT AT I,31;"[<]"
580 FOR J=1 TO 30
590 IF N$(I,J)<>"[a]" AND N$(I,J)<>" " THEN LET T=T+1
600 NEXT J
610 LET F$(I)=N$(I)
620 PRINT AT I,1;F$(I)
625 PRINT AT I,31;"[ ]"
630 GOTO 300
1000 LET S$=STR$ N
1010 LET I$=""
1020 FOR K=1 TO LEN S$
1030 LET I$=I$+CHR$ (128+CODE S$(K))
1040 NEXT K
1050 RETURN</syntaxhighlight>
{{out}}
Screenshot [http://www.edmundgriffiths.com/zx81forest.jpg here].
 
==={{header|Visual Basic .NET}}===
 
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.
 
<syntaxhighlight lang="vbnet">Public Class ForestFire
Private _forest(,) As ForestState
Private _isBuilding As Boolean
Private _bm As Bitmap
Private _gen As Integer
Private _sw As Stopwatch
 
Private Const _treeStart As Double = 0.5
Private Const _f As Double = 0.00001
Private Const _p As Double = 0.001
 
Private Const _winWidth As Integer = 300
Private Const _winHeight As Integer = 300
 
Private Enum ForestState
Empty
Burning
Tree
End Enum
 
Private Sub ForestFire_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.ClientSize = New Size(_winWidth, _winHeight)
ReDim _forest(_winWidth, _winHeight)
 
Dim rnd As New Random()
For i As Integer = 0 To _winHeight - 1
For j As Integer = 0 To _winWidth - 1
_forest(j, i) = IIf(rnd.NextDouble <= _treeStart, ForestState.Tree, ForestState.Empty)
Next
Next
 
_sw = New Stopwatch
_sw.Start()
DrawForest()
Timer1.Start()
End Sub
 
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If _isBuilding Then Exit Sub
 
_isBuilding = True
GetNextGeneration()
 
DrawForest()
_isBuilding = False
End Sub
 
Private Sub GetNextGeneration()
Dim forestCache(_winWidth, _winHeight) As ForestState
Dim rnd As New Random()
 
For i As Integer = 0 To _winHeight - 1
For j As Integer = 0 To _winWidth - 1
Select Case _forest(j, i)
Case ForestState.Tree
If forestCache(j, i) <> ForestState.Burning Then
forestCache(j, i) = IIf(rnd.NextDouble <= _f, ForestState.Burning, ForestState.Tree)
End If
 
Case ForestState.Burning
For i2 As Integer = i - 1 To i + 1
If i2 = -1 OrElse i2 >= _winHeight Then Continue For
For j2 As Integer = j - 1 To j + 1
If j2 = -1 OrElse i2 >= _winWidth Then Continue For
If _forest(j2, i2) = ForestState.Tree Then forestCache(j2, i2) = ForestState.Burning
Next
Next
forestCache(j, i) = ForestState.Empty
 
Case Else
forestCache(j, i) = IIf(rnd.NextDouble <= _p, ForestState.Tree, ForestState.Empty)
End Select
Next
Next
 
_forest = forestCache
_gen += 1
End Sub
 
Private Sub DrawForest()
Dim bmCache As New Bitmap(_winWidth, _winHeight)
 
For i As Integer = 0 To _winHeight - 1
For j As Integer = 0 To _winWidth - 1
Select Case _forest(j, i)
Case ForestState.Tree
bmCache.SetPixel(j, i, Color.Green)
 
Case ForestState.Burning
bmCache.SetPixel(j, i, Color.Red)
End Select
Next
Next
 
_bm = bmCache
Me.Refresh()
End Sub
 
Private Sub ForestFire_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
e.Graphics.DrawImage(_bm, 0, 0)
 
Me.Text = "Gen " & _gen.ToString() & " @ " & (_gen / (_sw.ElapsedMilliseconds / 1000)).ToString("F02") & " FPS: Forest Fire"
End Sub
End Class</syntaxhighlight>
 
==={{header|ZX Spectrum Basic}}===
This isn't a graphical implementation, but it uses a bit of colour to make the display clearer. It runs very slowly. The variable <tt>init</tt> defines the initial likelihood that each square will hold a tree, and can take values between 0 (no trees) and 1 (a tree in every square) inclusive. This can be used to check that the program is running correctly, and using a value of 1 is probably the most dramatic: but it only makes a difference in the short term. After a few generations, any starting configuration using these values of <math>f</math> and <math>p</math> will end up fluctuating around 20% tree cover—sparse woodland, perhaps, rather than true forest.
 
A screenshot of the program running can be found [http://www.edmundgriffiths.com/spectrumforestfire.jpg here].
<syntaxhighlight lang="zxbasic"> 10 PAPER 6: CLS
20 DIM n$(20,30)
30 LET init=.5
40 LET f=.02
50 LET p=.05
60 PAPER 0
70 FOR i=0 TO 31
80 PRINT AT 0,i;" "
90 PRINT AT 21,i;" "
100 NEXT i
110 FOR i=0 TO 21
120 PRINT AT i,0;" "
130 PRINT AT i,31;" "
140 NEXT i
150 INK 7
160 PRINT AT 0,1;"FOREST FIRE for Rosetta Code"
170 LET generation=0
180 PRINT AT 21,1;"Generation 0"
190 LET trees=0
200 PRINT AT 21,22;"Cover"
210 FOR i=1 TO 20
220 FOR j=1 TO 30
230 IF RND<init THEN PAPER 4: INK 7: PRINT AT i,j;"T": LET trees=trees+1
240 NEXT j
250 NEXT i
260 LET generation=generation+1
270 INK 7
280 PAPER 0
290 PRINT AT 21,12;generation
300 PRINT AT 21,28;" "
310 PRINT AT 21,28;INT (trees/6+.5);"%"
320 FOR i=1 TO 20
330 FOR j=1 TO 30
340 LET n$(i,j)=SCREEN$ (i,j)
350 IF SCREEN$ (i,j)="B" THEN LET n$(i,j)=" ": GO TO 450
360 IF SCREEN$ (i,j)="T" THEN GO TO 390
370 IF RND<=p THEN LET n$(i,j)="T"
380 GO TO 450
390 FOR k=i-1 TO i+1
400 FOR l=j-1 TO j+1
410 IF SCREEN$ (k,l)="B" THEN LET n$(i,j)="B": LET k=i+2: LET l=j+2
420 NEXT l
430 NEXT k
440 IF RND<=f THEN LET n$(i,j)="B"
450 NEXT j
460 NEXT i
470 LET trees=0
480 FOR i=1 TO 20
490 FOR j=1 TO 30
500 IF n$(i,j)="T" THEN INK 7: PAPER 4: PRINT AT i,j;"T": LET trees=trees+1: GO TO 540
510 IF n$(i,j)="B" THEN INK 6: PAPER 2: PRINT AT i,j;"B": GO TO 540
520 PAPER 6
530 PRINT AT i,j;" "
540 NEXT j
550 NEXT i
560 GO TO 260</syntaxhighlight>
 
=={{header|Batch File}}==
Accepts command line arguments in the form of <code>m p f i</code> <br>Where:
<pre>
m - length and width of the array
p - probability of a tree growing
f - probability of a tree catching on fire
i - iterations to output
</pre>
Default is <code> 10 50 5 5 </code>
<syntaxhighlight lang="dos">
@echo off
setlocal enabledelayedexpansion
 
if "%1"=="" (
call:default
) else (
call:setargs %*
)
 
call:createarray
call:fillarray
call:display
echo.
echo -------------------
echo.
 
for /l %%i in (1,1,%i%) do (
echo.
echo -------------------
echo.
call:evolve
call:display
)
pause>nul
 
:default
set m=10
set n=11
set p=50
set f=5
set i=5
exit /b
 
:setargs
set m=%1
set n=%m%+1
set p=%2
set f=%3
set i=%4
exit /b
 
:createarray
for /l %%m in (0,1,%n%) do (
for /l %%n in (0,1,%n%) do (
set a%%m%%n=0
)
)
exit /b
 
:fillarray
for /l %%m in (1,1,%m%) do (
for /l %%n in (1,1,%m%) do (
set /a treerandom=!random! %% 101
if !treerandom! leq %p% set a%%m%%n=T
)
)
exit /b
 
:display
for /l %%m in (1,1,%m%) do (
set "line%%m="
for /l %%n in (1,1,%m%) do (
set line%%m=!line%%m! !a%%m%%n!
)
set line%%m=!line%%m:0= !
echo.!line%%m!
)
exit /b
 
:evolve
for /l %%m in (1,1,%m%) do (
for /l %%n in (1,1,%m%) do (
call:nexttick !a%%m%%n! %%m %%n
set newa%%m%%n=!errorlevel!
)
)
call:update
exit /b
 
:nexttick
 
if %1==0 (
set /a treerandom=!random! %% 101
if !treerandom! leq %p% exit /b 1
exit /b 0
)
 
if %1==T (
set /a lowerm=%2-1
set /a upperm=%2+1
set /a lowern=%3-1
set /a uppern=%3+1
set burn=0
for /l %%m in (!lowerm!,1,!upperm!) do (
for /l %%n in (!lowern!,1,!uppern!) do (
if !a%%m%%n!==# set burn=1
)
)
if !burn!==1 exit /b 2
set /a burnrandom=!random! %% 101
if !burnrandom! leq %f% exit /b 2
exit /b 1
)
 
if %1==# exit /b 0
 
:update
for /l %%m in (1,1,%m%) do (
for /l %%n in (1,1,%m%) do (
if !newa%%m%%n!==1 set newa%%m%%n=T
if !newa%%m%%n!==2 set newa%%m%%n=#
set a%%m%%n=!newa%%m%%n!
)
)
exit /b
</syntaxhighlight>
{{out}}
'''Sample Default Output'''
<pre>
T T T
T T T T T
T T T
T T T T T T T
T T T T
T T T T T T T
T T T T T
T T T T T
T T T T T T
T T T T T
 
-------------------
 
 
-------------------
 
T T # T T T #
T T T T T T T T
T T T T T T
T T T T T T T T T
T T T T T T
T T T T T T T T T T
T T T T T T T T T
T T T T T T
T T T T T T T T #
T T T T T T T
 
-------------------
 
T # # # #
T # # # T T T T # #
T T T T T T
T T T T T T T T T
T T T T T T T T
T T T T T # T T T T
T T T T T T T T #
T T T T T T # #
T T T T # T T T
# T T T T T #
 
-------------------
 
# T T
# # # # #
T # # # T # # #
T T T T T T T T T T
T T T T # # T T T
T T T T # # T # #
T T T T # # # # #
T T T # # #
# # T # # T # T T
T # # # T # T
 
-------------------
 
T T T T T T T
T
# #
T # # # # # # # # #
T # T # # T # #
T # T # #
T T T #
# # # T T
# # # T
T # # T
 
-------------------
 
T T T T T T T T
T T T T T
T T T
#
# # T #
# # T T
# # # T T T
# T #
T T T T #
# T T T #
</pre>
 
=={{header|C}}==
Line 1,011 ⟶ 2,266:
{{libheader|SDL}}
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
Line 1,258 ⟶ 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>
#include <time.h> // For time
 
enum { empty = 0, tree = 1, fire = 2 };
Line 1,280 ⟶ 2,536:
show: printf("\033[H");
for_y {
for_x printf("%s",disp[univ[y][x]]);
printf("\033[E");
}
Line 1,325 ⟶ 2,581:
 
evolve(w, h);
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
 
<syntaxhighlight lang c sharp="csharp">using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;
 
namespace ForestFire
{
internal class Program : Form
{
private static voidreadonly Main(string[]Random argsrand = new Random();
private Bitmap img;
 
public Program(int w, int h, int f, int p)
{
Console.WriteSize = new Size("Height?w, "h);
int heightStartPosition = int.Parse(ConsoleFormStartPosition.ReadLine())CenterScreen;
Console.Write("Width? ");
int width = int.Parse(Console.ReadLine());
Console.Write("Probability of a tree spontaneously combusting? 1/");
int f = int.Parse(Console.ReadLine());
Console.Write("Probability of a tree growing? 1/");
int p = int.Parse(Console.ReadLine());
Console.Clear();
 
varThread statet = InitializeForestFirenew Thread(() => fire(heightf, widthp));
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;
Line 1,353 ⟶ 2,624:
do
{
g.FillRectangle(Brushes.White, 0, 0, img.Width, img.Height);
state = StepForestFire(state, f, p);
 
Console.SetCursorPositionfor (0,int y = 0); y < clientHeight - cellSize; y += cellSize)
Console.ResetColor();
Console.WriteLine("Generation " + ++generation);
 
for (int y = 0; y < height; y++)
{
for (int x = 0; x < widthclientWidth - cellSize; x ++= cellSize)
{
switch (state[y, x])
{
case CellState.Empty:
Console.Write(' ');
break;
case CellState.Tree:
Consoleg.ForegroundColor = ConsoleColorFillRectangle(Brushes.DarkGreen, x, y, cellSize, cellSize);
Console.Write('T');
break;
case CellState.Burning:
Consoleg.ForegroundColor = ConsoleColorFillRectangle(Brushes.DarkRed, x, y, cellSize, cellSize);
Console.Write('F');
break;
}
}
 
Console.WriteLine();
}
 
} while (Console.ReadKey(true).Key != ConsoleKey.Q && generation < uint.MaxValue);
Thread.Sleep(500);
 
Invoke((MethodInvoker)Refresh);
 
} while (generation < uint.MaxValue);
 
g.Dispose();
}
 
private static CellState[,] InitializeForestFire(int heightwidth, int widthheight)
{
// Create our state array, initialize all indices as Empty, and return it.
Line 1,399 ⟶ 2,669:
}
 
private staticCellState[,] readonlyStepForestFire(CellState[,] Randomstate, Randomint =f, newint Random(p);
 
private static 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 heightnumRows = state.GetLength(0);
int widthnumCols = state.GetLength(1);
 
for (int ir = 1; ir < heightnumRows - 1; ir++)
{
for (int oc = 1; oc < widthnumCols - 1; oc++)
{
/*
Line 1,425 ⟶ 2,693:
* If it's burning, set it to empty.
*/
switch (state[ir, oc])
{
case CellState.Empty:
if (Randomrand.Next(0, p) == 0)
newState[ir, oc] = CellState.Tree;
break;
 
case CellState.Tree:
if (IsNeighborNeighborHasState(state, ir, oc, CellState.Burning) || rand.Next(0, f) == 0)
Random.Next(0newState[r, f)c] == 0)CellState.Burning;
newState[i, o] = CellState.Burning;
break;
 
case CellState.Burning:
newState[ir, oc] = CellState.Empty;
break;
}
Line 1,446 ⟶ 2,715:
}
 
private static bool IsNeighborNeighborHasState(CellState[,] state, int x, int y, CellState value)
{
// Check each cell within a 1 cell radius for the specified value.
for (int ir = -1; ir <= 1; ir++)
{
for (int oc = -1; oc <= 1; oc++)
{
if (ir == 0 && oc == 0)
continue;
 
if (state[x + ir, y + oc] == value)
return true;
}
Line 1,462 ⟶ 2,731:
 
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));
}
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
'''Sample Output'''
[[File:ForestFireCpp.png|300px]]
<syntaxhighlight lang="cpp">
#include <windows.h>
#include <string>
 
//--------------------------------------------------------------------------------------------------
<pre>Generation 10
using namespace std;
 
//--------------------------------------------------------------------------------------------------
T T T T TF F T
enum states { NONE, TREE, FIRE };
TFTFFTTTFTF F TT
const int MAX_SIDE = 500;
F FTTTTTT TF F FFT
 
FFTT TTFFT T FF F T
//--------------------------------------------------------------------------------------------------
FF T F F TF T FFF
class myBitmap
TTTT T TFTF F F
{
T TT TFT F TTT TT
public:
TTTTTTTT F FTFT F
TTTTF myBitmap() F: TFpen( FFNULL ) F FF{}
~myBitmap()
TTTT F F F F T
{
TTTT TTFFF T TFFTT
DeleteObject( pen );
TTTTTTT T T F F TTT
DeleteDC( hdc );
TTTTTTFFTF FTFFFFFFTT T
DeleteObject( bmp );
FTT TT TFFFFFTFTTTTTT T
}
TFFT FF FF FTTTTT
 
T F T FFT T T T
bool create( int w, int h )
TF FTFFT FTF TF T
{
F F F FTF T T FT FF
BITMAPINFO bi;
FTFTTFT TTFTTTTT F
ZeroMemory( &bi, sizeof( bi ) );
TT F TT TTTFFFF T F
 
TTTF T TFTFTF TFT F
bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
T TFFFFF T F FT FF F
bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
TTTTTTTT TT FTFT F F
bi.bmiHeader.biCompression = BI_RGB;
</pre>
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = w;
bi.bmiHeader.biHeight = -h;
 
HDC dc = GetDC( GetConsoleWindow() );
bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
if( !bmp ) return false;
 
hdc = CreateCompatibleDC( dc );
SelectObject( hdc, bmp );
ReleaseDC( GetConsoleWindow(), dc );
 
width = w; height = h;
 
return true;
}
 
void clear()
{
ZeroMemory( pBits, width * height * sizeof( DWORD ) );
}
 
void setPenColor( DWORD clr )
{
if( pen ) DeleteObject( pen );
pen = CreatePen( PS_SOLID, 1, clr );
SelectObject( hdc, pen );
}
 
void saveBitmap( string path )
{
BITMAPFILEHEADER fileheader;
BITMAPINFO infoheader;
BITMAP bitmap;
DWORD wb;
 
GetObject( bmp, sizeof( bitmap ), &bitmap );
 
DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
 
infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
infoheader.bmiHeader.biCompression = BI_RGB;
infoheader.bmiHeader.biPlanes = 1;
infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
infoheader.bmiHeader.biHeight = bitmap.bmHeight;
infoheader.bmiHeader.biWidth = bitmap.bmWidth;
infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
 
fileheader.bfType = 0x4D42;
fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
 
GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
 
HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
CloseHandle( file );
 
delete [] dwpBits;
}
 
HDC getDC() const { return hdc; }
int getWidth() const { return width; }
int getHeight() const { return height; }
 
private:
HBITMAP bmp;
HDC hdc;
HPEN pen;
void *pBits;
int width, height;
};
//--------------------------------------------------------------------------------------------------
class forest
{
public:
forest()
{
_bmp.create( MAX_SIDE, MAX_SIDE );
initForest( 0.05f, 0.005f );
}
 
void initForest( float p, float f )
{
_p = p; _f = f;
seedForest();
}
 
void mainLoop()
{
display();
simulate();
}
 
void setHWND( HWND hwnd ) { _hwnd = hwnd; }
 
private:
float probRand() { return ( float )rand() / 32768.0f; }
void display()
{
HDC bdc = _bmp.getDC();
DWORD clr;
 
for( int y = 0; y < MAX_SIDE; y++ )
{
for( int x = 0; x < MAX_SIDE; x++ )
{
switch( _forest[x][y] )
{
case FIRE: clr = 255; break;
case TREE: clr = RGB( 0, 255, 0 ); break;
default: clr = 0;
}
 
SetPixel( bdc, x, y, clr );
}
}
 
HDC dc = GetDC( _hwnd );
BitBlt( dc, 0, 0, MAX_SIDE, MAX_SIDE, _bmp.getDC(), 0, 0, SRCCOPY );
ReleaseDC( _hwnd, dc );
}
 
void seedForest()
{
ZeroMemory( _forestT, sizeof( _forestT ) );
ZeroMemory( _forest, sizeof( _forest ) );
for( int y = 0; y < MAX_SIDE; y++ )
for( int x = 0; x < MAX_SIDE; x++ )
if( probRand() < _p ) _forest[x][y] = TREE;
}
 
bool getNeighbors( int x, int y )
{
int a, b;
for( int yy = -1; yy < 2; yy++ )
for( int xx = -1; xx < 2; xx++ )
{
if( !xx && !yy ) continue;
a = x + xx; b = y + yy;
if( a < MAX_SIDE && b < MAX_SIDE && a > -1 && b > -1 )
if( _forest[a][b] == FIRE ) return true;
}
 
return false;
}
 
void simulate()
{
for( int y = 0; y < MAX_SIDE; y++ )
{
for( int x = 0; x < MAX_SIDE; x++ )
{
switch( _forest[x][y] )
{
case FIRE: _forestT[x][y] = NONE; break;
case NONE: if( probRand() < _p ) _forestT[x][y] = TREE; break;
case TREE: if( getNeighbors( x, y ) || probRand() < _f ) _forestT[x][y] = FIRE;
}
}
}
 
for( int y = 0; y < MAX_SIDE; y++ )
for( int x = 0; x < MAX_SIDE; x++ )
_forest[x][y] = _forestT[x][y];
}
 
myBitmap _bmp;
HWND _hwnd;
BYTE _forest[MAX_SIDE][MAX_SIDE], _forestT[MAX_SIDE][MAX_SIDE];
float _p, _f;
};
//--------------------------------------------------------------------------------------------------
class wnd
{
public:
int wnd::Run( HINSTANCE hInst )
{
_hInst = hInst;
_hwnd = InitAll();
 
_ff.setHWND( _hwnd );
_ff.initForest( 0.02f, 0.001f );
 
ShowWindow( _hwnd, SW_SHOW );
UpdateWindow( _hwnd );
 
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
_ff.mainLoop();
}
}
return UnregisterClass( "_FOREST_FIRE_", _hInst );
}
private:
static int WINAPI wnd::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY: PostQuitMessage( 0 ); break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
 
HWND InitAll()
{
WNDCLASSEX wcex;
ZeroMemory( &wcex, sizeof( wcex ) );
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = ( WNDPROC )WndProc;
wcex.hInstance = _hInst;
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszClassName = "_FOREST_FIRE_";
 
RegisterClassEx( &wcex );
return CreateWindow( "_FOREST_FIRE_", ".: Forest Fire -- PJorente :.", WS_SYSMENU, CW_USEDEFAULT, 0, MAX_SIDE, MAX_SIDE, NULL, NULL, _hInst, NULL );
}
 
HINSTANCE _hInst;
HWND _hwnd;
forest _ff;
};
//--------------------------------------------------------------------------------------------------
int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
srand( GetTickCount() );
wnd myWnd;
return myWnd.Run( hInstance );
}
//--------------------------------------------------------------------------------------------------
</syntaxhighlight>
 
=={{header|Ceylon}}==
<syntaxhighlight lang="ceylon">import ceylon.random { DefaultRandom }
 
abstract class Cell() of tree | dirt | burning {}
object tree extends Cell() { string => "A"; }
object dirt extends Cell() { string => " "; }
object burning extends Cell() { string => "#"; }
 
class Forest(Integer width, Integer height, Float f, Float p) {
 
value random = DefaultRandom();
function chance(Float probability) => random.nextFloat() < probability;
value sparked => chance(f);
value sprouted => chance(p);
 
alias Point => Integer[2];
interface Row => {Cell*};
 
object doubleBufferedGrid satisfies
Correspondence<Point, Cell> &
KeyedCorrespondenceMutator<Point, Cell> {
 
value grids = [
Array {
for (j in 0:height)
Array {
for (i in 0:width)
chance(0.5) then tree else dirt
}
},
Array {
for (j in 0:height)
Array.ofSize(width, dirt)
}
];
 
variable value showFirst = true;
value currentState => showFirst then grids.first else grids.last;
value nextState => showFirst then grids.last else grids.first;
 
shared void swapStates() => showFirst = !showFirst;
 
shared {Row*} rows => currentState;
 
shared actual Boolean defines(Point key) =>
let (x = key[0], y = key[1])
0 <= x < width && 0 <= y < height;
shared actual Cell? get(Point key) =>
let (x = key[0], y = key[1])
currentState.get(y)?.get(x);
 
shared actual void put(Point key, Cell cell) {
value [x, y] = key;
nextState.get(y)?.set(x, cell);
}
}
 
variable value evolutions = 0;
shared Integer generation => evolutions + 1;
 
shared void evolve() {
 
evolutions++;
 
function firesNearby(Integer x, Integer y) => {
for (j in y - 1 : 3)
for (i in x - 1 : 3)
doubleBufferedGrid[[i, j]]
}.coalesced.any(burning.equals);
 
for(j->row in doubleBufferedGrid.rows.indexed) {
for(i->cell in row.indexed) {
switch (cell)
case (burning) {
doubleBufferedGrid[[i, j]] = dirt;
}
case (dirt) {
doubleBufferedGrid[[i, j]] = sprouted then tree else dirt;
}
case (tree) {
doubleBufferedGrid[[i, j]] =
firesNearby(i, j) || sparked
then burning else tree;
}
}
}
 
doubleBufferedGrid.swapStates();
}
 
shared void display() {
 
void drawLine() => print("-".repeat(width + 2));
 
drawLine();
for (row in doubleBufferedGrid.rows) {
process.write("|");
for (cell in row) {
process.write(cell.string);
}
print("|");
}
drawLine();
}
}
 
shared void run() {
 
value forest = Forest(78, 38, 0.02, 0.03);
 
while (true) {
 
forest.display();
 
print("Generation ``forest.generation``");
print("Press enter for next generation or q and then enter to quit");
 
value input = process.readLine();
if (exists input, input.trimmed.lowercased == "q") {
return;
}
 
forest.evolve();
}
}</syntaxhighlight>
 
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">
<lang Clojure>
(def burn-prob 0.1)
(def new-tree-prob 0.5)
Line 1,575 ⟶ 3,238:
(forest-fire)
 
</syntaxhighlight>
</lang>
 
example output
Line 1,591 ⟶ 3,254:
(:grass :fire! :fire! :burnt :tree))
</pre>
 
=={{header|COBOL}}==
{{works with|OpenCOBOL}}
<syntaxhighlight lang="cobol"> IDENTIFICATION DIVISION.
PROGRAM-ID. forest-fire.
 
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Probability represents a fraction of 10000.
*> For instance, IGNITE-PROB means a tree has a 1 in 10000 chance
*> of igniting.
78 IGNITE-PROB VALUE 1.
78 NEW-TREE-PROB VALUE 100.
 
78 EMPTY-PROB VALUE 3333.
 
78 AREA-SIZE VALUE 40.
 
01 sim-table.
03 sim-row OCCURS AREA-SIZE TIMES INDEXED BY row-index.
05 sim-area OCCURS AREA-SIZE TIMES
INDEXED BY col-index.
07 current-status PIC 9.
*> The flags correspond to the colours they will
*> be displayed as.
88 empty VALUE 0. *> Black
88 tree VALUE 2. *> Green
88 burning VALUE 4. *> Red
07 next-status PIC 9.
88 empty VALUE 0.
88 tree VALUE 2.
88 burning VALUE 4.
01 rand-num PIC 9999.
01 next-row PIC 9(4).
01 next-col PIC 9(4).
 
01 neighbours-row PIC 9(4).
01 neighbours-col PIC 9(4).
 
PROCEDURE DIVISION.
main-line.
*> Seed RANDOM with current time.
MOVE FUNCTION RANDOM(FUNCTION CURRENT-DATE (9:8)) TO rand-num
 
PERFORM initialise-table
PERFORM FOREVER
PERFORM show-simulation
PERFORM step-simulation
END-PERFORM
 
GOBACK
.
 
initialise-table.
PERFORM VARYING row-index FROM 1 BY 1
UNTIL AREA-SIZE < row-index
AFTER col-index FROM 1 BY 1
UNTIL AREA-SIZE < col-index
PERFORM get-rand-num
IF rand-num <= EMPTY-PROB
SET empty OF current-status (row-index, col-index)
TO TRUE
SET empty OF next-status (row-index, col-index)
TO TRUE
ELSE
SET tree OF current-status (row-index, col-index)
TO TRUE
SET tree OF next-status (row-index, col-index)
TO TRUE
END-IF
END-PERFORM
.
 
show-simulation.
PERFORM VARYING row-index FROM 1 BY 1
UNTIL AREA-SIZE < row-index
AFTER col-index FROM 1 BY 1
UNTIL AREA-SIZE < col-index
DISPLAY SPACE AT LINE row-index COLUMN col-index
WITH BACKGROUND-COLOR
current-status (row-index, col-index)
END-PERFORM
.
 
*> Updates the simulation.
step-simulation.
PERFORM VARYING row-index FROM 1 BY 1
UNTIL AREA-SIZE < row-index
AFTER col-index FROM 1 BY 1
UNTIL AREA-SIZE < col-index
EVALUATE TRUE
WHEN empty OF current-status (row-index, col-index)
PERFORM get-rand-num
IF rand-num <= NEW-TREE-PROB
SET tree OF next-status
(row-index, col-index) TO TRUE
END-IF
 
WHEN tree OF current-status (row-index, col-index)
PERFORM simulate-tree
 
WHEN burning OF current-status
(row-index, col-index)
SET empty OF next-status (row-index, col-index)
TO TRUE
END-EVALUATE
END-PERFORM
 
PERFORM update-statuses.
.
 
*> Updates a tree tile, assuming row-index and col-index are at
*> a tree area.
simulate-tree.
*> Find the row and column of the bottom-right neighbour.
COMPUTE next-row = FUNCTION MIN(row-index + 1, AREA-SIZE)
COMPUTE next-col = FUNCTION MIN(col-index + 1, AREA-SIZE)
COMPUTE neighbours-row = FUNCTION MAX(row-index - 1, 1)
COMPUTE neighbours-col = FUNCTION MAX(col-index - 1, 1)
 
*> If a neighbour is burning, catch fire.
PERFORM VARYING neighbours-row FROM neighbours-row BY 1
UNTIL next-row < neighbours-row
*> Check if neighbours in a row are on fire.
PERFORM VARYING neighbours-col FROM neighbours-col BY 1
UNTIL next-col < neighbours-col
IF neighbours-row = row-index
AND neighbours-col = col-index
EXIT PERFORM CYCLE
END-IF
IF burning OF current-status
(neighbours-row, neighbours-col)
SET burning OF next-status (row-index, col-index)
TO TRUE
EXIT PARAGRAPH
END-IF
END-PERFORM
 
*> Move neighbours-col back to starting position
COMPUTE neighbours-col =
FUNCTION MAX(neighbours-col - 3, 1)
END-PERFORM
 
*> Otherwise, there is a random chance of
*> catching fire.
PERFORM get-rand-num
IF rand-num <= IGNITE-PROB
SET burning OF next-status (row-index, col-index) TO TRUE
END-IF
.
 
update-statuses.
PERFORM VARYING row-index FROM 1 BY 1
UNTIL AREA-SIZE < row-index
AFTER col-index FROM 1 BY 1
UNTIL AREA-SIZE < col-index
MOVE next-status (row-index, col-index)
TO current-status (row-index, col-index)
END-PERFORM
.
 
*> Puts a random value between 0 and 9999 in rand-num.
get-rand-num.
COMPUTE rand-num =
FUNCTION MOD(FUNCTION RANDOM * 100000, 10000)
.</syntaxhighlight>
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defvar *dims* '(10 10))
(defvar *prob-t* 0.5)
(defvar *prob-f* 0.1)
Line 1,666 ⟶ 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 1,742 ⟶ 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 TREE_PROBtreeProb = 0.55; // originalOriginal tree probability.
enum F_PROBfProb = 0.01; // autoAuto combustion probability.
enum P_PROBcProb = 0.01; // treeTree creation probability.
 
enum Cell : char { empty=' ', tree='T', fire='#' }
alias World = Cell[][] World;
 
bool hasBurningNeighbours(in World world, in intulong r, in intulong c)
pure nothrow @safe @nogc {
foreach (immutable rowShift; -1 .. 2)
foreach (immutable colShift; -1 .. 2)
if ((r + rowShift) >= 0 && (r + rowShift) < world.length &&
(c + colShift) >= 0 && (c + colShift) < world[0].length &&
world[r + rowShift][c + colShift] == Cell.fire)
return true;
return false;
}
 
void nextState(in World world, World nextWorld) /*nothrow*/ @safe /*@nogc*/ {
foreach (r, row; world)
foreach (c, elem; row)
final switch (elem) with (Cell) {
case Cell.empty:
nextWorld[r][c]= uniform(0.,1.)uniform01 <P_PROB cProb) ?Cell. tree :Cell. empty;
break;
 
case Cell.tree:
if (world.hasBurningNeighbours(r, c))
nextWorld[r][c] = Cell.fire;
else
nextWorld[r][c] =uniform (0.,1.)uniform01 <F_PROB fProb) ?Cell. fire :Cell. tree;
break;
 
case Cell.fire:
nextWorld[r][c] = Cell.empty;
break;
}
}
 
void main() @safe {
auto world = new World(8, 65);
foreach (row; world)
foreach (ref el; row)
el = uniform(0.0, 1.0)uniform01 < TREE_PROBtreeProb) ? Cell.tree : Cell.empty;
auto nextWorld = new World(world.length, world[0].length);
 
foreach (immutable i; 0 .. 4) {
nextState(world, nextWorld);
writeln writefln(join"%(cast%(string[]%c%)nextWorld, "\n"%), "\n", nextWorld);
world.swap(world, nextWorld);
}
}</langsyntaxhighlight>
{{out}}
<pre> T T T#TT T TT TT TTTT TT TTT T TT T# T T TT TT TTTTT
Line 1,839 ⟶ 3,673:
 
===Graphical Version===
{{libheader|simpledisplay}} (With Image class made final).
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.stringalgorithm, std.algorithmtypetuple, simpledisplay;
simpledisplay;
 
enum double TREE_PROB = 0.55; // originalOriginal tree probability.
enum double F_PROB = 0.01; // autoAuto combustion probability.
enum double P_PROB = 0.01; // treeTree creation probability.
enum worldSide = 600;
 
enum Cell : ubyte { empty, tree, burning }
template TypeTuple(T...) { alias T TypeTuple; }
alias TypeTuple!(-1,World 0,= 1) spCell[worldSide][];
 
enum Cell : char { empty=' ', tree='T', burning='#' }
alias Cell[][] World;
 
immutable white = Color(255, 255, 255),
Line 1,858 ⟶ 3,691:
void nextState(ref World world, ref World nextWorld,
ref Xorshift rnd, Image img) {
enum double div = cast(double)typeof(rnd.front()).max;
immutable nr = world.length;
immutable nc = world[0].length;
foreach (immutable r, const row; world)
foreach (immutable c, immutable elem; row)
START: final switch (elem) with (Cell) {
case Cell.empty:
img.putPixel(c, r, white);
nextWorld[r][c] = (rnd.front()/div)uniform01 < P_PROB ? Cell.tree : Cell.empty;
rnd.popFront();
break;
 
case Cell.tree:
img.putPixel(c, r, green);
 
foreach (immutable rowShift; spTypeTuple!(-1, 0, 1))
foreach (immutable colShift; spTypeTuple!(-1, 0, 1))
if ((r + rowShift) >= 0 && (r + rowShift) < nr &&
(c + colShift) >= 0 && (c + colShift) < nc &&
world[r + rowShift][c + colShift] == Cell.burning) {
nextWorld[r][c] = Cell.burning;
gotobreak ENDSTART;
}
 
nextWorld[r][c]=( rnd.front()/div)uniform01 < F_PROB ? Cell.burning : Cell.tree;
rnd.popFront()break;
END: break;
 
case Cell.burning:
img.putPixel(c, r, red);
nextWorld[r][c] = Cell.empty;
break;
}
Line 1,897 ⟶ 3,727:
void main() {
auto rnd = Xorshift(1);
auto world = new World(600, 600worldSide); // create world
foreach (ref row; world)
foreach (ref el; row)
el = uniform(0rnd.0, 1.0, rnd)uniform01 < TREE_PROB ? Cell.tree : Cell.empty;
auto nextWorld = new World(world.length, world[0].length);
 
auto w= new SimpleWindow(world.length,world[0].length,"ForestFire");
Line 1,907 ⟶ 3,737:
 
w.eventLoop(1, {
auto painter = w.draw();
nextState(world, nextWorld, rnd, img);
painter.drawImage(Point(0, 0), img);
});
}</langsyntaxhighlight>
 
About 34 FPS, 600x600 cells.
=={{header|Déjà Vu}}==
<syntaxhighlight lang="dejavu">#chance of empty->tree
set :p 0.004
#chance of spontaneous tree combustion
set :f 0.001
#chance of tree in initial state
set :s 0.5
#height of world
set :H 10
#width of world
set :W 20
 
has-burning-neigbour state pos:
for i range -- swap ++ dup &< pos:
for j range -- swap ++ dup &> pos:
& i j
try:
state!
catch value-error:
:empty
if = :burning:
return true
false
 
evolve state pos:
state! pos
if = :tree dup:
if has-burning-neigbour state pos:
:burning drop
elseif chance f:
:burning drop
elseif = :burning:
:empty
else:
if chance p:
:tree
else:
:empty
 
step state:
local :next {}
for k in keys state:
set-to next k evolve state k
next
 
local :(c) { :tree "T" :burning "B" :empty "." }
print-state state:
for j range 0 H:
for i range 0 W:
!print\ (c)! state! & i j
!print ""
 
init-state:
local :first {}
for j range 0 H:
for i range 0 W:
if chance s:
:tree
else:
:empty
set-to first & i j
first
 
run:
init-state
while true:
print-state dup
!print ""
step
 
run-slowly:
init-state
while true:
print-state dup
drop !prompt "Continue."
step
 
run</syntaxhighlight>
{{out}}
<pre>T.T.T...T..T..TT.T.T.
.TT.T...T..T....TTTTT
......T.TTT.TTTTT....
..TTT...T.T..T..TTT..
....T.....TTT...TTTTT
..TTT..TTTTTTTTT....T
T....T..TT.TT.T...T..
TTT.TT.T..TT.TTT.TT..
.TT.TT.T...T.T..T.TTT
..TTTTT...TTTTTT..T.T
TT..T....T..T..TTTT..
 
TTT.T...T..T.TTT.T.T.
.TT.T...T..T..T.TTTTT
......T.TTT.TTTTT....
..TTT...T.T..T..TTT..
....TT....TTB...TTTTT
..TTT..TTTTTTTTT...TT
T....T.TTT.TT.T...T..
TTT.TT.T..TB.TTT.TT..
.TT.TT.T...T.T..T.TTT
..TTTTB...TTTTTT..T.T
TT..T....T..T..TTTT..
 
TTT.T...T..T.TTT.T.T.
.TTTT...T..T..T.TTTTT
......T.TTTTTTTTT....
..TTT...T.T..B..TTT..
....TT....TB....TTTTT
..TTT..TTTTBBBTT...TT
T....T.TTT.BB.T...T..
TTT.TT.T..B..TTT.TT..
.TTTTB.B...B.T..T.TTT
..TTTB....TTTTTT..T.T
TT..T....T..T..TTTT..</pre>
 
=={{header|EasyLang}}==
 
[https://easylang.online/apps/forest-fire.html Run it]
 
<syntaxhighlight>
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}}==
<syntaxhighlight lang="lisp">#!/usr/bin/env emacs -script
;; -*- lexical-binding: t -*-
;; run: ./forest-fire forest-fire.config
(require 'cl-lib)
;; (setq debug-on-error t)
 
(defmacro swap (a b)
`(setq ,b (prog1 ,a (setq ,a ,b))))
 
(defconst burning ?B)
(defconst tree ?t)
 
(cl-defstruct world rows cols data)
 
(defun new-world (rows cols)
;; When allocating the vector add padding so the border will always be empty.
(make-world :rows rows :cols cols :data (make-vector (* (1+ rows) (1+ cols)) nil)))
 
(defmacro world--rows (w)
`(1+ (world-rows ,w)))
 
(defmacro world--cols (w)
`(1+ (world-cols ,w)))
 
(defmacro world-pt (w r c)
`(+ (* (mod ,r (world--rows ,w)) (world--cols ,w))
(mod ,c (world--cols ,w))))
 
(defmacro world-ref (w r c)
`(aref (world-data ,w) (world-pt ,w ,r ,c)))
 
(defun print-world (world)
(dotimes (r (world-rows world))
(dotimes (c (world-cols world))
(let ((cell (world-ref world r c)))
(princ (format "%c" (if (not (null cell))
cell
?.)))))
(terpri)))
 
(defun random-probability ()
(/ (float (random 1000000)) 1000000))
 
(defun initialize-world (world p)
(dotimes (r (world-rows world))
(dotimes (c (world-cols world))
(setf (world-ref world r c) (if (<= (random-probability) p) tree nil)))))
 
(defun neighbors-burning (world row col)
(let ((n 0))
(dolist (offset '((1 . 1) (1 . 0) (1 . -1) (0 . 1) (0 . -1) (-1 . 1) (-1 . 0) (-1 . -1)))
(when (eq (world-ref world (+ row (car offset)) (+ col (cdr offset))) burning)
(setq n (1+ n))))
(> n 0)))
 
(defun advance (old new p f)
(dotimes (r (world-rows old))
(dotimes (c (world-cols old))
(cond
((eq (world-ref old r c) burning)
(setf (world-ref new r c) nil))
((null (world-ref old r c))
(setf (world-ref new r c) (if (<= (random-probability) p) tree nil)))
((eq (world-ref old r c) tree)
(setf (world-ref new r c) (if (or (neighbors-burning old r c)
(<= (random-probability) f))
burning
tree)))))))
 
(defun read-config (file-name)
(with-temp-buffer
(insert-file-contents-literally file-name)
(read (current-buffer))))
 
(defun get-config (key config)
(let ((val (assoc key config)))
(if (null val)
(error (format "missing value for %s" key))
(cdr val))))
 
(defun simulate-forest (file-name)
(let* ((config (read-config file-name))
(rows (get-config 'rows config))
(cols (get-config 'cols config))
(skip (get-config 'skip config))
(a (new-world rows cols))
(b (new-world rows cols)))
(initialize-world a (get-config 'tree config))
(dotimes (time (get-config 'time config))
(when (or (and (> skip 0) (= (mod time skip) 0))
(<= skip 0))
(princ (format "* time %d\n" time))
(print-world a))
(advance a b (get-config 'p config) (get-config 'f config))
(swap a b))))
 
(simulate-forest (elt command-line-args-left 0))
</syntaxhighlight>
 
The configuration file controls the simulation.
<syntaxhighlight lang="lisp">((rows . 10)
(cols . 45)
(time . 100)
(skip . 10)
(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</syntaxhighlight>
 
{{out}}
<pre style="height:35ex;overflow:scroll;">
* time 0
.t...t..t.t.t...ttt...tttt..tt...t.t.t.t.t..t
.t.t.t..t.ttt.tt.tttt.tt....t.t.tt.t.t.tt.ttt
t..t.tttt..t..tt..tt.t.t.tt.....t..t..tt.tt.t
.tt.t.ttt.t...t...tt..t....tttttt.t..tt.tt.tt
.t..t..t.tt.t...tt...t.t.tt.t.t..ttttt.t..ttt
.tt.ttttt..t.t....tttt.t.t..tttttt.tt.t.t.t.t
ttt.....t.tttttttt.tt....ttt.t.....t.ttt..ttt
.tt..tt.tt.ttt...tt.t..ttt.t.tt.tt....tttt...
t.tt...tttt...t.t.tt.tt..ttt...t.tt.t.tttttt.
...t......t.t...tttt...ttttt.tttt..t..t.tttt.
* time 10
......................tttt..tt...t.B........B
....................B.tt...tt.t.tt..........B
.....................t.t.tt.....B...........B
...........t..........t...tttttB............B
.............t..tB...t.t.tt.t.tB.........t..B
.........t.......ttttt.t.tt.tttB.............
................Btttt....ttttt...........t...
t....B...t.......tt.t..ttt.t.tt.BB...........
.....B..........t.ttttt..ttt..tt.tt.t...t....
................tttt...ttttt.tttt..t.........
* time 20
..........t.....t.t................t........t
.....t...........t.t.........................
.........................t..............t....
..........tttt..........................t....
.t.........t.t...........................t...
....t....t......................t............
..t.tt.....t..............t........t.t...t...
tt.......t...................................
..t...t.........................t....t..t.t..
.....t.......................................
* time 30
......t...t.....t.t......t.........t.......tt
.....t.........t.t.t...............t...t.....
...........tt.........t..t..t......t....t....
..........tttt.......t.....t.........t..t....
.t.........t.t...t.tt..........t.........t...
....t....t......t.tt.t..........t.......t....
..t.tt.....t..t.....t.t...t..tB....t.t...t...
tt..t....t.......t..................t........
..t...t....t...........t........t....t..t.t..
.....t...t....t..t....tt.t.....t...........t.
* time 40
......t...t.....t.t......t......t..t.......tt
.....t.........t.t.tt..............tt..t.....
...........tt............t..t......t....tt...
t...t.....tttt.............tt.t.t....t..t....
.t.........t.t......t..........t.........t...
....t....t...t........t.t.......t.t..t..t....
..t.tt.....t..B....t......t....t...t.t...t...
tt..t....t.t.....tt.................t........
..t...t....t..t........tt.t.....t....t..t.t..
..t..t...t....t..t....tt.t.....t......t....t.
* time 50
......t...t.....t.t......t.....tt.t...t....tt
..t.tt.........t.t.tt.t......t.t...t...t.....
.........................t..t..t..t.....tt...
t...t......................tt.t.t....t..t...t
.t..................t.........tt.........t..t
....t....t..........t.t.t.......t.t..t..t....
..tttt...t.t.......t......t....t...ttt...tt.t
tt..t.t..t.t.....tt.................t........
..t...t....t..t....t...tt.t.....t....tt.t.t..
..t..t...t....t..t....tt.t.t...t....t.t....t.
* time 60
......t...t.t...t.t.t....t.....tt.t...t....tt
..t.tt.......t.t.t.tt.t......t.t...t...t..t.t
......t.t...............tt.tt..t..t.....tt...
t...t.t.............t......tt.t.t....t..t...t
tt...............tttt.........tt.........t..t
....tt.ttt..t.......t.t.t.t.....t.t..t..t....
..tttt...ttt.......t......t....t...ttt..ttt.t
tt..t.t.tt.t...t.tt.................t....t...
..tt..t....t..t..t.t...B........t....tt.t.t..
..t..t...t....t..t..t.tB...Bt..t...tt.t....t.
* time 70
......tt..t.t...t.t.t.t..t.....tt.t...t....tt
t.t.tt.......t.t.t.tt.t.....tttt...t...t..t.t
.t....t.t............t..tt.tt..t..t....ttt...
t...t.tt..t.....t...t...t..tt.t.tt...t..t.t.t
tt.....t.........tttt.........tt..t......tt.t
....ttttttt.t...t...t.t.t.t.....t.t..t..t.t..
..tttt...ttt..t....t......t...tt...ttt..ttt.t
ttt.t.t.tttt...t.tt....t.......t....tt..tt...
..tt..ttt.tt..t..ttt.....t......t...ttt.t.t..
..t..tt..t....t.tt..t..........t.t.tt.t...tt.
* time 80
....t.tt.tt.t...t.t.t.t..t....ttt.t.........B
t.t.tt.......t.t.t.tt.t.....ttttt..t........B
.t....t.t............t..tt.tt..t..t..........
t...t.ttt.t.....t...t...t..tt.tttt...t......t
tt.....t.......tttttt....t....ttt.ttt.......t
....ttttttt.t..tt..tt.t.t.t.....t.t..t.......
..tttt...ttt..tt...t......t...tt...ttt......t
ttt.t.t.tttt...t.tt....t......ttt...tt..BB...
..ttt.ttt.tt..t..tttt....tt.....t...ttt.t.t..
..t..tt..t....tttt.tt..........t.t.tt.t...tt.
* time 90
....t.tt.tt.t...t.t.t.t..t........B..........
t.t.tt.......t.ttt.tt.t.............B........
tt....t.t.t.......t..t..tt...................
t...t.ttt.t.....t.t.t.t.t............t..t...t
tt.tt.tt.......tttttt....t..........B...t...t
....ttttttt.t..ttt.tt.ttt.t..........t.....t.
..tttt...ttt..tt.t.t......t........Btt..t.t.t
ttt.t.t.tttt...t.tt..t.t...........ttt.......
..ttt.ttt.tt..t..tttt.t..tt.....BB..ttt......
..t..tt..t....tttt.tt.......t..t.t.tt.t......
</pre>
 
=={{header|Erlang}}==
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">
-module( forest_fire ).
 
-export( [task/0] ).
 
-record( state, {neighbours=[], position, probability_burn, probability_grow, tree} ).
 
task() ->
erlang:spawn( fun() ->
Pid_positions = forest_create( 5, 5, 0.5, 0.3, 0.2 ),
Pids = [X || {X, _} <- Pid_positions],
[X ! {tree_pid_positions, Pid_positions} || X <- Pids],
Start = forest_status( Pids ),
Histories = [Start | [forest_step( Pids ) || _X <- lists:seq(1, 2)]],
[io:fwrite("~p~n~n", [X]) || X <- Histories]
end ).
 
 
 
forest_create( X_max, Y_max, Init, Grow, Burn ) ->
[{tree_create(tree_init(Init, random:uniform()), X, Y, Grow, Burn), {X,Y}} || X <- lists:seq(1, X_max), Y<- lists:seq(1, Y_ma\
x)].
 
forest_status( Pids ) ->
[X ! {status_request, erlang:self()} || X <- Pids],
[receive {status, Tree, Position, X} -> {Tree, Position} end || X <- Pids].
 
forest_step( Pids ) ->
[X ! {step} || X <- Pids],
forest_status( Pids ).
 
is_neighbour({X, Y}, {X, Y} ) -> false; % Myself
is_neighbour({Xn, Yn}, {X, Y} ) when abs(Xn - X) =< 1, abs(Yn - Y) =< 1 -> true;
is_neighbour( _Position_neighbour, _Position ) -> false.
 
loop( State ) ->
receive
{tree_pid_positions, Pid_positions} ->
loop( loop_neighbour(Pid_positions, State) );
{step} ->
[X ! {tree, State#state.tree, erlang:self()} || X <- State#state.neighbours],
loop( loop_step(State) );
{status_request, Pid} ->
Pid ! {status, State#state.tree, State#state.position, erlang:self()},
loop( State )
end.
 
loop_neighbour( Pid_positions, State ) ->
My_position = State#state.position,
State#state{neighbours=[Pid || {Pid, Position} <- Pid_positions, is_neighbour( Position, My_position)]}.
 
loop_step( State ) ->
Is_burning = lists:any( fun loop_step_burning/1, [loop_step_receive(X) || X <- State#state.neighbours] ),
Tree = loop_step_next( Is_burning, random:uniform(), State ),
State#state{tree=Tree}.
 
loop_step_burning( Tree ) -> Tree =:= burning.
 
loop_step_next( _Is_burning, Probablility, #state{tree=empty, probability_grow=Grow} ) when Grow > Probablility -> tree;
loop_step_next( _Is_burning, _Probablility, #state{tree=empty} ) -> empty;
loop_step_next( _Is_burning, _Probablility, #state{tree=burning} ) -> empty;
loop_step_next( true, _Probablility, #state{tree=tree} ) -> burning;
loop_step_next( false, Probablility, #state{tree=tree, probability_burn=Burn} ) when Burn > Probablility -> burning;
loop_step_next( false, _Probablility, #state{tree=tree} ) -> tree.
 
loop_step_receive( Pid ) -> receive {tree, Tree, Pid} -> Tree end.
 
tree_create( Tree, X, Y, Grow, Burn ) ->
State = #state{position={X, Y}, probability_burn=Burn, probability_grow=Grow, tree=Tree},
erlang:spawn_link( fun() -> random:seed( X, Y, 0 ), loop( State ) end ).
 
tree_init( Tree_probalility, Random ) when Tree_probalility > Random -> tree;
tree_init( _Tree_probalility, _Random ) -> empty.
</syntaxhighlight>
 
{{out}}
29> forest_fire:task().
<pre>
[{tree,{1,1}},
{empty,{1,2}},
{empty,{1,3}},
{empty,{1,4}},
{tree,{1,5}},
{empty,{2,1}},
{empty,{2,2}},
{empty,{2,3}},
{tree,{2,4}},
{empty,{2,5}},
{tree,{3,1}},
{tree,{3,2}},
{empty,{3,3}},
{tree,{3,4}},
{empty,{3,5}},
{tree,{4,1}},
{tree,{4,2}},
{tree,{4,3}},
{tree,{4,4}},
{empty,{4,5}},
{tree,{5,1}},
{tree,{5,2}},
{tree,{5,3}},
{tree,{5,4}},
{empty,{5,5}}]
 
[{burning,{1,1}},
{tree,{1,2}},
{tree,{1,3}},
{tree,{1,4}},
{burning,{1,5}},
{tree,{2,1}},
{tree,{2,2}},
{tree,{2,3}},
{burning,{2,4}},
{tree,{2,5}},
{burning,{3,1}},
{burning,{3,2}},
{tree,{3,3}},
{burning,{3,4}},
{tree,{3,5}},
{burning,{4,1}},
{burning,{4,2}},
{burning,{4,3}},
{burning,{4,4}},
{tree,{4,5}},
{burning,{5,1}},
{burning,{5,2}},
{burning,{5,3}},
{burning,{5,4}},
{tree,{5,5}}]
 
[{empty,{1,1}},
{burning,{1,2}},
{burning,{1,3}},
{burning,{1,4}},
{empty,{1,5}},
{burning,{2,1}},
{burning,{2,2}},
{burning,{2,3}},
{empty,{2,4}},
{burning,{2,5}},
{empty,{3,1}},
{empty,{3,2}},
{burning,{3,3}},
{empty,{3,4}},
{burning,{3,5}},
{empty,{4,1}},
{empty,{4,2}},
{empty,{4,3}},
{empty,{4,4}},
{burning,{4,5}},
{empty,{5,1}},
{empty,{5,2}},
{empty,{5,3}},
{empty,{5,4}},
{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 2,005 ⟶ 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}}
<syntaxhighlight lang="forth">30 CONSTANT WIDTH
30 CONSTANT HEIGHT
WIDTH HEIGHT * CONSTANT SIZE
 
1 VALUE SEED
: (RAND) ( -- u) \ xorshift generator
SEED DUP 13 LSHIFT XOR
DUP 17 RSHIFT XOR
DUP 5 LSHIFT XOR
DUP TO SEED ;
10000 CONSTANT RANGE
100 CONSTANT GROW
1 CONSTANT BURN
: RAND ( -- u) (RAND) RANGE MOD ;
 
\ Create buffers for world state
CREATE A SIZE ALLOT A SIZE ERASE
CREATE B SIZE ALLOT B SIZE ERASE
 
0 CONSTANT NONE 1 CONSTANT TREE 2 CONSTANT FIRE
: NEARBY-FIRE? ( addr u -- t|f)
2 -1 DO
2 -1 DO
J WIDTH * I + OVER + \ calculate an offset
DUP 0> OVER SIZE < AND IF
>R OVER R> + C@ \ fetch state of the offset cell
FIRE = IF UNLOOP UNLOOP DROP DROP TRUE EXIT THEN
ELSE DROP THEN
LOOP
LOOP DROP DROP FALSE ;
: GROW? RAND GROW <= ; \ spontaneously sprout?
: BURN? RAND BURN <= ; \ spontaneously combust?
: STEP ( prev next --) \ Given state in PREV, put next in NEXT
>R 0 BEGIN DUP SIZE <
WHILE
2DUP + C@ CASE
FIRE OF NONE ENDOF
TREE OF 2DUP NEARBY-FIRE? BURN? OR IF FIRE ELSE TREE THEN ENDOF
NONE OF GROW? IF TREE ELSE NONE THEN ENDOF
ENDCASE
( i next-cell-state) OVER R@ + C! \ commit to next
1+ REPEAT R> DROP DROP DROP ;
 
: (ESCAPE) 27 EMIT [CHAR] [ EMIT ;
: ESCAPE" POSTPONE (ESCAPE) POSTPONE S" POSTPONE TYPE ; IMMEDIATE
: CLEAR ESCAPE" H" ;
: RETURN ESCAPE" E" ;
: RESET ESCAPE" m" ;
: .FOREST ( addr --) CLEAR
HEIGHT 0 DO
WIDTH 0 DO
DUP C@ CASE
NONE OF SPACE ENDOF
TREE OF ESCAPE" 32m" [CHAR] T EMIT RESET ENDOF
FIRE OF ESCAPE" 31m" [CHAR] # EMIT RESET ENDOF
ENDCASE 1+
LOOP RETURN
LOOP RESET DROP ;
 
: (GO) ( buffer buffer' -- buffer' buffer)
2DUP STEP \ step the simulation
DUP .FOREST \ print the current state
SWAP ; \ prepare for next iteration
: GO A B BEGIN (GO) AGAIN ;</syntaxhighlight>
 
=={{header|Fortran}}==
{{works with|Fortran|95 and later}}
 
<langsyntaxhighlight lang="fortran">module ForestFireModel
implicit none
 
Line 2,193 ⟶ 4,862:
end subroutine forestfire_print
 
end module ForestFireModel</langsyntaxhighlight>
 
<langsyntaxhighlight lang="fortran">program ForestFireTest
use ForestFireModel
implicit none
Line 2,212 ⟶ 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 2,298 ⟶ 4,968:
}
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import DataControl.ListMonad (replicateM, unless)
import ControlData.ArrowList (tails, transpose)
import ControlSystem.MonadRandom (randomRIO)
import System.Random
 
data Cell = Empty | Tree | Fire deriving (Eq)
 
data Cell
= Empty
| Tree
| Fire
deriving (Eq)
instance Show Cell where
show Empty = " "
show Tree = "T"
show Fire = "$"
 
randomCell = liftM ([Empty, Tree] !!) (randomRIO (0,1) :: IO Int)Cell
randomChancerandomCell = fmap ([Empty, Tree] !!) (randomRIO (0, 1.0) :: IO DoubleInt)
 
randomChance :: IO Double
rim b = map (fb b). (fb =<< rb) where
randomChance = randomRIO (0, 1.0) :: IO Double
fb = liftM2 (.) (:) (flip (++) . return)
rb = fst. unzip. zip (repeat b). head
rim :: a -> [[a]] -> [[a]]
 
rim b = fmap (fb b) . (fb =<< rb)
take3x3 = concatMap (transpose. map take3). take3 where
where
take3 = init. init. takeWhile (not.null). map(take 3). tails
fb = (.) <$> (:) <*> (flip (++) . return)
 
rb = fst . unzip . zip (repeat b) . head
list2Mat n = takeWhile(not.null). map(take n). iterate(drop n)
 
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
let s = m * n
fs <- replicateM s randomCell
 
let nextState xs = do
ts <- replicateM s randomChance
vs <- replicateM s randomChance
let rv [r1, [l, c, r], r3] newTree fire
| c == Fire = Empty
| c == Tree && Fire `elem` concat [r1, [l, r], r3] = Fire
| c == Tree && 0.01 >= fire = Fire
| c == Empty && 0.1 >= newTree = Tree
| otherwise = c
return $ zipWith3 rv xs ts vs
evolve i xs =
 
evolve i xs = unless (i > k) $
do let nfs = nextState $ take3x3 $ rim Empty $ list2Mat n xs
putStrLn ("\n>>>>>> " ++ show i ++ ":")
mapM_ (putStrLn . concatMap show) $ list2Mat n xs
nfs >>= evolve (i + 1)
evolve 1 fs
 
evolve 1 fs</lang>
main :: IO ()
A run:
<langmain haskell>*Main>= evolveForest 6 50 3</syntaxhighlight>
{{Out}} Sample:
 
<pre>>>>>>> 1:
TTT TTT TTT T TTTTTTTTTTTT TTT TTT TT T T TT T TT TTTTTT
TTTTTTT TTT T TT TTTT T T TT T T TTTTTTT T T T T TTTTTTT T TT TT
T TTTT TT T TTTTTTT T TT TTTTT TTTTTTTTT TTTT T TT TT TTT TTT T TTTTT TTTTT
T TT TTTTTT TTTT TTT TT TTT TTT T TTTTTTT T TTTT T TTT TT T TTTTT
TTT T TT TTT TT TTT T T TT T T TT T TT T TT T T TTTTTTTT TT
T TT T T T TTT TTTTTTTT TTT T T T T TT TTTTT TT TT T TT
 
>>>>>> 2:
TTT TTT TTT TTT T TTTTTTTTTTTT TT T T TT TT T T$ TT TTTT TT
TTTTTTT TTT T TT TTTT T T T TT TTTTTTTT T T TTT T TT T TTT TTTTT TTT
TT TTTT TT$ T TTTTTT TTTTT$TT T TTTT T TT T T TTTT TTT$T TT TTTTTT TT T TTT
TT TT T TT T TTTTTTT T TTTT T TTT TTTTTT TT T TTTTTTT TTTT TTTTTTT TTT
TT TT TTTTT TTTT TT T T TT T T TT T TT T TT T T TTTTTTTT TT
TTT T TT TT T T TTT TTTTTTTT TTT T T T T TT TTTTT TT TTT TTT TT
 
>>>>>> 3:
TTT TTTTT TT TT T TTTTTTTTT TT TTT TTT TTT TT T T TT T TT $ TTTTTT TT
TTTT TT T $$T TTTT T T TT $$ TTTTTTTTTT T $T T $ T$ TTT TTTTT TTT
TTTTTTTTTTT TT T$ T TTTTTT TTTT$ $T TT T TTTT T TT$ $ TTTTTTT TT TT T TTT
T TTTTTTTT TTT TTTTTTTT TT T $ TTTTTT$ T TTTTTTT T $$$T T TTT $$ T TTTTTT TTT
TTTTT TTTT TT TT TTT T T TT TT T TT T TT T TT T T TTTTTTTT TT
TTT T TT TT T T T TTT TTTTTTTT TTT T T T T TT TTTTTT TT TTT T TT TT</langpre>
 
=={{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 2,449 ⟶ 5,128:
procedure probability(P) #: succeed with probability P
if ?0 <= P then return
end</langsyntaxhighlight>
 
{{libheader|Icon Programming Library}}
Line 2,456 ⟶ 5,135:
 
=={{header|J}}==
<langsyntaxhighlight lang="j">NB. states: 0 empty, 1 tree, _1 fire
dims =:10 10
 
Line 2,476 ⟶ 5,155:
smoutput ' #o' {~ forest=. step forest
end.
)</langsyntaxhighlight>
 
Example use:
 
<langsyntaxhighlight lang="j"> run 2
##### #
Line 2,499 ⟶ 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 2,506 ⟶ 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 2,646 ⟶ 5,345:
processNPrint(land, 10);
}
}</langsyntaxhighlight>
===Graphics===
See: [[Forest fire/Java/Graphics]]
 
=={{header|JAMES II/Rule-based Cellular AutomataJavaScript}}==
<lang j2carules>@caversion 1;
 
===JavaScript Node===
dimensions 2;
 
Functional approach using [https://lodash.com/ lodash]
state EMPTY, TREE, BURNING;
 
<syntaxhighlight lang="javascript">"use strict"
// an empty cell grows a tree with a chance of p = 5 %
rule{EMPTY} [0.05] : -> TREE;
 
const _ = require('lodash');
// a burning cell turns to a burned cell
rule{BURNING}: -> EMPTY;
 
const WIDTH_ARGUMENT_POSITION = 2;
// a tree starts burning if there is at least one neighbor burning
const HEIGHT_ARGUMENT_POSITION = 3;
rule{TREE} : BURNING{1,} -> BURNING;
const TREE_PROBABILITY = 0.5;
const NEW_TREE_PROBABILITY = 0.01;
const BURN_PROBABILITY = 0.0001;
const CONSOLE_RED = '\x1b[31m';
const CONSOLE_GREEN = '\x1b[32m';
const CONSOLE_COLOR_CLOSE = '\x1b[91m';
const CONSOLE_CLEAR = '\u001B[2J\u001B[0;0f';
const NEIGHBOURS = [
[-1, -1],
[-1, 0],
[-1, 1],
[ 0, -1],
[ 0, 1],
[ 1, -1],
[ 1, 0],
[ 1, 1]
];
const PRINT_DECODE = {
' ': ' ',
'T': `${CONSOLE_GREEN}T${CONSOLE_COLOR_CLOSE}`,
'B': `${CONSOLE_RED}T${CONSOLE_COLOR_CLOSE}`,
};
const CONDITIONS = {
'T': (forest, y, x) => Math.random() < BURN_PROBABILITY || burningNeighbour(forest, y, x) ? 'B' : 'T',
' ': () => Math.random() < NEW_TREE_PROBABILITY ? 'T' : ' ',
'B': () => ' '
};
 
const WIDTH = process.argv[WIDTH_ARGUMENT_POSITION] || 20;
// a tree is hit by lightning with a change of f = 0.006 %
const HEIGHT = process.argv[HEIGHT_ARGUMENT_POSITION] || 10;
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.
 
const update = forest => {
=={{header|JavaScript}}==
<lang javascript>var return _.map(forest, (c, ci) => {
return _.map(c, (r, ri) => {
return CONDITIONS[r](forest, ci, ri);
});
});
}
 
const printForest = forest => {
process.stdout.write(CONSOLE_CLEAR);
_.each(forest, c => {
_.each(c, r => {
process.stdout.write(PRINT_DECODE[r]);
});
process.stdout.write('\n');
})
}
 
const burningNeighbour = (forest, y, x) => {
return _(NEIGHBOURS)
.map(n => _.isUndefined(forest[y + n[0]]) ? null : forest[y + n[0]][x + n[1]])
.any(_.partial(_.isEqual, 'B'));
};
 
let forest = _.times(HEIGHT, () => _.times(WIDTH, () => Math.random() < TREE_PROBABILITY ? 'T' : ' '));
 
setInterval(() => {
forest = update(forest);
printForest(forest)
}, 20);
 
</syntaxhighlight>
 
 
===JavaScript===
<syntaxhighlight lang="javascript">var forest = {
X: 50,
Y: 50,
Line 2,734 ⟶ 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 2,752 ⟶ 5,508:
</body>
</html>
</syntaxhighlight>
</lang>
 
The output is a (mostly fluent) animation of the area.
 
=={{header|Liberty BASICJulia}}==
<syntaxhighlight lang="julia">using Printf
<lang lb>'[RC] Forest Fire
dim oldgen(200,200), newgen(200,200)
p =0.99
f =0.9999
 
@enum State empty tree fire
nomainwin
WindowWidth = 200
WindowHeight = 200
open "Forest Fire" for graphics_nsb_nf as #1
#1 "trapclose [quit]"
#1 "down ; fill brown ; flush"
 
p =0.99
f =0.9999
 
function evolution(nepoch::Int=100, init::Matrix{State}=fill(tree, 30, 50))
for generation = 1 to 200
# Single evolution
for x = 1 to 199
function evolve!(forest::Matrix{State}; f::Float64=0.12, p::Float64=0.5)
for y = 1 to 199
dir = [-1 -1; -1 0; -1 1; scan0 'we-1; can0 break1; early1 -1; 1 0; 1 1]
# A tree will burn if at least selectone caseneighbor oldgen(x,y)is burning
for i in 1:size(forest, 1), j in 1:size(forest, case 02)
for k in 1:size(dir, 1)
if rnd(0) > p then newgen(x,y) = 1 : #1 "color green ; set "; x; " "; y
if checkbounds(Bool, forest, i case+ dir[k, 1], j + dir[k, 2]) &&
newgenget(xforest,y) =i 0+ :dir[k, #1], "colorj brown+ ;dir[k, set2]) "; x; " ";== yfire
caseforest[i, 1j] = fire
if oldgen(x-1,y-1) = 2 or oldgen(x-1,y) = 2 or oldgen(x-1,y+1) = 2_break
end
or oldgen(x,y-1) = 2 or oldgen(x,y+1) = 2 or oldgen(x+1,y-1) = 2_
end
or oldgen(x+1,y) = 2 or oldgen(x+1,y+1) = 2 or rnd(0) > f then
end
#1 "color red ; set "; x; " "; y
for i in newgenLinearIndices(x,yforest) = 2
# A burning cell turns into an empty end ifcell
if forest[i] == fire endforest[i] select= empty end
# A tree ignites oldgen(x-1,y-1)=newgen(x-1,y-1)with probability f even if no neighbor is burning
if forest[i] == tree && rand() < f forest[i] = fire end
next y
# An empty space fills with a tree with probability p
next x
if forest[i] == empty && rand() < p forest[i] = tree end
next generation
end
end
 
# Print functions
function printforest(f::Matrix{State})
for i in 1:size(f, 1)
for j in 1:size(f, 2)
print(f[i, j] == empty ? ' ' : f[i, j] == tree ? '🌲' : '🔥')
end
println()
end
end
function printstats(f::Matrix{State})
tot = length(f)
nt = count(x -> x in (tree, fire), f)
nb = count(x -> x == fire, f)
@printf("\n%6i cell(s), %6i tree(s), %6i currently burning (%6.2f%%, %6.2f%%)\n",
tot, nt, nb, nt / tot * 100, nb / nt * 100)
end
 
# Main
printforest(init)
printstats(init)
for i in 1:nepoch
# println("\33[2J")
evolve!(init)
# printforest(init)
# printstats(init)
# sleep(1)
end
printforest(init)
printstats(init)
end
 
evolution()</syntaxhighlight>
 
{{out}}
Final output (epoch 100):
<pre>🌲🌲🔥🌲 🌲🌲🌲🌲 🔥🌲🌲🔥🌲🌲🌲🌲🌲🔥🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲 🌲🌲🌲🔥 🌲🌲🌲🌲🔥🌲🌲
🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲 🔥🌲🌲 🌲🌲🔥🔥🌲🌲 🌲🌲🌲 🌲🌲🌲🌲
🌲🌲🌲🌲🌲🔥🔥🌲 🌲🌲🌲 🔥🔥🌲🌲🌲 🌲 🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲 🌲🌲 🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲
🌲🔥🌲 🌲🌲 🌲 🌲🌲🌲🌲 🌲🌲 🌲 🌲🌲🌲 🌲🌲 🌲 🌲🔥🌲🌲🌲🔥🔥🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲
🌲🌲🌲 🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲 🌲🌲🌲 🌲🌲
🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲 🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲 🌲🌲
🌲🌲🌲 🌲🌲🌲🌲 🌲🌲 🌲🌲 🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🔥🌲 🌲🌲🌲🌲🌲🌲 🌲🌲🌲 🌲 🔥🌲🌲🌲🌲🌲
🌲🌲🔥🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲 🌲🌲🌲 🌲🌲 🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲
🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🔥 🌲🌲🌲🌲 🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥 🔥🌲🔥🌲🌲 🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲
🌲 🔥 🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲 🌲🌲🌲🌲🌲🔥🌲 🌲 🌲🌲🌲 🌲🔥 🔥🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🔥🌲🌲 🌲 🌲🌲🌲🌲🌲🌲
🌲🌲🔥🌲🌲🌲 🌲 🔥🌲 🌲 🌲 🌲🌲🌲🔥🌲🌲🔥🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲
🌲 🌲🌲 🌲🌲🌲🌲 🌲 🔥🔥🌲🌲🌲🔥 🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥 🌲🌲
🌲🌲🌲🔥 🌲🌲🌲🌲🔥🌲🔥🌲 🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲🔥🌲🌲
🌲🌲🌲🌲🌲 🌲🌲🌲🌲🌲🌲 🌲🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🔥 🌲🌲🌲🌲🌲🌲🔥 🌲🌲🌲 🔥🔥
🌲 🌲🌲🌲🌲🌲🌲🌲🔥 🌲🌲🌲🌲 🌲🌲 🌲🌲🔥🌲🌲 🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲 🔥🌲🔥🌲
🌲🌲🌲 🌲🌲🔥 🌲🌲🌲🌲🌲🌲🌲🌲🔥🌲🌲 🌲🔥 🌲🌲 🌲🌲🌲🔥🌲🌲🔥🌲 🔥🌲 🌲🌲🌲🌲🌲🌲🌲🌲 🌲
🌲🌲🌲 🔥🌲🌲🌲🌲 🌲🌲 🌲 🌲🌲🌲 🌲🌲🌲🌲🌲 🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲 🌲🌲🌲🌲🌲🌲🌲
🌲 🌲 🌲🌲 🌲🌲 🌲🌲 🌲 🌲🌲🌲🌲🌲🌲🌲 🌲 🌲 🌲🌲🌲 🌲🌲 🌲🌲🌲🌲 🌲 🌲
🌲🌲 🌲 🌲🌲🌲 🌲🌲 🌲 🌲🌲🌲🌲🌲 🌲🌲 🌲🌲 🌲🌲 🌲🌲 🌲🌲 🌲 🌲🌲🌲
🌲🌲 🌲🌲 🌲🌲 🌲🌲 🌲🌲 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 🌲 🌲 🌲🌲🌲 🌲
🌲🌲🌲 🌲🌲🌲🌲 🌲 🌲 🌲 🌲🌲🌲🌲🌲 🌲🌲 🌲 🌲 🌲🌲 🌲🌲 🌲 🌲🌲 🌲🌲
🌲🌲 🌲🌲🌲 🌲🌲🌲 🌲 🌲 🌲 🌲 🌲🌲 🌲 🌲🌲 🌲 🌲 🌲 🌲🌲
🌲🌲 🌲 🌲🌲🌲🌲 🌲 🌲🌲 🌲🌲🌲🌲 🌲 🌲🌲🌲🌲 🌲 🌲🌲🌲🌲
🌲🌲 🌲🌲 🌲🌲🌲🌲🌲 🌲 🌲🌲 🌲🌲🌲🌲🌲 🌲 🌲 🌲🌲🌲 🌲🌲🌲 🌲 🌲🌲 🌲 🌲
🌲 🌲🌲 🌲🌲 🌲 🌲🌲🌲🌲 🌲🌲 🌲 🌲🌲🌲 🌲🌲 🌲🌲🌲 🌲
🌲🌲 🌲🌲 🌲 🌲 🌲🌲🌲🌲🌲 🌲🌲 🌲 🌲 🌲 🌲🌲 🌲 🌲🌲🌲🌲🌲🌲 🌲🌲
🌲 🌲 🌲🌲 🌲🌲 🌲 🌲🌲 🌲🌲🌲 🌲 🌲 🌲 🌲 🌲🌲🌲🌲 🌲
🌲🌲🌲🌲🌲 🌲 🌲🌲 🌲 🌲 🌲🌲🌲 🌲🌲🌲 🌲 🌲🌲 🌲🌲 🌲 🌲🌲🌲🌲
 
1500 cell(s), 1089 tree(s), 73 currently burning ( 72.60%, 6.70%)</pre>
 
=={{header|Lua}}==
This program uses the Lua Curses library for graphics, although changing the code to avoid such dependency is easy.
<syntaxhighlight lang="lua">
-- ForestFire automaton implementation
-- Rules: at each step:
-- 1) a burning tree disappears
-- 2) a non-burning tree starts burning if any of its neighbours is
-- 3) an empty spot may generate a tree with prob P
-- 4) a non-burning tree may ignite with prob F
 
local socket = require 'socket' -- needed for socket.sleep
local curses = require 'curses'
 
local p_spawn, p_ignite = 0.005, 0.0002
local naptime = 0.03 -- seconds
local forest_x, forest_y = 60, 30
 
local forest = (function (x, y)
local wrl = {}
for i = 1, y do
wrl[i] = {}
for j = 1, x do
local rand = math.random()
wrl[i][j] = (rand < 0.5) and 1 or 0
end
end
return wrl
end)(forest_x, forest_y)
 
math.randomseed(os.time())
 
forest.step = function (self)
for i = 1, #self do
for j = 1, #self[i] do
if self[i][j] == 0 then
if math.random() < p_spawn then self[i][j] = 1 end
elseif self[i][j] == 1 then
if self:ignite(i, j) or math.random() < p_ignite then self[i][j] = 2 end
elseif self[i][j] == 2 then self[i][j] = 0
else error("Error: forest[" .. i .. "][" .. j .. "] is " .. self[i][j] .. "!")
end
end
end
end
 
forest.draw = function (self)
for i = 1, #self do
for j = 1, #self[i] do
if self[i][j] == 0 then win:mvaddch(i,j," ")
elseif self[i][j] == 1 then
win:attron(curses.color_pair(1))
win:mvaddch(i,j,"Y")
win:attroff(curses.color_pair(1))
elseif self[i][j] == 2 then
win:attron(curses.color_pair(2))
win:mvaddch(i,j,"#")
win:attroff(curses.color_pair(2))
else error("self[" .. i .. "][" .. j .. "] is " .. self[i][j] .. "!")
end
end
end
end
 
forest.ignite = function (self, i, j)
for k = i - 1, i + 1 do
if k < 1 or k > #self then goto continue1 end
for l = j - 1, j + 1 do
if l < 1 or
l > #self[i] or
math.abs((k - i) + (l - j)) ~= 1
then
goto continue2
end
if self[k][l] == 2 then return true end
::continue2::
end
::continue1::
end
return false
end
 
local it = 1
[quit]
curses.initscr()
close #1
curses.start_color()
end</lang>
curses.echo(false)
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
win = curses.newwin(forest_y + 2, forest_x, 0, 0)
win:clear()
win:mvaddstr(forest_y + 1, 0, "p_spawn = " .. p_spawn .. ", p_ignite = " .. p_ignite)
repeat
forest:draw()
win:move(forest_y, 0)
win:clrtoeol()
win:addstr("Iteration: " .. it .. ", nap = " .. naptime*1000 .. "ms")
win:refresh()
forest:step()
it = it + 1
socket.sleep(naptime)
until false
</syntaxhighlight>
 
=={{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 2,809 ⟶ 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}}==
<syntaxhighlight lang="matlab">function forest_fire(f,p,N,M)
% Forest fire
if nargin<4;
M=200;
end
if nargin<3;
N=200;
end
if nargin<2;
p=.03;
end
if nargin<1;
f=p*.0001;
end
 
% initialize;
F = (rand(M,N) < p)+1; % tree with probability p
S = ones(3); S(2,2)=0; % surrounding
 
textmap = ' T#';
colormap([.5,.5,.5;0,1,0;1,0,0]);
while(1)
image(F); pause(.1) % uncomment for graphical output
% disp(textmap(F)); pause; % uncomment for textual output
G = ((F==1).*((rand(M,N)<p)+1)); % grow tree
G = G + (F==2) .* ((filter2(S,F==3)>0) + (rand(M,N)<f) + 2); % burn tree if neighbor is burning or by chance f
G = G + (F==3); % empty after burn
F = G;
end; </syntaxhighlight>
 
=={{header|Nim}}==
{{trans|C}}
<syntaxhighlight lang="nim">import random, os, sequtils, strutils
 
randomize()
 
type State {.pure.} = enum Empty, Tree, Fire
 
const
Disp: array[State, string] = [" ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
TreeProb = 0.01
BurnProb = 0.001
 
proc chance(prob: float): bool {.inline.} = rand(1.0) < prob
 
# Set the size
var w, h: int
if paramCount() >= 2:
w = paramStr(1).parseInt
h = 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
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)
 
# Initialize
var univ, univNew = newSeqWith(h, newSeq[State](w))
 
while true:
 
# Show.
stdout.write "\e[H"
for y, x in fields():
stdout.write Disp[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): 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
break
if chance(BurnProb): univNew[y][x] = Fire
univ = univNew
sleep 200</syntaxhighlight>
 
=={{header|OCaml}}==
Line 2,817 ⟶ 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 2,889 ⟶ 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}}==
<syntaxhighlight lang="parigp">step(M,p,f)={
my(m=matsize(M)[1],n=matsize(M)[2]);
matrix(m,n,i,j,
if(M[i,j]=="*",
" "
,
if(M[i,j]=="t",
my(nbr="t");
for(x=max(1,i-1),min(m,i+1),
for(y=max(1,j-1),min(n,j+1),
if(M[x,y]=="*",nbr="*";break(2))
)
);
if(random(1.)<f,"*",nbr)
,
if(random(1.)<p,"t"," ")
)
)
)
};
burn(n,p,f)={
my(M=matrix(n,n,i,j,if(random(2)," ","t")),N);
while(1,print(M=step(M,p,f)))
};
burn(5,.1,.03)</syntaxhighlight>
 
=={{header|Perl}}==
Requires terminal that understands ANSI escape sequences:<langsyntaxhighlight Perllang="perl">
use 5.10.0;
 
Line 2,958 ⟶ 6,042:
}
 
forest while (1);</langsyntaxhighlight>
 
=={{header|=Alternate Perl 6}}Solution===
<syntaxhighlight lang="perl">use strict;
<lang perl6>my $RED = "\e[1;31m";
use warnings;
my $CLEAR = "\e[0m";
use feature 'bitwise';
 
my $p = 0.01; # probability of empty -> tree
my $f = 0.0001; # probability of tree -> burning
 
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 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 @show = (' ', '木', $RED ~ '木' ~ $CLEAR);
<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 Cell-State @!grid;
has @!neighbors;
has Int $.height;
has Int $.width;
has $.p;
has $.f;
<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 new(Int $height, Int $width, $p=0.01, $f=0.001) {
my $c = self.bless(*, :$height, :$width, :$p, :$f);
$c!init-grid;
$c!init-neighbors;
return $c;
}
<span style="color: #008080;">function</span> <span style="color: #000000;">randomf</span><span style="color: #0000FF;">()</span>
method !init-grid {
<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>
@!grid = [ (Bool.pick ?? Tree !! Empty) xx $!width ] xx $!height;
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
}
<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 !init-neighbors {
<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 X ^$!width -> $i, $j {
<span style="color: #000080;font-style:italic;">-- limit to 40K cells, otherwise it gets too slow.
@!neighbors[$i][$j] = gather for
-- n here is the cell size [-1,-1],[+0,-1],[+1,-1],in pixels (min of 1x1)
-- Note you still get some setTimeout [-1,+0],( violations ),[+1,+0],
-- in js even with the limit [-1,+1],[+0,+1],[+1,+1]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>
take-rw @!grid[$i + .[0]][$j + .[1]] // next;
<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>
}
}
}
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
method step {
<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>
my @new;
<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>
for ^$!height X ^$!width -> $i, $j {
<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>
given @!grid[$i][$j] {
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
when Empty { @new[$i][$j] = rand < $!p ?? Tree !! Empty }
<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>
when Tree { @new[$i][$j] =
<span style="color: #000080;font-style:italic;">--
(@!neighbors[$i][$j].any === Burning or rand < $!f) ?? Burning !! Tree;
-- There is a "dead border" of 1 cell all around the edge of f (& fn) which
}
-- we never display or update. If we have got this right/an exact fit, then
when Burning { @new[$i][$j] = Empty }
-- 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.
--</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>
<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>
<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>
<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>
<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>
<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>
<span style="color: #008080;">case</span> <span style="color: #000000;">TREE</span><span style="color: #0000FF;">:</span>
<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>
<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>
<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>
<span style="color: #008080;">case</span> <span style="color: #000000;">FIRE</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: #008080;">end</span> <span style="color: #008080;">switch</span>
<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>
<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>
<span style="color: #000000;">cy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">n</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<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>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fn</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<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>
<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>
<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>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<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>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<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>
<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>
<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>
<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>
<span style="color: #000080;font-style:italic;">-- (above MINSIZE prevents the title from getting squished)</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<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>
<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>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PHP}}==
<syntaxhighlight lang="php"><?php
 
define('WIDTH', 10);
define('HEIGHT', 10);
 
define('GEN_CNT', 10);
define('PAUSE', 250000);
 
define('TREE_PROB', 50);
define('GROW_PROB', 5);
define('FIRE_PROB', 1);
 
define('BARE', ' ');
define('TREE', 'A');
define('BURN', '/');
 
 
$forest = makeNewForest();
 
for ($i = 0; $i < GEN_CNT; $i++) {
displayForest($forest, $i);
$forest = getNextForest($forest);
}
 
displayForest($forest, 'done');
exit;
 
 
function makeNewForest() {
return mapForest([
'func' => function(){
return isProb(TREE_PROB) ? TREE : BARE;
}
]);
}
 
 
function displayForest($forest, $generationNum) {
system("clear");
echo PHP_EOL . "Generation: $generationNum" . PHP_EOL;
mapForest(['forest' => $forest, 'func' => function($f, $x, $y){
echo $f[$y][$x] . ($x == WIDTH - 1 ? PHP_EOL : '');
}
]);
echo PHP_EOL;
usleep(PAUSE);
}
 
 
function getNextForest($oldForest) {
return mapForest(['forest' => $oldForest, 'func' => function($f, $x, $y){
switch ($f[$y][$x]) {
case BURN:
return BARE;
case BARE:
return isProb(GROW_PROB) ? TREE : BARE;
case TREE:
$caughtFire = isProb(FIRE_PROB);
$ablaze = $caughtFire ? true : getNumBurningNeighbors($f, $x, $y) > 0;
return $ablaze ? BURN : TREE;
}
}
]);
for ^$!height X ^$!width -> $i, $j {
}
@!grid[$i][$j] = @new[$i][$j];
 
 
function getNumBurningNeighbors($forest, $x, $y) {
$burningNeighbors = mapForest([
'forest' => $forest,
'x1' => $x - 1, 'x2' => $x + 2,
'y1' => $y - 1, 'y2' => $y + 2,
'default' => 0,
'func' => function($f, $x, $y){
return $f[$y][$x] == BURN ? 1 : 0;
}
]);
$numOnFire = 0;
foreach ($burningNeighbors as $row) {
$numOnFire += array_sum($row);
}
return $numOnFire;
}
method Str {
 
join '', gather for ^$!height -> $i {
 
take @show[@!grid[$i].list], "\n";
function mapForest($params) {
$p = array_merge([
'forest' => [],
'func' => function(){echo "default\n";},
'x1' => 0,
'x2' => WIDTH,
'y1' => 0,
'y2' => HEIGHT,
'default' => BARE
], $params);
$newForest = [];
for ($y = $p['y1']; $y < $p['y2']; $y++) {
$newRow = [];
for ($x = $p['x1']; $x < $p['x2']; $x++) {
$inBounds = ($x >= 0 && $x < WIDTH && $y >= 0 && $y < HEIGHT);
$newRow[] = ($inBounds ? $p['func']($p['forest'], $x, $y) : $p['default']);
}
$newForest[] = $newRow;
}
return $newForest;
}
 
 
my Forest $f .= new(20,30);
function isProb($prob) {
print "\e[2J"; # ANSI clear screen
return rand(0, 100) < $prob;
}
my $i = 0;
</syntaxhighlight>
loop {
print "\e[H"; # ANSI home
say $i++;
say $f.Str;
$f.step;
}</lang>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(load "@lib/simul.l")
 
(scl 3)
Line 3,075 ⟶ 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 3,143 ⟶ 6,407:
 
1000 { drawforest showpage iter } repeat
%%EOF</langsyntaxhighlight>
 
=={{header|PureBasic}}==
<lang 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().
; If experiencing this problem, please reduce the #Width & #Height
; or activate the parameter #UnLoadCPU below with a parameter 1 or 2.
;
; This code should work with the demo version of PureBasic on both PC & Linux
 
; General parameters for the world
#f = 1e-6
#p = 1e-2
#SeedATree = 0.005
#Width = 400
#Height = 400
 
; Setting up colours
#Fire = $080CF7
#BackGround = $BFD5D3
#YoungTree = $00E300
#NormalTree = $00AC00
#MatureTree = $009500
#OldTree = $007600
#Black = $000000
 
; Depending on your hardware, use this to control the speed/CPU-load.
; 0 = No load reduction
; 1 = Only active about every second frame
; 2 = '1' & release the CPU after each horizontal line.
#UnLoadCPU = 0
 
Enumeration
#Empty =0
#Ignited
#Burning
#Tree
#Old=#Tree+20
EndEnumeration
 
Global Dim Forest.i(#Width, #Height)
Global Title$="Forest fire in PureBasic"
Global Cnt
 
Macro Rnd()
(Random(2147483647)/2147483647.0)
EndMacro
 
Procedure Limit(n, min, max)
If n<min
n=min
ElseIf n>max
n=max
EndIf
ProcedureReturn n
EndProcedure
 
Procedure SpreadFire(x,y)
Protected cnt=0, i, j
For i=Limit(x-1, 0, #Width) To Limit(x+1, 0, #Width)
For j=Limit(y-1, 0, #Height) To Limit(y+1, 0, #Height)
If Forest(i,j)>=#Tree
Forest(i,j)=#Ignited
EndIf
Next
Next
EndProcedure
 
Procedure InitMap()
Protected x, y, type
For y=1 To #Height
For x=1 To #Width
If Rnd()<=#SeedATree
type=#Tree
Else
type=#Empty
EndIf
Forest(x,y)=type
Next
Next
EndProcedure
 
Procedure UpdateMap()
Protected x, y
For y=1 To #Height
For x=1 To #Width
Select Forest(x,y)
Case #Burning
Forest(x,y)=#Empty
SpreadFire(x,y)
Case #Ignited
Forest(x,y)=#Burning
Case #Empty
If Rnd()<=#p
Forest(x,y)=#Tree
EndIf
Default
If Rnd()<=#f
Forest(x,y)=#Burning
Else
Forest(x,y)+1
EndIf
EndSelect
Next
Next
EndProcedure
 
Procedure PresentMap()
Protected x, y, c
cnt+1
SetWindowTitle(0,Title$+", time frame="+Str(cnt))
StartDrawing(ImageOutput(1))
For y=0 To OutputHeight()-1
For x=0 To OutputWidth()-1
Select Forest(x,y)
Case #Empty
c=#BackGround
Case #Burning, #Ignited
c=#Fire
Default
If Forest(x,y)<#Tree+#Old
c=#YoungTree
ElseIf Forest(x,y)<#Tree+2*#Old
c=#NormalTree
ElseIf Forest(x,y)<#Tree+3*#Old
c=#MatureTree
ElseIf Forest(x,y)<#Tree+4*#Old
c=#OldTree
Else ; Tree died of old age
Forest(x,y)=#Empty
c=#Black
EndIf
EndSelect
Plot(x,y,c)
Next
CompilerIf #UnLoadCPU>1
Delay(1)
CompilerEndIf
Next
StopDrawing()
ImageGadget(1, 0, 0, #Width, #Height, ImageID(1))
EndProcedure
 
If OpenWindow(0, 10, 30, #Width, #Height, Title$, #PB_Window_MinimizeGadget)
SmartWindowRefresh(0, 1)
If CreateImage(1, #Width, #Height)
Define Event, freq
If ExamineDesktops() And DesktopFrequency(0)
freq=DesktopFrequency(0)
Else
freq=60
EndIf
AddWindowTimer(0,0,5000/freq)
InitMap()
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
End
Case #PB_Event_Timer
CompilerIf #UnLoadCPU>0
Delay(25)
CompilerEndIf
UpdateMap()
PresentMap()
EndSelect
ForEver
EndIf
EndIf</lang>
[[Image:Forest_Fire_in_PureBasic,_frame_300.png]]
 
=={{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 3,400 ⟶ 6,494:
break
grid = gnew(grid)
iter +=1</langsyntaxhighlight>
 
'''Sample output'''
Line 3,459 ⟶ 6,553:
Print/Quit/<int>/<return> 4: </pre>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(require 2htdp/universe)
(require 2htdp/image)
Line 3,519 ⟶ 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|REALbasicRaku}}==
(formerly Perl 6)
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:
<lang realbasic>
Sub Run()
//Handy named constants
Const empty = 0
Const tree = 1
Const fire = 2
Const ablaze = &cFF0000 //Using the &c numeric operator to indicate a color in hex
Const alive = &c00FF00
Const dead = &c804040
//Our forest
Dim worldPic As New Picture(480, 480, 32)
Dim newWorld(120, 120) As Integer
Dim oldWorld(120, 120) As Integer
//Initialize forest
Dim rand As New Random
For x as Integer = 0 to 119
For y as Integer = 0 to 119
if rand.InRange(0, 2) = 0 Or x = 119 or y = 119 or x = 0 or y = 0 Then
newWorld(x, y) = empty
worldPic.Graphics.ForeColor = dead
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
Else
newWorld(x, y) = tree
worldPic.Graphics.ForeColor = alive
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Next
Next
oldWorld = newWorld
//Burn, baby burn!
While Window1.stop = False
For x as Integer = 0 To 119
For y As Integer = 0 to 119
Dim willBurn As Integer = rand.InRange(0, Window1.burnProb.Value)
Dim willGrow As Integer = rand.InRange(0, Window1.growProb.Value)
if x = 119 or y = 119 or x = 0 or y = 0 Then
Continue
end if
Select Case oldWorld(x, y)
Case empty
If willGrow = (Window1.growProb.Value) Then
newWorld(x, y) = tree
worldPic.Graphics.ForeColor = alive
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Case tree
if oldWorld(x - 1, y) = fire Or oldWorld(x, y - 1) = fire Or oldWorld(x + 1, y) = fire Or oldWorld(x, y + 1) = fire Or oldWorld(x + 1, y + 1) = fire Or oldWorld(x - 1, y - 1) = fire Or oldWorld(x - 1, y + 1) = fire Or oldWorld(x + 1, y - 1) = fire Or willBurn = (Window1.burnProb.Value) Then
newWorld(x, y) = fire
worldPic.Graphics.ForeColor = ablaze
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
end if
Case fire
newWorld(x, y) = empty
worldPic.Graphics.ForeColor = dead
worldPic.Graphics.FillRect(x*4, y*4, 4, 4)
End Select
Next
Next
Window1.Canvas1.Graphics.DrawPicture(worldPic, 0, 0)
oldWorld = newWorld
me.Sleep(Window1.speed.Value)
Wend
End Sub
</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.
<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.
Dim fire As New forestFire
fire.Run()
End Sub
 
===ANSI graphics===
stop As Boolean //a globally accessible property of Window1. Boolean properties default to False.
{{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) {
Sub Pushbutton1.Action()
@!coords = ^$!height X ^$!width;
stop = True
@!spot = [ (Bool.pick ?? Tree !! Empty) xx $!width ] xx $!height;
End Sub
self!init-neighbors;
</lang>
}
[[Image:ForestFireRB.PNG]]
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}}==
This version has been elided, &nbsp; otherwise the size of the program (with all it's options and optional formatting) would
<br>probably be on the big side for general viewing, and maybe a wee bit complex to demonstrate how to program for this task.
<br><br>If repeatable results are desired, the RANDSEED variable can be set to a positive integer.
<br><br>Glyphs were chosen in an attempt to pictorialize a tree (↑) and also a fire (▒).
<br>The choice of glyphs within the DOS code page (under Windoes) is rather limited.
<br><br>There are two dependencies: the '''LINESIZE''' function is used (some REXXes don't have it), and the RYO
<br>version that I wrote was wasn't included here. Also, the '''CLS''' (DOS) command is used to clear the screen.
<lang rexx>/*REXX program grows and displays a forest (with growth and lightning).
┌───────────────────────────elided version─────────────────────────┐
├─── full version has many more options and enhanced displays. ────┤
└──────────────────────────────────────────────────────────────────┘ */
signal on syntax; signal on novalue /*handle REXX program errors. */
signal on halt /*handle cell growth interruptus.*/
parse arg peeps '(' generations rows cols bare! life! clearscreen every
@abc='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc; upper @abcU
blank = 'BLANK'
generations = p(generations 100)
rows = p(rows 3)
cols = p(cols 3)
bare! = pickchar(bare! blank)
clearscreen = p(clearscreen 0)
every = p(every 999999999)
life! = pickchar(life! '☼')
fents=max(79,cols) /*fence width shown after display*/
$.=bare! /*the universe is new, and barren*/
gens=abs(generations) /*use this for convenience. */
x=space(peeps) /*remove superfluous spaces. */
if x=='' then x='2,1 2,2 2,3'
 
If repeatable results are desired, the &nbsp; '''randSeed''' &nbsp; variable can be set to a non-negative integer.
do while x \==''
parse var x p x; parse var p r ',' c .; $.r=overlay(life!,$.r,c+1)
end
life=0; !.=0; call showCells /*show initial state of the cells*/
/*─────────────────────────────────────watch cell colony grow/live/die. */
do life=1 for gens
do r=1 for rows; rank=bare!
do c=2 for cols; ?=substr($.r,c,1); ??=?; n=neighbors()
select /*select da quickest choice first*/
when ?==bare! then if n==3 then ??=life!
otherwise if n<2 | n>3 then ??=bare!
end /*select*/
rank=rank || ??
end /*c*/
@.r=rank
end /*c*/
 
Glyphs were chosen in an attempt to pictorialize a tree &nbsp; (<big>↑</big>) &nbsp; and also a fire &nbsp; (<big>▒</big>).
do r=1 for rows; $.r=@.r; end /*assign alternate cells ──► real*/
 
if life//every==0 | generations>0 | life==gens then call showCells
The choice of glyphs within the code page '''437''' &nbsp; (DOS and/or under Windows) is rather limited.
end /*life*/
 
/*─────────────────────────────────────stop watching the universe (life)*/
There is one (OS) dependency: &nbsp; use of the &nbsp; '''CLS''' &nbsp; (DOS) command which is used to clear the screen &nbsp; (the original
halt: cycles=life-1; if cycles\==gens then say 'REXX program interrupted.'
<br>version examined the host environment and used the correct command to clear the terminal screen).
exit /*stick a fork in it, we're done.*/
<pre>
/*───────────────────────────────SHOWCELLS subroutine─-─────────────────*/
┌───────────────────────────elided version──────────────────────────┐
showCells: if clearscreen then 'CLS' /* ◄─── change this for your OS.*/
├─── original version has many more options & enhanced displays. ───┤
_=; do r=rows by -1 for rows /*show the forest in proper order*/
└───────────────────────────────────────────────────────────────────┘
z=strip(substr($.r,2),'T') /*pick off the meat of the row. */
</pre>
say z; _=_ || z /*be neat about trailing blanks. */
<syntaxhighlight lang="rexx">/*REXX program grows and displays a forest (with growth and fires caused by lightning).*/
end /*r*/
parse value scrSize() with sd sw . /*the size of the terminal display. */
say right(copies('═',fents)life,fents) /*show&tell for a stand of trees.*/
parse arg generations birth lightning rSeed . /*obtain the optional arguments from CL*/
if _=='' then exit /*if no life, then stop the run. */
if datatype(rSeed,'W') then call random ,,rSeed /*do we want RANDOM BIF repeatability?*/
if !._ then do; say 'repeating ...'; exit; end
!._generations =1 p(generations 100) /*assignmaybe ause state &one comparehundred later generations. */
birth = p(strip(birth , ,'%') 50 ) *100 /*calculate the percentage for births. */
return
lightning = p(strip(lightning, ,'%') 1/8) *100 /* " " " " lightning*/
/*───────────────────────────────NEIGHBORS subroutine───────────────────*/
bare! = ' ' /*the glyph used to show a bare place. */
neighbors: rp=r+1; cp=c+1; rm=r-1; cm=c-1 /*count 8 neighbors of a cell*/
fire! = '▒' /*glyph is close to a conflagration. */
return (substr($.rm,cm,1)==life!) + (substr($.rm,c ,1)==life!) + ,
tree! = '↑' /*this is an up─arrow [↑] glyph (tree).*/
(substr($.rm,cp,1)==life!) + (substr($.r ,cm,1)==life!) + ,
rows = max(12, sd-2) /*shrink the usable screen rows by two.*/
(substr($.r ,cp,1)==life!) + (substr($.rp,cm,1)==life!) + ,
cols = max(79, sw-1) /* " " " " cols " one.*/
(substr($.rp,c ,1)==life!) + (substr($.rp,cp,1)==life!)
every = 999999999 /*shows a snapshot every Nth generation*/
/*───────────────────────────────1-liner subroutines────────────────────*/
field = min(100000, rows*cols) /*the size of the forest area (field). */
err: say;say;say center(' error! ',max(40,linesize()%2),"*");say;do j=1 for arg();say arg(j);say;end;say;exit 13
$.=bare! /*forest: it is now a treeless field. */
novalue: syntax: call err 'REXX program' condition('C') "error",condition('D'),'REXX source statement (line' sigl"):",sourceline(sigl)
@.=$. /*ditto, for the "shadow" forest. */
pickchar: _=p(arg(1));if translate(_)==blank then _=' ';if length(_) ==3 then _=d2c(_);if length(_) ==2 then _=x2c(_);return _
gens=abs(generations) /*use this for convenience. */
p: return word(arg(1),1)</lang>
signal on halt /*handle any forest life interruptus. */
'''output''' when using the defaults of:
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒observe the forest grow and/or burn. */
* generations = 100
do life=1 for gens /*simulate a forest's life cycle. */
* rows = 39
do r=1 for rows; rank=bare! /*start a forest rank as being bare. */
* columns = 79 (one less than the window size)
do c=2 for cols; ?=substr($.r, c, 1); ??=?
* lightning rate = ½%
select /*select the most likeliest choice 1st.*/
* new growth rate = 6%
when ?==tree! then if ignite?() then ??=fire! /*on fire ? */
* bare character = blank
when ?==bare! then if random(1, field)<=birth then ??=tree! /*new growth.*/
* fire character = ▒
otherwise ??=bare! /*it's barren*/
* tree character = ↑
end /*select*/ /* [↑] when (↑) if ≡ short circuit.*/
<br>This is the 7th generation (out of 100).
rank=rank || ?? /*build rank: 1 forest "row" at a time*/
<pre style="overflow:scroll">
end /*c*/ /*ignore column one, start with col two*/
@.r=rank /*and assign rank to alternate forest. */
end /*r*/ /* [↓] ··· and, later, yet back again.*/
 
do r=1 for rows; $.r=@.r; end /*r*/ /*assign alternate cells ──► real cells*/
if \(life//every==0 | generations>0 | life==gens) then iterate
'CLS' /* ◄─── change this command for your OS*/
do r=rows by -1 for rows; say strip(substr($.r, 2), 'T') /*a row of trees*/
end /*r*/ /* [↑] display forest to the terminal.*/
say right(copies('▒', cols)life, cols) /*show and tell for a stand of trees. */
end /*life*/
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒stop observing the forest evolve. */
halt: if life-1\==gens then say 'Forest simulation interrupted.' /*was this pgm HALTed?*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
ignite?: if substr($.r, c+1, 1) == fire! then return 1 /*is east on fire? */
cm=c-1; if substr($.r, cm , 1) == fire! then return 1 /* " west " " */
rm=r-1; rp=r+1 /*test north & south*/
if pos(fire!, substr($.rm, cm, 3)substr($.rp, cm, 3)) \== 0 then return 1
return random(1, field) <= lightning /*lightning ignition*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
p: return word(arg(1), 1) /*pick─a─word: first or second word.*/</syntaxhighlight>
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>
'''output''' &nbsp; when using the defaults of:
::::* &nbsp; generations = 100
::::* &nbsp; rows = 48
::::* &nbsp; lightning rate = 12.5%
::::* &nbsp; new growth rate = 50%
::::* &nbsp; bare character = (a true blank)
::::* &nbsp; fire character = ▒
::::* &nbsp; tree character = <big>↑</big>
<br>Shown below is the 10<sup>th</sup> generation &nbsp; (out of 100).
<pre>
↑↑↑↑↑↑↑↑▒▒▒▒▒▒▒▒▒ ↑↑↑↑↑↑ ▒↑↑↑↑▒ ▒↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑▒ ▒↑↑↑↑↑↑↑↑↑↑↑↑↑▒▒▒↑↑↑
↑↑↑↑↑↑↑↑▒ ↑↑↑↑↑↑↑ ▒↑↑↑↑▒ ↑↑ ▒↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑▒ ↑ ▒↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Line 3,744 ⟶ 6,957:
</pre>
 
=={{header|RubyRing}}==
<syntaxhighlight lang="ring">
<lang ruby>require 'enumerator'
# Project : Forest fire
 
load "guilib.ring"
def transition arr, tree_prob, fire_prob
load "stdlib.ring"
arr.enum_with_index.map do |cell, i|
 
if i == 0 or i == arr.length - 1
paint = null
# boundary conditions: cells are always empty here
 
:empty
new qapp
else
case cell {
when :fire win1 = new qwidget() {
setwindowtitle("Forest fire")
# burning cells become empty
setgeometry(100,100,500,600)
:empty
label1 = new qlabel(win1) {
when :empty
setgeometry(10,10,400,400)
# empty cells grow a tree with probability tree_prob
rand < tree_prob ? :tree : :empty settext("")
when :tree }
# check my neighbouring cells, are they on fire? new qpushbutton(win1) {
if arr[i - 1] == :fire or arr[i + 1] == :fire setgeometry(150,500,100,30)
:fire settext("draw")
setclickevent("draw()")
}
show()
}
exec()
}
 
func draw
p1 = new qpicture()
color = new qcolor() {
setrgb(0,0,255,255)
}
pen = new qpen() {
setcolor(color)
setwidth(1)
}
paint = new qpainter() {
begin(p1)
setpen(pen)
 
pregen = newlist(200,200)
newgen = newlist(200,200)
for gen = 1 to 20
see "gen = " + gen + nl
for x = 1 to 199
for y = 1 to 199
switch pregen[x][y]
on 0
if random(9)/10 > 0.099
newgen[x][y] = 1
color = new qcolor()
color.setrgb(0,128,0,255)
pen.setcolor(color)
setpen(pen)
drawpoint(x,y)
ok
on 2
newgen[x][y] = 0
color = new qcolor()
color.setrgb(165,42,42,255)
pen.setcolor(color)
setpen(pen)
drawpoint(x,y)
on 1
if pregen[x][y] = 2 or pregen[x][y] = 2 or pregen[x][y+1] = 2 or
pregen[x][y] = 2 or pregen[x][y+1] = 2 or pregen[x+1][y] = 2 or
pregen[x+1][y] = 2 or pregen[x+1][y+1] = 2 or random(9)/10 > 0.0999
color = new qcolor()
color.setrgb(255,0,0,255)
pen.setcolor(color)
setpen(pen)
drawpoint(x,y)
newgen[x][y] = 2
ok
off
pregen[x][y] = newgen[x][y]
next
next
next
 
endpaint()
}
label1 { setpicture(p1) show() }
return
</syntaxhighlight>
Output:
 
https://www.dropbox.com/s/6rjho62odzyqaqc/ForestFire.jpg?dl=0
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">class Forest_Fire
Neighborhood = [-1,0,1].product([-1,0,1]) - [0,0]
States = {empty:" ", tree:"T", fire:"#"}
def initialize(xsize, ysize=xsize, p=0.5, f=0.01)
@xsize, @ysize, @p, @f = xsize, ysize, p, f
@field = Array.new(xsize+1) {|i| Array.new(ysize+1, :empty)}
@generation = 0
end
def evolve
@generation += 1
work = @field.map{|row| row.map{|cell| cell}}
for i in 0...@xsize
for j in 0...@ysize
case cell=@field[i][j]
when :empty
cell = :tree if rand < @p
when :tree
cell = :fire if fire?(i,j)
else
cell = :empty
# neighbours not on fire, but catch fire at random
rand < fire_prob ? :fire : :tree
end
work[i][j] = cell
end
end
@field = work
end
def fire?(i,j)
rand < @f or Neighborhood.any? {|di,dj| @field[i+di][j+dj] == :fire}
end
def display
puts "Generation : #@generation"
puts @xsize.times.map{|i| @ysize.times.map{|j| States[@field[i][j]]}.join}
end
end
 
forest = Forest_Fire.new(10,30)
def pretty_print arr
10.times do |i|
# colour the trees green, the fires red, and the empty spaces black
forest.evolve
print(arr.map { |cell|
forest.display
"\e[3" +
end</syntaxhighlight>
case cell
Sample Output:
when :tree
<pre style="height:64ex;overflow:scroll">
"2mT"
Generation : 1
when :fire
TT TTTT TT TT "1mF" T T T TTT
T TTT T when :empty TTT T T T T T
TT T TTT T T "0m "T T TTT T
T TT T end + "\e[0m"T TT TTT T T
TTTT TTTTTTT TT T
}.join)
T T T TT T TTT TT
end
TT TT TTT TT TTT T T
T TTTTT TT TT T TTT TT
T TTT T T T T T TT T
TTTTT T TT TTT TT T T T
Generation : 2
TTTTTTTT TTTT TTTTTTTTT TTTTT
T# TTTTTTTTT TTTTTT T T T TT
TT # TTTTT T T TTTTTTTTTT TT
T TTTTT T TT TTTTTT TTT TTT
TTTTTTT TTTTTTTT T TTT TTT
TTTT T TTT TTT TT TTTTTTT
TT TT TTTT TTT TTTT TTTT TT T
T T TTTTTT TTTTTTT T TTTTTTTTT
TTTTT TTTTTT T T T TT TTTT TT
TTTTTTT TTTTT TTTTTT T T TT
Generation : 3
###TTTTT TTTT TTTTTTTTTTTTTTTT
# T####TTTTT TTTTTT TTTTTT TT
##TT TTTTTTT TTTTTTTTTTTT TT
TT T###T T TTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTT TTTTTTTTT
TTTTT T TTTTTTT TTTT TTTTTTT
TT TTTTTTT TTT TTTT TTTTTTT T
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
TTTTT TTTTTT T TTTTTTTT#TTTTT
TTTTTTTT TTTTTT#TTTTT TTTT TT
Generation : 4
##### TTTT TTTTTTTTTTTTTTTT
T # #TTTT TTTTTTTTTTTTT TT
## ##TTTTTTTTTTTTTTTTTTTTT
## # # T TTTTTTTTTTTTTTTTTTT
TTT#####TTTTTTTTTTTT TTTTTTTTT
TTTTTTT TTTTTTTTTTTTT TTTTTTTT
TTTTTTTTTTTTTTTTTTT TTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTT###TTTT
TTTTTTTTTTTTTTTT##TTTTT# #TTTT
TTTTTTTT TTTTT# #TTTT ###TTTT
Generation : 5
T#TTTTTTTTTTTTTTTTTTTT
#T TTTT #TTT TTTTTTTTTTTTT TT
T T #TTTTTTTTTTTTTTTTTTTT
T #TTTTT#TTTTTT#TTTTTTT
### #TTTTTTTTTTT TTTTTTTTT
TT##### #TTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTT#####TTT
TTTTTTTTTTTTTTT####TTT# #TTT
TTTTTTTTTTTTTT## #TTT# T #TTT
TTTTTTTT TTTT# T #TTT #TTT
Generation : 6
T T # ##TTTTTTTTTTTTTTTTTT
T #TTTTT #TT TTTTTTTTTTTTT TT
T#TT TTT #TTT###TTTT###TTTTTT
TTTTTT T #TTT# #TTTT# #TTTTTT
TTT ##TTT###TTTT###TTTTTT
## #TTTTTTTTTTT#######TT
T#########TTT#######T# #TT
TTTTTTTTTTTTT## #T# T #TT
TTTTTTTTTTTTT# TT #T# TTT #TT
TTTTTTTT TTT# #T #T#T #TT
Generation : 7
TT # T T #TTTTTTTTTTTTTTTTT
#T #TTT# T ## ####TT#####TTTTT
# ##TTTTTT #T# #TT# #TTTTT
###TTTTT# #T# T #TT# T #TTTTT
TTTT T #T# #TT# #####T
T TTT T ########### #T
# #T# # T TTT #T
###########T# TT # T #T
TTTTTTTTTTTT# TT##T # TTT #T
TTTTTT#T TTT# #T # #T TT #T
Generation : 8
## TT T #############TTTT
# #T# TT T ## #TTTT
T #T#### # T ## T #TTTT
##TT# T # TT ## TTT #####
T#TTTT#TT # TT ## TT #
T T TTTTT TTT T #
TT TTTT # TTT T T TTT #
# ##T TTTT T #
############ T# #T #TTTT #
TTTTT# #TTT# TT #T T # TT #
Generation : 9
TT##T TTT #TTT
T TT # ##TTT#T TTT #TTT
#T # T TTT TTT ####
T ## T#T TTTT TTTT
TT# #### #T TT TTT T T T
T # #TT## T TTT T TTT TT T
TTT TTTTT T T## #T T TTT
TT T TT #TTT###TTT
T# T #TT #TTTT
##### ### T#T # TT TTT
Generation : 10
T# # T##T TTTT TTT #TT
#T##T #T# #TTTTT TTT ###
T # T TTTT#T TTTT TTTTTTT
# T T # #T TTTT TTTTT
T# T T #TT TTT TT# TTT T
T ## #TT ###T#TTTTTTTTTT
T### #####TTTT# T #T # ##T TT
TTTTTTTTTT#TTT ### #TT
TTTT TTTT T # TT T ## T #TTT
T # # TT TT ##TTT
</pre>
 
=={{header|Rust}}==
N = 20 # 20 trees
Inspired by the Raku 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.
P = 0.5 # probability of growing a tree
{{libheader|rand}}
F = 0.1 # probability of catching on fire
{{libheader|ansi_term}}
<syntaxhighlight lang="rust">extern crate rand;
extern crate ansi_term;
 
#[derive(Copy, Clone, PartialEq)]
srand Time.now.to_i
enum Tile {
Empty,
Tree,
Burning,
Heating,
}
 
impl fmt::Display for Tile {
# each cell has a 50/50 chance of being a tree
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
array = (1..N).map { rand < 0.5 ? :tree : :empty }
let output = match *self {
array[0] = array[-1] = :empty # boundary conditions
Empty => Black.paint(" "),
pretty_print array
Tree => Green.bold().paint("T"),
puts
Burning => Red.bold().paint("B"),
Heating => Yellow.bold().paint("T"),
};
write!(f, "{}", output)
}
}
 
// This has been added to the nightly rust build as of March 24, 2016
begin
// Remove when in stable branch!
array = transition(array, P, F)
trait Contains<T> {
fn contains(&self, T) -> bool;
}
 
impl<T: PartialOrd> Contains<T> for std::ops::Range<T> {
pretty_print array
fn contains(&self, elt: T) -> bool {
end while gets.chomp.downcase != "q"</lang>Sample Output:
self.start <= elt && elt < self.end
[[File:Ruby-Forest-Fire.png]]
}
}
 
const NEW_TREE_PROB: f32 = 0.01;
=={{header|Run BASIC}}==
const INITIAL_TREE_PROB: f32 = 0.5;
<lang runbasic>graphic #g, 200,200
const FIRE_PROB: f32 = 0.001;
dim preGen(200,200)
dim newGen(200,200)
 
const FOREST_WIDTH: usize = 60;
for gen = 1 to 200
const FOREST_HEIGHT: usize = 30;
for x = 1 to 199
 
for y = 1 to 199
const SLEEP_MILLIS: u64 = 25;
select case preGen(x,y)
 
case 0
use std::fmt;
if rnd(0) > .99 then newGen(x,y) = 1 : #g "color green ; set "; x; " "; y
use std::io;
case 2
use std::io::prelude::*;
newGen(x,y) = 0 : #g "color brown ; set "; x; " "; y
use std::io::BufWriter;
case 1
use std::io::Stdout;
if preGen(x-1,y-1) = 2 or preGen(x-1,y) = 2 or preGen(x-1,y+1) = 2 _
use std::process::Command;
or preGen(x,y-1) = 2 or preGen(x,y+1) = 2 or preGen(x+1,y-1) = 2 _
use std::time::Duration;
or preGen(x+1,y) = 2 or preGen(x+1,y+1) = 2 or rnd(0) > .999 then
use rand::Rng;
#g "color red ; set "; x; " "; y
use ansi_term::Colour::*;
newGen(x,y) = 2
 
end if
use Tile::{Empty, Tree, Burning, Heating};
end select
 
preGen(x-1,y-1) = newGen(x-1,y-1)
fn main() {
next y
let sleep_duration = Duration::from_millis(SLEEP_MILLIS);
next x
let mut forest = [[Tile::Empty; FOREST_WIDTH]; FOREST_HEIGHT];
next gen
 
render #g</lang>
prepopulate_forest(&mut forest);
[[File:ForestFire.png]]
print_forest(forest, 0);
 
std::thread::sleep(sleep_duration);
 
for generation in 1.. {
 
for row in forest.iter_mut() {
for tile in row.iter_mut() {
update_tile(tile);
}
}
 
for y in 0..FOREST_HEIGHT {
for x in 0..FOREST_WIDTH {
if forest[y][x] == Burning {
heat_neighbors(&mut forest, y, x);
}
}
}
 
print_forest(forest, generation);
 
std::thread::sleep(sleep_duration);
}
}
 
fn prepopulate_forest(forest: &mut [[Tile; FOREST_WIDTH]; FOREST_HEIGHT]) {
for row in forest.iter_mut() {
for tile in row.iter_mut() {
*tile = if prob_check(INITIAL_TREE_PROB) {
Tree
} else {
Empty
};
}
}
}
 
fn update_tile(tile: &mut Tile) {
*tile = match *tile {
Empty => {
if prob_check(NEW_TREE_PROB) == true {
Tree
} else {
Empty
}
}
Tree => {
if prob_check(FIRE_PROB) == true {
Burning
} else {
Tree
}
}
Burning => Empty,
Heating => Burning,
}
}
 
fn heat_neighbors(forest: &mut [[Tile; FOREST_WIDTH]; FOREST_HEIGHT], y: usize, x: usize) {
let neighbors = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];
 
for &(xoff, yoff) in neighbors.iter() {
let nx: i32 = (x as i32) + xoff;
let ny: i32 = (y as i32) + yoff;
if (0..FOREST_WIDTH as i32).contains(nx) && (0..FOREST_HEIGHT as i32).contains(ny) &&
forest[ny as usize][nx as usize] == Tree {
forest[ny as usize][nx as usize] = Heating
}
}
}
 
fn prob_check(chance: f32) -> bool {
let roll = rand::thread_rng().gen::<f32>();
if chance - roll > 0.0 {
true
} else {
false
}
}
 
fn print_forest(forest: [[Tile; FOREST_WIDTH]; FOREST_HEIGHT], generation: u32) {
let mut writer = BufWriter::new(io::stdout());
clear_screen(&mut writer);
writeln!(writer, "Generation: {}", generation + 1).unwrap();
for row in forest.iter() {
for tree in row.iter() {
write!(writer, "{}", tree).unwrap();
}
writer.write(b"\n").unwrap();
}
}
 
fn clear_screen(writer: &mut BufWriter<Stdout>) {
let output = Command::new("clear").output().unwrap();
write!(writer, "{}", String::from_utf8_lossy(&output.stdout)).unwrap();
}
</syntaxhighlight>
 
=={{header|Sather}}==
<langsyntaxhighlight lang="sather">class FORESTFIRE is
private attr fields:ARRAY{ARRAY{INT}};
private attr swapu:INT;
Line 4,031 ⟶ 7,567:
end;
 
end;</langsyntaxhighlight>
 
=={{header|Scala}}==
<langsyntaxhighlight lang="scala">import scala.util.Random
 
class Forest(matrix:Array[Array[Char]]){
Line 4,061 ⟶ 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 4,071 ⟶ 7,607:
}
}
}</langsyntaxhighlight>
Sample output:
<pre>.T..TTT.TT .T..TTT.TT TT..TTT.TT TT..TTTTTT TT..TTTTTT
Line 4,083 ⟶ 7,619:
.TTT.TTTTT .#TT.TTTTT ..#T.TTTTT ...#.TTTTT .....TTTTT
T.T.TTT.T. TTT.TTT.T. ###.TTT.T. ...TTTT.T. T..##TT.T.</pre>
 
=={{header|Sidef}}==
{{trans|Perl}}
<syntaxhighlight lang="ruby">define w = `tput cols`.to_i-1
define h = `tput lines`.to_i-1
define r = "\033[H"
 
define red = "\033[31m"
define green = "\033[32m"
define yellow = "\033[33m"
 
define chars = [' ', green+'*', yellow+'&', red+'&']
 
define tree_prob = 0.05
define burn_prob = 0.0002
 
enum |Empty, Tree, Heating, Burning|
 
define dirs = [
%n(-1 -1), %n(-1 0), %n(-1 1), %n(0 -1),
%n(0 1), %n(1 -1), %n(1 0), %n(1 1),
]
 
var forest = h.of { w.of { 1.rand < tree_prob ? Tree : Empty } }
 
var range_h = h.range
var range_w = w.range
 
func iterate {
var new = h.of{ w.of(0) }
for i in range_h {
for j in range_w {
given (new[i][j] = forest[i][j]) {
when (Tree) {
1.rand < burn_prob && (new[i][j] = Heating; next)
dirs.each { |pair|
var y = pair[0]+i
range_h.contains(y) || next
var x = pair[1]+j
range_w.contains(x) || next
forest[y][x] == Heating && (new[i][j] = Heating; break)
}
}
when (Heating) { new[i][j] = Burning }
when (Burning) { new[i][j] = Empty }
case (1.rand < tree_prob) { new[i][j] = Tree }
}
}
}
forest = new
}
 
STDOUT.autoflush(true)
 
func init_forest {
print r
forest.each { |row|
print chars[row]
print "\033[E\033[1G"
}
iterate()
}
 
loop { init_forest() }</syntaxhighlight>
 
{{trans|Raku}}
OO approach:
<syntaxhighlight lang="ruby">define RED = "\e[1;31m"
define YELLOW = "\e[1;33m"
define GREEN = "\e[1;32m"
 
define DIRS = [
[-1, -1], [0, -1], [1, -1],
[-1, 0], [1, 0],
[-1, 1], [0, 1], [1, 1],
]
 
enum (Empty, Tree, Heating, Burning)
define pix = [' ', GREEN + "*", YELLOW + "*", RED + "*"]
 
class Forest(p=0.01, f=0.001, height, width) {
 
has coords = []
has spot = []
has neighbors = []
 
method init {
coords = (0..height ~X 0..width)
spot = height.of { width.of { [true, false].pick ? Tree : Empty } }
self.init_neighbors
}
 
method init_neighbors {
for i,j in coords {
neighbors[i][j] = gather {
for dir in DIRS {
take(\(spot[i + dir[0]][j + dir[1]] \\ next))
}
}
}
}
 
method step {
var heat = []
 
for i,j in coords {
given (spot[i][j]) {
when Empty { spot[i][j] = Tree if (1.rand < p) }
when Tree { spot[i][j] = Heating if (1.rand < f) }
when Heating { spot[i][j] = Burning; heat << [i, j] }
when Burning { spot[i][j] = Empty }
}
}
 
for i,j in heat {
neighbors[i][j].each { |ref|
*ref = Heating if (*ref == Tree)
}
}
}
 
method show {
for i in ^height {
say pix[spot[i]]
}
}
}
 
STDOUT.autoflush(true)
var(height, width) = `stty size`.nums.map{.dec}...
 
var forest = Forest(height: height, width: width)
print "\e[2J"
 
loop {
print "\e[H"
forest.show
forest.step
}</syntaxhighlight>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
# Build a grid
Line 4,162 ⟶ 7,837:
printGrid
if {[gets stdin line] < 0} break
}</langsyntaxhighlight>
Sample output:
<pre>
Line 4,211 ⟶ 7,886:
</pre>
 
=={{header|Visual Basic .NETuBasic/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
 
Input "%Chance a tree will burn: ";F ' Enter chance of combustion
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.
Input "%Chance a tree will grow: ";P ' Enter chance of a new tree
 
Proc _CreateForest ' Now create a new forest
<lang VisualBasic.NET>Public Class ForestFire
Private _forest(,) As ForestState
Private _isBuilding As Boolean
Private _bm As Bitmap
Private _gen As Integer
Private _sw As Stopwatch
 
Do
Private Const _treeStart As Double = 0.5
Proc _PrintForest ' Print the current forest
Private Const _f As Double = 0.00001
Input "Press '1' to continue, '0' to quit: ";A
Private Const _p As Double = 0.001
Proc _BurnForest ' See what happens
Proc _UpdateForest ' Update from buffer
While A ' Until the user has enough
Loop ' and answers with zero
 
End
Private Const _winWidth As Integer = 300
Private Const _winHeight As Integer = 300
 
Private Enum ForestState
Empty
Burning
Tree
End Enum
 
_CreateForest ' Create an entire new forest
Private Sub ForestFire_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Local(1)
Me.ClientSize = New Size(_winWidth, _winHeight)
ReDim _forest(_winWidth, _winHeight)
 
For a@ = 0 to 120 ' For each main cell determine
Dim rnd As New Random()
If RND(100) < P Then ' if a tree will grow here
For i As Integer = 0 To _winHeight - 1
@(a@) = T For j As Integer = 0 To _winWidth - 1 ' Ok, we got a tree
Else ' Otherwise it remains empty
_forest(j, i) = IIf(rnd.NextDouble <= _treeStart, ForestState.Tree, ForestState.Empty)
@(a@) = NextE
NextEndIf
Next
Return
 
_sw = New Stopwatch
_sw.Start()
DrawForest()
Timer1.Start()
End Sub
 
_BurnForest ' Now the forest starts to burn
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Local(2)
If _isBuilding Then Exit Sub
 
For a@ = 0 To 10 ' Loop vertical
_isBuilding = True
For b@ = 0 To 10 ' Loop horizontal
GetNextGeneration()
If @((a@ * 11) + b@) = B Then @((a@ * 11) + b@ + 121) = E
' A tree has been burned flat
If @((a@ * 11) + b@) = E Then ' For each open space determine
If RND(100) < P Then ' if a tree will grow here
@((a@ * 11) + b@ + 121) = T
Else ' Otherwise it remains an empty space
@((a@ * 11) + b@ + 121) = E
EndIf
EndIf
 
If @((a@ * 11) + b@) = T Then ' A tree grows here
DrawForest()
If RND(100) < F Then ' See if it will spontaneously combust
_isBuilding = False
@((a@ * 11) + b@ + 121) = B
End Sub
Else ' No, then see if it got any burning
@((a@ * 11) + b@ + 121) = FUNC(_BurningTrees(a@, b@))
EndIf ' neighbors that will set it ablaze
EndIf
 
Next
Private Sub GetNextGeneration()
Next
Dim forestCache(_winWidth, _winHeight) As ForestState
Return
Dim rnd As New Random()
 
For i As Integer = 0 To _winHeight - 1
For j As Integer = 0 To _winWidth - 1
Select Case _forest(j, i)
Case ForestState.Tree
If forestCache(j, i) <> ForestState.Burning Then
forestCache(j, i) = IIf(rnd.NextDouble <= _f, ForestState.Burning, ForestState.Tree)
End If
 
_UpdateForest Case ForestState.Burning ' Update the main buffer
Local(1)
For i2 As Integer = i - 1 To i + 1
If i2 = -1 OrElse i2 >= _winHeight Then Continue For
For j2 As Integer = j - 1 To j + 1
If j2 = -1 OrElse i2 >= _winWidth Then Continue For
If _forest(j2, i2) = ForestState.Tree Then forestCache(j2, i2) = ForestState.Burning
Next
Next
forestCache(j, i) = ForestState.Empty
 
For a@ = 0 To 120 Case Else ' Move from temporary buffer to main
@(a@) = @(a@+121)
forestCache(j, i) = IIf(rnd.NextDouble <= _p, ForestState.Tree, ForestState.Empty)
Next
End Select
Return
Next
Next
 
_forest = forestCache
_gen += 1
End Sub
 
_PrintForest ' Print the forest on screen
Private Sub DrawForest()
Local(2)
Dim bmCache As New Bitmap(_winWidth, _winHeight)
Print ' Let's make a little space
 
For a@ = 0 To 10 For i As Integer = 0 To _winHeight' -Loop 1vertical
For b@ = 0 To 10 For j As Integer = 0 To _winWidth' -Loop 1horizontal
If @((a@ * 11) + b@) = B Then Select Case _forest(j,' i)This is a burning tree
Print " Case ForestState.Tree*";
Else bmCache.SetPixel(j, i, Color ' Otherwise..Green)
If @((a@ * 11) + b@) = E Then ' It may be an empty space
Print " ";
Else ' Otherwise
Print " @"; ' It has to be a tree
EndIf
EndIf
Next
Print ' Terminate row
Next
 
Print Case ForestState.Burning ' Terminate map
Return
bmCache.SetPixel(j, i, Color.Red)
End Select
Next
Next
 
_bm = bmCache
Me.Refresh()
End Sub
 
_BurningTrees Param(2) ' Check the trees environment
Private Sub ForestFire_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Local(2)
e.Graphics.DrawImage(_bm, 0, 0)
 
For c@ = a@-1 To a@+1 ' Loop vertical -1/+1
Me.Text = "Gen " & _gen.ToString() & " @ " & (_gen / (_sw.ElapsedMilliseconds / 1000)).ToString("F02") & " FPS: Forest Fire"
If c@ < 0 Then Continue ' Skip top edge
End Sub
Until c@ > 10 ' End at bottom edge
End Class</lang>
For d@ = b@-1 To b@+1 ' Loop horizontal -1/+1
If d@ < 0 Then Continue ' Skip left edge
Until d@ > 10 ' End at right edge
If @((c@ * 11) + d@) = B Then Unloop : Unloop : Return (B)
Next ' We found a burning tree, exit!
Next ' Try next row
 
Return (T) ' No burning trees found</syntaxhighlight>
{{out}}
<pre> @ @ @ @
@ @ @ @ @ @
@ @ @ @
@ @ @
@ @ @ @ @
@
@ @
@ * *
*
* @ @
 
 
Press '1' to continue, '0' to quit: 1
 
@ @ @ @
@ @ @ @ @ @
@ @ @ @
@ @ @
@ @ @ @ @
@ @
* *
* @
@
@ @ @
@
 
Press '1' to continue, '0' to quit: 0
 
0 OK, 0:1236</pre>
 
=={{header|Uiua}}==
{{Works with|Uiua|0.12.0-dev.1}}
[https://www.uiua.org/pad?src=0_12_0-dev_1__UyDihpAgNjAKUHQg4oaQIDAuMDEKUGYg4oaQIDAuMDAwMDUK4oqeKDxQdCDimoLil4zil4wpLuKHoVMKTnMg4oaQIFvCrzFfwq8xIMKvMV8wIMKvMV8xIDBfwq8xIDBfMSAxX8KvMSAxXzAgMV8xXQpOc09uRmlyZSDihpAg4oavU19T4omhKC8rPTLirJow4oqhK05zwqQp4oqZwqTimIcx4oqe4oqfLuKHoVMKW-KNpSjiiLXiqKwoPFB04pqC4peMfOKorCgrMTxQZuKagnwyKT4wfOKLhTAp4p-cTnNPbkZpcmUuKTIwMF0K4oeM4omh4oi14qisKDBfMF8wfDBfMV8wfDFfMF8wKQriiaEo4pa94p-c4omh4pa9MikgIyBVcHNjYWxlCg== Run it in Uiua Pad] (will take a short while to complete).
<syntaxhighlight lang="Uiua">
S ← 60
Pt ← 0.01
Pf ← 0.00005
⊞(<Pt ⚂◌◌).⇡S
Ns ← [¯1_¯1 ¯1_0 ¯1_1 0_¯1 0_1 1_¯1 1_0 1_1]
NsOnFire ← ↯S_S≡(/+=2⬚0⊡+Ns¤)⊙¤☇1⊞⊟.⇡S
[⍥(∵⨬(<Pt⚂◌|⨬(+1<Pf⚂|2)>0|⋅0)⟜NsOnFire.)200]
⇌≡∵⨬(0_0_0|0_1_0|1_0_0)
≡(▽⟜≡▽2) # Upscale
</syntaxhighlight>
{{out}}
[[File:Uiua Forest Fire.png|thumb|center]]
 
=={{header|Vedit macro language}}==
This macro shows an example of using search in columnar block.
Instead of checking all the 8 neighboring cells separately, a search in 3x3 character block is performed to check if there is fire.
 
Note: In order to display the graphics characters correctly, use DOS (OEM) font such as "Terminal".
<syntaxhighlight lang="vedit">#1 = 25 // height of the grid
#2 = 60 // width of the grid
#3 = 2 // probability of random fire, per 1000
#4 = 40 // probability of new tree, per 1000
 
#5 = #2+2+Newline_Chars // total length of a line
#90 = Time_Tick // seed for random number generator
#91 = 1000 // get random numbers in range 0 to 999
 
// Fill the grid and draw border
Buf_Switch(Buf_Free)
Ins_Char('-', COUNT, #2+2)
Ins_Newline
for (#11=0; #11<#1; #11++) {
Ins_Char('|')
for (#12=0; #12<#2; #12++) {
Call("RANDOM")
if (Return_Value < 500) { // 50% propability for a tree
Ins_Char('♠')
} else {
Ins_Char(' ')
}
}
Ins_Char('|')
Ins_Newline
}
Ins_Char('-', COUNT, #2+2)
 
#8=1
Repeat(10) {
BOF
Update()
// calculate one generation
for (#11=1; #11<#1+2; #11++) {
Goto_Line(#11)
for (#12=1; #12<#2+2; #12++) {
Goto_Col(#12)
#14=Cur_Pos
Call("RANDOM")
#10 = Return_Value
if (Cur_Char == '♠') { // tree?
if (#10 < #3) {
Ins_Char('*', OVERWRITE) // random combustion
} else {
if (Search_Block("░", CP-#5-1, CP+#5+2, COLUMN+BEGIN+NOERR)) {
Goto_Pos(#14)
Ins_Char('*', OVERWRITE) // combustion
}
}
} else {
if (Cur_Char == ' ') { // empty space?
if (#10 < #4) {
Ins_Char('+', OVERWRITE) // new tree
}
}
}
}
}
// convert tmp symbols
Replace("░"," ", BEGIN+ALL+NOERR) // old fire goes out
Replace("*","░", BEGIN+ALL+NOERR) // new fire
Replace("+","♠", BEGIN+ALL+NOERR) // new tree
}
Return
 
//--------------------------------------------------------------
// Generate random numbers in range 0 <= Return_Value < #91
// #90 = Seed (0 to 0x7fffffff)
// #91 = Scaling (0 to 0xffff)
 
:RANDOM:
#92 = 0x7fffffff / 48271
#93 = 0x7fffffff % 48271
#90 = (48271 * (#90 % #92) - #93 * (#90 / #92)) & 0x7fffffff
return ((#90 & 0xffff) * #91 / 0x10000)</syntaxhighlight>
 
Sample output, 10th generation:
<pre style="line-height:100%">
--------------------------------------------------------------
| ♠♠♠♠ ♠♠ ♠ ♠♠♠♠ ♠ ♠♠♠♠♠♠ ♠♠♠♠♠ ♠♠♠♠ ♠♠♠♠ ♠♠♠|
| ░♠♠♠ ♠ ♠♠ ♠ ░♠♠♠♠ ♠ ♠ ♠ ♠♠♠ ♠ ♠♠░♠|
|♠ ♠ ░ ♠ ♠♠ ♠ ♠♠ ♠ ♠♠♠ ♠ ♠ ♠♠♠ ♠♠♠♠♠♠♠♠ ♠|
| ♠ ░♠♠♠ ♠ ♠ ♠░ ♠ ░░♠♠♠♠♠ ♠♠♠♠ ♠ ♠♠♠♠♠ ♠♠♠♠♠|
| ♠ ░♠♠♠ ♠♠ ♠ ♠ ░ ░♠ ♠ ♠░░░░░░░░ ♠ ♠♠♠♠♠♠♠♠♠♠ |
| ♠♠ ♠ ♠♠♠ ♠♠♠ ░ ♠ ♠♠ ░ ♠♠ ♠ ♠♠♠♠♠♠♠♠|
|♠ ░♠♠♠♠♠♠♠♠ ♠♠ ♠♠♠░ ░░░ ░░░░ ♠ ░ ░ ░░ ░ ♠|
| ♠ ░ ♠ ♠ ♠ ♠♠♠♠░ ░ |
| ░♠ ♠♠♠♠♠♠♠♠♠ ♠ ♠♠♠ ♠ ♠ ♠ |
| ♠ ♠ ░♠ ♠♠ ♠♠♠♠♠♠♠♠♠♠ ░░ ░ |
| ♠ ░♠♠♠ ♠♠ ░░░ ♠░ ░ ♠♠♠ ░░░░ ♠ |
| ░░♠♠♠ ♠ ♠░ ♠ ♠ ♠ ♠ ♠ ♠ ░ |
| ♠ ♠♠♠♠♠♠ ♠♠ ♠♠♠░ ♠ ░ ♠ |
|░ ░ ♠ ♠♠ ♠ ♠ ♠ ♠♠♠ ♠ ♠♠ |
| ♠ ♠♠ ░░░░♠ ♠♠ ♠♠♠░♠ ♠ ♠ ♠ ░ ░|
|♠♠♠ ♠ ░ ♠♠♠♠ ♠ ♠ ♠♠ ░♠░ ♠|
|♠ ♠♠♠♠░ ♠♠ ♠♠♠ ░ ♠ ♠ ♠ ░ ░ |
|♠ ♠♠♠♠♠░ ♠♠ ♠ ♠ ♠♠ ♠ ♠ ♠ ░♠♠♠ ♠|
|♠♠♠♠♠ ♠ ░░░░♠♠♠♠♠ ♠♠░ ♠ ♠ ♠♠ ♠ ♠|
| ♠♠♠♠♠♠♠ ♠ ♠♠ ♠░ ♠ ♠ ♠ ░♠♠♠ ♠ |
| ♠ ♠♠♠♠♠ ♠♠ ♠ ♠ ♠♠ ♠ ♠ ░♠♠ ♠ |
|♠♠♠ ♠♠♠♠♠♠ ♠ ♠♠♠ ♠░ ░ ░♠♠ ♠♠♠|
| ♠♠♠♠♠ ♠♠♠♠♠ ♠♠♠ ♠♠ ♠░ ♠ ♠ ░♠ ░ ♠ ░♠ ♠ ♠♠|
| ♠ ♠♠ ♠ ♠♠ ♠♠♠♠ ♠♠♠♠♠░ ░♠♠ ♠♠♠♠♠♠░ ♠ ♠♠ |
| ♠ ♠ ♠♠♠♠♠♠♠ ♠♠♠ ♠░░ ░░ ♠░ ░░░♠♠♠ ♠ ♠♠ ♠♠ ♠ ♠♠ ♠ |
--------------------------------------------------------------
</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>