222 lines
5.1 KiB
Text
222 lines
5.1 KiB
Text
//
|
|
// FOREST FIRE SIMULATION
|
|
//
|
|
// Using FutureBasic 7.0.34
|
|
// August 2025, R.W.
|
|
//
|
|
Boolean running
|
|
BlockOperationRef dCode
|
|
OperationQueueRef cQueue
|
|
OperationQueueRef opQueue
|
|
|
|
long N, M
|
|
double pfire, ptree, generation
|
|
long dimx, dimy
|
|
long f(142,142) // the forest
|
|
long future(142,142) // the predicted future
|
|
CFStringRef gen
|
|
CGFloat red, green, blue
|
|
colorRef colR
|
|
float rndf
|
|
pfire=0.00002: ptree=0.002 //probabilities
|
|
|
|
begin enum 1
|
|
_window
|
|
_generation
|
|
_toggle
|
|
end enum
|
|
|
|
// Build window
|
|
|
|
void local fn BuildWindow
|
|
CGRect r = fn CGRectMake( 0, 0, 570, 570 )
|
|
window _window, @"Forest Fire Simulation", r, NSWindowStyleMaskTitled + ¬
|
|
NSWindowStyleMaskClosable
|
|
WindowSetBackgroundColor( _window, fn ColorBlack) //ColorWindowBackground )
|
|
ViewSetFlipped( _WindowContentViewTag, YES )
|
|
WindowSubclassContentView(_Window)
|
|
ViewSetNeedsDisplay( _windowContentViewTag )
|
|
windowcenter (_Window)
|
|
AppSetAppearance(fn AppearanceNamed(NSAppearanceNameDarkAqua))
|
|
WindowMakeFirstResponder( _Window, _windowContentViewTag )
|
|
ViewSetAcceptsFirstResponder( _Window, _true )
|
|
end fn
|
|
|
|
void local fn DrawControls
|
|
gen = @""
|
|
CGRect r = fn CGRectMake( 10, 532, 220, 32 )
|
|
textlabel _generation, gen,r,_window
|
|
r = fn CGRectMake( 450, 530, 100, 24 )
|
|
button _toggle,,, @"Start", r, , , _Window
|
|
end fn
|
|
|
|
//
|
|
// Populate the array with empty and tree cells according to a
|
|
// specific probability
|
|
// (e.g. a cell has the probability 0.5 to be a tree)
|
|
|
|
void local fn buildForest
|
|
int x, y
|
|
// Initialize forest with trees (1) or empty (0)
|
|
for y = 1 to N
|
|
for x = 1 to M
|
|
rndf = (rnd(65536)-1)/65536.0
|
|
// a cell has the probability 0.5 to be a tree
|
|
if rndf < 0.5 then f(x,y) = 1 else f(x,y) = 0
|
|
next
|
|
next
|
|
end fn
|
|
|
|
//
|
|
// Draw the forest
|
|
|
|
local fn DrawForest
|
|
int x, y
|
|
cls
|
|
for y = 1 to N
|
|
for x = 1 to M
|
|
red = 0.0: green = 0.0: blue = 0.0 //black
|
|
if f(x,y) == 1
|
|
red = 0: green = 0.50: blue = 0 //green
|
|
else
|
|
if f(x,y) == 2
|
|
red = 0.97: green = 0.49: blue = 0 //red
|
|
end if
|
|
end if
|
|
Colr = fn ColorWithRGB(red,green,blue,1.0)
|
|
pen 1, colr
|
|
oval fill (x*4,y*4,3.2,3.2), colr
|
|
next
|
|
next
|
|
end fn
|
|
|
|
//
|
|
// Simulates the forest fire
|
|
|
|
local fn simulate
|
|
|
|
int x, y, xx, yy, localfire
|
|
|
|
// A burning cell turns into an empty cell
|
|
// A tree will burn if at least one neighbor is burning
|
|
// A tree ignites with probability pfire even if no neighbor is burning
|
|
// An empty space grows a tree with probability ptree
|
|
//
|
|
for y = 1 to N
|
|
for x = 1 to M
|
|
rndf = (rnd(65536)-1)/65536.0
|
|
select case f(x,y)
|
|
case 0 // empty
|
|
if rndf < ptree
|
|
future(x,y) = 1
|
|
else
|
|
future(x,y) = 0
|
|
end if
|
|
case 1 // tree
|
|
if rndf < pfire
|
|
future(x,y) = 2 // probability of ignition
|
|
else
|
|
// check neighbors for fire
|
|
localFire = 0
|
|
for yy = y-1 to y+1
|
|
for xx = x-1 to x+1
|
|
if f(xx,yy) == 2 then localFire = 1
|
|
next
|
|
next
|
|
if localFire == 1
|
|
future(x,y) = 2
|
|
else
|
|
future(x,y) = 1
|
|
end if
|
|
end if
|
|
case 2 // burning
|
|
future(x,y) = 0
|
|
end select
|
|
next
|
|
next
|
|
|
|
// Copy future to forest
|
|
for y = 1 to N
|
|
for x = 1 to M
|
|
f(x,y) = future(x,y)
|
|
next
|
|
next
|
|
generation++
|
|
end fn
|
|
|
|
//
|
|
// Executed as long as we are running
|
|
//
|
|
local fn tillTheCowsComeHome (dPtr as Ptr)
|
|
while running
|
|
dispatchmain
|
|
fn drawforest
|
|
dispatchend
|
|
fn Simulate
|
|
delay 110
|
|
wend
|
|
// callback canned
|
|
OperationCancel (dCode )
|
|
end fn
|
|
|
|
// Begin animation
|
|
void local fn Animate
|
|
// setup dispatch queue w/ callback
|
|
dCode = fn BlockOperationWithCallback( @fn tillTheCowsComeHome, NULL )
|
|
cQueue = fn OperationQueueInit // Init queue
|
|
OperationQueueSetMaxConcurrentOperationCount( cQueue, 1 ) // serial only
|
|
OperationQueueAddOperations( cQueue, @[dCode], NO ) // add to queue
|
|
end fn
|
|
|
|
//
|
|
// App Event handler
|
|
//
|
|
void local fn DoAppEvent( ev as long )
|
|
select ( ev )
|
|
case _appWillTerminate
|
|
if running then OperationCancel (dCode )
|
|
end select
|
|
end fn
|
|
|
|
//
|
|
// Dialog handler
|
|
|
|
void local fn DoDialog( ev as long, tag as long, wnd as long, obj as CFTypeRef )
|
|
select ( ev )
|
|
case _btnClick
|
|
select ( tag )
|
|
case _toggle
|
|
running = !running // toggles run status
|
|
if running
|
|
button _toggle,,, @"Stop"
|
|
fn Animate
|
|
textlabel _generation, @""
|
|
else
|
|
button _toggle,,, @"Start"
|
|
gen = concat(@"Stopped at Generation: ",str(generation))
|
|
textlabel _generation, gen
|
|
end if
|
|
end select
|
|
case _windowShouldClose
|
|
if running then OperationCancel (dCode )
|
|
end
|
|
end select
|
|
end fn
|
|
//==========================================
|
|
|
|
on dialog fn DoDialog
|
|
|
|
fn BuildWindow
|
|
fn DrawControls
|
|
|
|
randomize
|
|
|
|
N = 130 // number of rows
|
|
M = 140 // number of columns
|
|
generation = 1
|
|
running = _False
|
|
|
|
fn buildForest
|
|
fn drawForest
|
|
|
|
handleEvents
|