Simulate Fire in 2D Environment
Programming Assignment
This assignment focuses on lists of lists. Turn in a file named fire.py. You will need DrawingPanel.py and one.txt.
Place these files in the same directory as your program.
Background Information:
As you have doubtless seen, computers are commonly used to simulate real life scenarios. One such common scenario ishow fire spreads. This is super common in computer gaming to make games more realistic and interesting. However, it isalso has many applications in preventing and controlling real life fires. Fire simulations are used for training for fire fighters.
Trainers can’t go out and create a huge fire in order to train fire fighters but they also don’t want to send them into a firewith no practical training. Simulations are a great way to solve this problem. Fire simulations are also used to predict howfires will spread so that people in danger can be evacuated.
In this assignment, you will create a simulation of fire spreading.
How the program works:
For this program, your world consists of a grid of squares, each representing a square meter
of ground. Some of these squares will contain trees (or other burnable vegetation), some
nothing and some fire. We will represent trees as green, nothing as yellow and fire as red.
You can assume that all the squares on the edge of the grid will always contain nothing.
Think of them as a firebreak (a section of land that has been cleared to prevent the further
spread of fire).
As your program runs, you will animate how the fire spreads from burning areas to areas
with vegetation. Your simulation should continue until all fire has gone out.
Program Behavior and Development Strategy:
Step 1: populate the simulation grid
When your program starts it should prompt the user for a file name. It should then read in the initial state of the land from
this file. This file will contain a grid of 0, 1 and 2 characters separated by whitespace. You program should create a list of
lists with the inner lists as long as the rows are wide and the outer list as long as the number of rows in the file.
We have provided one sample input file, one.txt. You will need to create other input files to test your code.
Step 2: spreading the fire
The next step is to determine how the fire spreads. If a square is empty (0), it will stay
empty no matter what. If a square is on fire (2), on the next time step it will become
empty (0). If a square has a tree in it (1) you will need to look at its neighbors to determine
its chances of catching fire.
For this simulation we will be considering the neighbor right above (north), right below
(south), to the right (east) and to the left (west). We will not be considering diagonal
neighbors. If any of the north, south, east or west neighbors are on fire, generate a random
number between 1 and 100 and if it is below 75 (the propagation percent) make that square
on fire (2), otherwise leave it as a tree (1).
Note that as you are doing this you will be changing your list of lists. This means that if you were to alter your original list,you would be comparing each square to some squares that were already updated and some that weren’t. To avoid thisproblem, create a new list of lists to store all of your changes in. When you finish a pass through the grid replace youroriginal list of lists with this new list of lists.
Step 4: Visualization
In order to watch the simulation you will need to create a visualization on a drawing panel. Draw a grid on a drawing panelthat is 10 times the length of each inner list and 10 times the height of the outer list. Make each square 10 by 10 pixels.
Color the squares differently depending on whether they are fire, empty or tree. In this document we have used green, yellowand red but you may use whatever colors you would like.
Step 5: Simulating
Animate the simulation by updating the fire’s progress and redrawing every 100 milliseconds. Your simulation shouldcontinue until all fire has gone out. Remember, you can make your program pause by calling panel.sleep(number)where number is the number of milliseconds you want it to pause.
Solution
drawingpanel.py
# drawingpanel.py
# Python 3 uses “tkinter”, and Python 2.x uses “Tkinter”.
# Detect version info and import appropriate graphics.
import sys
ifsys.version_info>= (3, 0):
fromtkinter import *
else:
fromTkinter import *
import time
”’
DrawingPanel objects represent a simple interface for creating
graphical windows in Python.
Author : Marty Stepp (stepp AT cs.washington.edu)
Version: 2010/01/15
”’
classDrawingPanel(Tk):
”’
Constructs a panel of the given width, height, and optional background color.
Keyword arguments:
width — width of the DrawingPanel in pixels (default 500)
height — height of the DrawingPanel in pixels (default 500)
background — background color of the DrawingPanel (default “white”)
”’
def __init__(self, width=500, height=500, background=”white”):
Tk.__init__(self)
self.width = width
self.height = height
self.title(“DrawingPanel”)
self.canvas = Canvas(self, width = width + 1, height = height + 1)
self.canvas[“bg”] = background
self.bg = background
self.canvas.pack({“side”: “top”})
self.wm_resizable(0, 0)
self.update()
# hack – runs mainloop on exit if not interactive
if not hasattr(sys, ‘ps1′):
self.install_mainloop_hack()
definstall_mainloop_hack(self):
# for everything but idle
sys.exitfunc = self.mainloop
# extra-terrible hack, just for idle
# flush_stdout is called immediately after code execution – intercept
# this call, and use it to call mainloop
try:
importidlelib.run
defmainloop_wrap(orig_func):
defnewfunc(*a, **kw):
self.mainloop()
idlelib.run.flush_stdout = orig_func
returnorig_func(*a, **kw)
returnnewfunc
idlelib.run.flush_stdout = mainloop_wrap(idlelib.run.flush_stdout)
exceptImportError:
pass
def clear(self):
self.canvas.create_rectangle(0, 0, self.width + 1, self.height + 1, fill=self.bg, outline=self.bg)
”’
Sets the panel’s background color to be the given color.
Keyword arguments:
color — the color to set, as a string such as “yellow” or “black”
”’
defset_background(self, color):
self.canvas[“bg”] = color
”’
Causes the DrawingPanel to pause for the given number of milliseconds.
Useful for creating simple animations.
Keyword arguments:
ms — number of milliseconds to pause
”’
def sleep(self, ms):
try:
self.update()
time.sleep(ms / 1000.0)
self.update()
except Exception:
pass
fire.py
import copy
import sys
fromdrawingpanel import *
import random
#input(name) function takes the name of the file as argument and returns a list of lists with the data in the file
def input(name):
results = []
with open(name) as inputfile:
for line in inputfile:
results.append(line.strip().split(‘ ‘))
return results
#fire_or_not(list) returns boolean True if ther is still fire else it returns False
deffire_or_not(list):
k=False
for i in range(0,len(list)):
for j in range(0,len(list[0])):
ifint(list[i][j])==2:
k=True
break
return k
#check_index(list,i,j) function is used in fire(list,proba) to avoid array out of bound error.It checks whether given indices are valid for the given list of lists
defcheck_index(list,i,j):
k=False
if i>=0 and j<len(list[0]) and i<len(list) and j>=0:
ifint(list[i][j])==2:
k=True
return k
#fire(list,proba) returns the updated list of lists by taking the old list and propagation percentage as parameters
def fire(list,proba):
updated_list=copy.deepcopy(list)
for i in range(0,len(updated_list)):
for j in range(0,len(updated_list[0])):
ifint(list[i][j])==2:
updated_list[i][j]=0
elifint(list[i][j])==1:
if check_index(list,i-1,j) or check_index(list,i+1,j) or check_index(list,i,j+1) or check_index(list,i,j-1):
m=random.randint(1,100)
if(m<proba):
updated_list[i][j]=2
else:
updated_list[i][j]=0
else:
updated_list[i][j]=0
returnupdated_list
#drawing(panel,list) updates the squares in the panel according to the numbers in list of lists
def drawing(panel,list):
for i in range(0,len(list)):
for j in range(0,len(list[0])):
ifint(list[i][j])==1:
panel.canvas.create_rectangle(10*j, 10*i, 10+10*j, 10+10*i,fill=”green”,width=0)
elifint(list[i][j])==2:
panel.canvas.create_rectangle(10*j, 10*i, 10+10*j, 10+10*i,fill=”red”,width=0)
elifint(list[i][j])==0:
panel.canvas.create_rectangle(10*j, 10*i, 10+10*j, 10+10*i,fill=”yellow”,width=0)
#main(name,proba) takes the name of the file and propagation percentage as parameters and uses all the functions defined previously b
def main(name,proba):
list=input(name)
panel = DrawingPanel(len(input(“one.txt”)[0])*10,len(input(“one.txt”))*10)
panel.set_background(“yellow”)
whilefire_or_not(list):
drawing(panel,list)
panel.sleep(100)
list=fire(list,proba)
drawing(panel,list)
#change the filename and propagation percentage here
main(“one.txt”,75)