import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.colors as cc
from matplotlib.colors import ListedColormap
# creates the four colors for our simulation, EMPTY is white,
# TREE is green, FIRE is red and BURNT is black
colors = cc.ColorConverter.colors
cols = [colors['w'],
colors['g'],
colors['r'],
colors['k']]
ff1 = ListedColormap(cols)
# TODO revise this method to include a boolean parameter called torus
# when true, the function should wrap around the edges, when false
# return the function as written.
def von_neuman_neighbors(i, j, size):
n = []
if i > 0:
n.append((i - 1, j))
if j > 0:
n.append((i, j - 1))
if i < size - 1:
n.append((i + 1, j))
if j < size - 1:
n.append((i, j + 1))
return n
# TODO write this method to include all eight neighbors. Use the
# torus parameter as described above
def moore_neighbors(i, j, size, torus):
pass
class Forest():
states = {"EMPTY":0, "TREE":1, "FIRE":2, "BURNT":3}
def __init__(self, size):
self.size = size
self.x = np.arange(size)
self.y = np.arange(size)
self.cells = np.zeros((size, size))
def set_fire(self, locs):
for p in locs:
self.cells[p[0] + self.size / 2, p[1] + self.size / 2] = Forest.states["FIRE"]
def random_setup(self, d):
for i in range(self.size):
for j in range(self.size):
if (np.random.random() < d):
self.cells[i, j] = Forest.states["TREE"]
else:
self.cells[i, j] = Forest.states["EMPTY"]
def image_setup(self):
plt.title("Forest Fire Simulation")
self.plt = plt.imshow(self.cells, interpolation='nearest',
origin='bottom',
vmin=np.min(Forest.states["EMPTY"]),
vmax=np.max(Forest.states["BURNT"]),
cmap=ff1)
def update(self):
newcells = np.zeros((self.size, self.size))
for i in range(self.size):
for j in range(self.size):
neighbors = von_neuman_neighbors(i, j, self.size)
# TODO Add in code to make the fire spread. If a tree is near
# a fire cell, it catches. All trees on fire burn out completely in
# one timestep.
if self.cells[i,j] == Forest.states["FIRE"]:
newcells[i,j] = self.cells[i,j]
elif self.cells[i,j] == Forest.states["TREE"]:
newcells[i,j] = self.cells[i,j]
elif self.cells[i,j] == Forest.states["BURNT"]:
newcells[i,j] = self.cells[i,j]
elif self.cells[i,j] == Forest.states["EMPTY"]:
newcells[i,j] = self.cells[i,j]
# TODO Revise to have burnt trees turn into empty cells randomly
# TODO Revise to have empty cells grow new trees randomly if they
# they are adjacent to a living tree
# TODO Add in a probability of a lightning strike each round. If it hits a
# tree, the tree is set on fire.
self.cells = newcells
def plot(self):
self.plt.set_data(self.cells)
return self.plt
size = 60
density = 0.35
fig, ax = plt.subplots()
ax.set_ylim(-1, size)
ax.set_xlim(-1, size)
middle = ((0, 0), )
ff = Forest(size)
ff.random_setup(density)
ff.set_fire(middle)
################
# ANIMATION
ff.image_setup()
def update(data):
ff.update()
return ff.plot(),
def data_gen():
while True: yield 1
ani = animation.FuncAnimation(fig, update, data_gen, blit=False, interval=50)
plt.show()
Explore forest density values between 35% and 65%, and plot this versus the average percent of initial trees burned over 20 iterations.
Questions to answer
Add in decay of burnt trees, new growth, and lightning, and plot the distribution of the states over time.