474 lines
24 KiB
Text
474 lines
24 KiB
Text
Computers can be used to build models of complex real world systems such as the
|
||
weather, traffic and stockmarkets. Computer models can help us to understand the
|
||
dynamics of these real world systems, and to make decisions about them. For
|
||
example, a model that can predict Saturday's weather could help us decid
|
||
whether to go to the beach or not. A traffic model could help us plan where to
|
||
build a new road to reduce traffic jams. A model of the stockmarket could help
|
||
us decide when to buy and sell shares.
|
||
|
||
In this project, you will build a simple model of a bushfire spreading across a
|
||
landscape represented as a two-dimensional grid. The speed and direction that a
|
||
bushfire will spread in is affected by many factors, including the amount and
|
||
type of fuel (trees) available, the slope of the land, and the direction of the
|
||
wind. Your model will help forecast how much damage (number of grid squares
|
||
burnt) a fire will do before it burns out.
|
||
|
||
Models like this (but much more complicated!) are used to help predict which way
|
||
a fire might spread, to assess where high risk fires are most likely to occur,
|
||
and help understand how the damage cause by fires can be reduced via management
|
||
practices. See Phoenix rapid fire for an example of a much more complex model
|
||
(developed at the University of Melbourne).
|
||
|
||
In this project we will look at three different problems related to a bushfire
|
||
|
||
- How to build a bushfire model from a data file
|
||
- How to determine if a cell in a specific location will ignite
|
||
- How to model the spread of a bushfire
|
||
|
||
You will also need to write and submit a set of test cases for evaluating
|
||
the model.
|
||
|
||
--------------------------------------------------------------------------------
|
||
The bushfire model
|
||
|
||
We model a bushfire as occurring in a square grid made up of M by M cells. The
|
||
cell ci,j refers to the cell in the ith row and the jth column of the grid. Each
|
||
cell typically has eight adjacent cells (horizontally, vertically and
|
||
diagonally). Cells on the edge of the grid are adjacent to only five other
|
||
cells; cells in the corners of the grid are adjacent to only three other cells.
|
||
For convenience, we take the top of the grid to be North, the right side to
|
||
East, the bottom to be South and the left side to be West. See
|
||
bushfire_model.png for reference.
|
||
|
||
Each cell in the M by M grid has several attributes:
|
||
- fuel load: the amount of combustible material (trees, leaf litter, etc) in
|
||
that cell. The fuel load of a cell is represented as a non-negative integer,
|
||
where 0 (zero) equates to no combustible material.
|
||
- height: the elevation of the cell. Height is represented as a positive integer
|
||
(a cell with height 3 is higher than a cell with height 2, which is in turn
|
||
higher than a cell with height 1, and so on). Fires will tend to spread more
|
||
rapidly uphill, and more slowly downhill, compared to flat ground.
|
||
- burning: a Boolean value indicating whether the cell is currently burning or
|
||
not. A cell can only be burning if it's fuel load is greater than 0 (zero).
|
||
|
||
In addition, the entire grid is characterised by three further attributes:
|
||
|
||
- ignition threshold: how combustible the landscape is (for instance, a dry
|
||
landscape would be more combustible than a wet landscape, and have a lower
|
||
ignition threshold). The ignition threshold is represented by an integer
|
||
greater than 0 (zero). A non-burning cell will start burning if its ignition
|
||
factor (explained below) is greater than or equal to the ignition threshold.
|
||
- ignition factor: the intensity of fire around a particular non-burning cell at
|
||
a given point in time that, in combination with the ignition threshold
|
||
described above, will be used to determine whether a cell will start burning.
|
||
The ignition factor is floating point number; details of how to calculate the
|
||
ignition factor are provided on the following sections.
|
||
- wind direction: if a wind is blowing, it can carry embers that allow a fire to
|
||
spread more rapidly in a particular direction. Wind may blow from one of eight
|
||
directions: North, Northeast, East, Southeast, South, Southwest, West or
|
||
Northwest (abbreviated N, NE, E, SE, S, SW, W, NW) or there may be no wind.
|
||
How the wind affects ignition will be explained further.
|
||
|
||
--------------------------------------------------------------------------------
|
||
Part 1 - Parse a bushfire scenario file
|
||
|
||
Your task is to write a function parse_scenario(filename) that parses a file
|
||
with the structure described below, validates the contents and returns either a
|
||
dictionary containing all values required to specify a model scenario if the
|
||
contents are valid, or None if any of the contents are invalid.
|
||
|
||
The structure of the file is as follows:
|
||
|
||
- an integer specifying the width and height (M) of the square landscape grid
|
||
- M lines, each containing M integer values (separated by commas), defining the
|
||
initial fuel load of the landscape (a visual representation of the M by
|
||
M grid)
|
||
- M lines, each containing M integer values (separated by commas), defining the
|
||
height of the landscape (again, a visual representation of the M by M grid)
|
||
- an integer specifying the ignition threshold for this scenario
|
||
- a one or two character string specifying the wind direction for this scenario
|
||
(or 'None' if there is no wind)
|
||
- one or more lines, each containing the (i,j) coordinates (row number, column
|
||
number) of a cell which is burning at the start of the simulation
|
||
|
||
For example, the file 'bf0.dat' specifies a 2 by 2 landscape:
|
||
|
||
- there is an initial fuel load of 2 in three of the four cells, with a fuel
|
||
load of 0 in the cell c1,0
|
||
- the height of all cells in the first column (j = 0) is 1, while the height of
|
||
all cells in the second column (j = 1) is 2 (ie, the landscape slopes up
|
||
toward the East)
|
||
- the ignition threshold is 1
|
||
- a wind is blowing from the North
|
||
- the top left cell c0,0 is burning at the start of the simulation
|
||
|
||
You may assume that the input files are well-formed, but your function should
|
||
ensure that:
|
||
|
||
- the dimensions of the grid are a positive integer;
|
||
- the ignition threshold is a positive integer not greater than eight;
|
||
- the wind direction is valid; and
|
||
- the coordinates of the burning cells are (a) located on the landscape, and (b)
|
||
have non-zero initial fuel load.
|
||
|
||
If all values are valid, your function should return a dictionary with key/value
|
||
pairs as follows:
|
||
|
||
- f_grid: a list of lists (of dimensions M by M)
|
||
- h_grid: a list of lists (of dimensions M by M)
|
||
- i_threshold: an integer
|
||
- w_direction: a string or None
|
||
- burn_seeds: a list of tuples
|
||
|
||
If there is no wind, w_direction can be either an empty string '' or None. If
|
||
any values are invalid, your function should return None.
|
||
|
||
For example:
|
||
|
||
>>> parse_scenario('bf0.dat')
|
||
{'f_grid': [[2, 2], [0, 2]],
|
||
'h_grid': [[1, 2], [1, 2]],
|
||
'i_threshold': 1,
|
||
'w_direction': 'N',
|
||
'burn_seeds': [(0, 0)]}
|
||
|
||
>>> parse_scenario('bf.dat')
|
||
{'f_grid': [[1, 2, 1], [0, 1, 2], [0, 0, 1]],
|
||
'h_grid': [[1, 1, 1], [2, 1, 2], [3, 2, 2]],
|
||
'i_threshold': 1,
|
||
'w_direction': 'N',
|
||
'burn_seeds': [(1, 1)]}
|
||
|
||
--------------------------------------------------------------------------------
|
||
Updating the model
|
||
|
||
The state of the bushfire model is defined by the attributes (fuel load, height,
|
||
burning, ignition threshold and wind direction) described on the previous
|
||
section. Of these, fuel load and burning status may change over time as the
|
||
bushfire spreads. Height, ignition threshold and wind direction are fixed and
|
||
never change.
|
||
|
||
The state of the model is updated in discrete timesteps, t = 0, 1, 2, 3, ...
|
||
|
||
At each timestep, the following things happen:
|
||
|
||
- If a cell is currently burning, it's fuel load will be reduced by one in the
|
||
following timestep. If this will result in its fuel load reaching zero, it
|
||
will stop burning in the following timestep.
|
||
- If a cell is not currently burning, it may start burning, depending on its
|
||
proximity to other cells which are burning in this timestep. The rules
|
||
describing how to determine if a cell catches fire are described on the
|
||
next section.
|
||
|
||
Note, the future state of each cell in time t+1 is determined on the basis of
|
||
the current state of the grid at time t. We stop updating the model when no
|
||
cells are burning, as the state will not change after this point.
|
||
|
||
--------------------------------------------------------------------------------
|
||
Determining when a cell catches fire (simple)
|
||
|
||
To determine whether a cell ci,j catches fire, we calculate its ignition factor
|
||
and compare this to the landscape's ignition threshold. As stated above, a cell
|
||
will catch fire if its ignition factor is greater than or equal to the ignition
|
||
threshold. A cell must be currently not burning and have a fuel load greater
|
||
than 0 (zero) in order to catch fire.
|
||
|
||
We will start by considering the simplest case: a flat landscape with no wind in
|
||
which cell ci,j is not currently burning. In this case, each cell adjacent to
|
||
ci,j that is burning contributes 1 point to ci,j's ignition factor. Thus, if the
|
||
ignition threshold is 1, ci,j will start burning if it is adjacent to at least
|
||
one burning cell. If the ignition threshold is 2, ci,j will start burning only
|
||
if it is adjacent to at least two burning cells.
|
||
|
||
Consider the sequence of landscape states shown in simple-bushfire-model.png, in
|
||
which all cells are of the same height, there is no wind, and the ignition
|
||
threshold is 1. At the first timestep (t = 0), the two cells c0,0 and c0,1 are
|
||
burning. During this timestep, the fuel load of each of these two cells will
|
||
decrease by one (causing the fire in c0,0 to stop burning in the next time step,
|
||
t = 1). If we then consider at the surrounding cells, c1,0 has a fuel load of 0
|
||
(zero), so it cannot catch fire. Cells c0,2, c1,1 and c1,2 each have a fuel load
|
||
greater than 0 (zero) and are adjacent to one of the currently burning cells,
|
||
therefore they will start burning in the next time step (t == 1).
|
||
|
||
The example in simple_bushfire_model_2.png is identical to that in
|
||
simple_bushfire_model.png, but the ignition threshold is now 2, meaning that
|
||
each non-burning cell needs to be adjacent to two or more burning cells in
|
||
order to start burning. Therefore, cells c0,2 and cells c1,2 will not start
|
||
burning at t = 1, as they were only adjacent to a single burning cell at t = 0.
|
||
|
||
Only cells that are located within the bounds of the landscape grid can
|
||
contribute to a cell's ignition factor. Thus, a cell located in the corner of a
|
||
grid will, in this simple case, only have three adjacent cells that may cause it
|
||
to start burning.
|
||
|
||
--------------------------------------------------------------------------------
|
||
Determining when a cell catches fire (height included)
|
||
|
||
Height and wind modify can modify the calculation of the basic ignition factor
|
||
described on the previous section. The effect of landscape height is described on
|
||
this section.
|
||
|
||
On a flat landscape, where neighbouring cells are of the same height, each
|
||
burning cell contributes 1 point to an adjacent non-burning cell's
|
||
ignition factor.
|
||
|
||
However, bushfires tend to spread more rapidly uphill, therefore if a cell ci,j
|
||
has height that is greater than that of an adjacent burning cell, that cell will
|
||
contribute twice as much (i.e., 2 points) to ci,j's ignition factor. Conversely,
|
||
bushfires tend to spread more slowly downhill, therefore an adjacent burning
|
||
cell with height greater than ci,j's height will contribute only half as much
|
||
(i.e., 0.5 points) to ci,j's ignition factor.
|
||
|
||
In the sequence shown in height_bushfire_model.png, the height of each cell is
|
||
indicated by a small blue number. No wind is blowing and the ignition threshold
|
||
of the landscape is 2. At the first timestep (t = 0) a single cell c0,0 is
|
||
burning. The cell to the South of it (c1,0) has a fuel load of 0 (zero) and
|
||
hence cannot catch fire. On a flat landscape, the other two adjacent cells (c0,1
|
||
and c1,1 would not catch fire either, as their ignition factor would only be 1
|
||
(from the single burning cell c0,0), below the ignition threshold of 2. However,
|
||
in this landscape, cells c0,1 and c1,1 are higher than cell c0,0, therefore its
|
||
contribution to their ignition factor is doubled to 2 points, high enough to
|
||
equal the landscape's ignition threshold and cause them to start burning in the
|
||
following timestep (t = 1).
|
||
|
||
In constrast, the top-right cell c0,2 will escape being burnt in timestep t = 2
|
||
(and beyond) as it is lower than the surrounding cells, hence they each
|
||
contribute only 0.5 points to its ignition factor. Thus, even when all three
|
||
surrounding cells are burning, c0,2's ignition factor is only 1.5, below the
|
||
landscape ignition threshold of 2.
|
||
|
||
--------------------------------------------------------------------------------
|
||
Determining when a cell catches fire (wind included)
|
||
|
||
Wind can carry burning embers that allow a fire to spread more rapidly in a
|
||
particular direction. If a wind is blowing, up to three additional cells are
|
||
considered to be adjacent to ci,j for the purpose of calculating its
|
||
ignition factor.
|
||
|
||
For example, as shown in wind_example.png, if a wind is blowing from the North,
|
||
the cell two cells above ci,j and the cells immediately to the left and right
|
||
of this cell are considered adjacent to ci,j (ie, cells ci−2,j−1, ci−2,j and
|
||
ci−2,j+1). If any of these additional cells are burning, they will also
|
||
contribute when calculating ci,j's ignition factor.
|
||
|
||
If a wind is blowing from the Southwest, the cell two cells below and to the
|
||
left of ci,j and the cells immediately above and to the right of this cell are
|
||
considered adjacent to ci,j. That is, cells ci+1,j−2, ci+2,j−2 and ci+2,j−1. Of
|
||
course, these additional cells must be within the bounds of the landscape in
|
||
order to have any effect, as in the simple case on the previous section.
|
||
|
||
The sequence shown in wind_bushfire_model.png is identical to the simple example
|
||
shown on the previous section (on a flat landscape, with ignition threshold of 2)
|
||
except that the wind is now blowing from the Northwest. As a consequence, cell
|
||
c0,0 is considered adjacent to c1,2, which therefore has an ignition factor of
|
||
2 (as c0,1 is also adjacent and burning) and hence will start burning at t = 1.
|
||
In addition, c0,0 and c0,1 are also both considered adjacent to c2,2, which will
|
||
also start burning at t = 1. Bushfires spread much more rapidly when the wind
|
||
is blowing!
|
||
|
||
When considering the joint effects of height and wind, you should compare the
|
||
heights of ci,j and each of its adjacent cells on a pairwise basis, disregarding
|
||
the heights of any other surrounding cells. For example, if c0,0 was higher than
|
||
c2,2 and c0,1 was lower than c2,2 then they would contribute 0.5 points and 2
|
||
points respectively to c2,2's ignition factor, irrespective of the heights of the
|
||
intervening cells (c1,1, etc).
|
||
|
||
--------------------------------------------------------------------------------
|
||
Part 2 - Determine if a cell starts burning
|
||
|
||
Based on the rules described earlier, your task is to write a function
|
||
check_ignition(b_grid, f_grid, h_grid, i_threshold, w_direction, i, j) that
|
||
takes as arguments the burning state b_grid (at time t), current fuel load
|
||
f_grid (at time t), height h_grid, ignition threshold i_threshold, wind
|
||
direction w_direction and coordinates i and j of a cell, and returns True if
|
||
that cell will catch fire at time t + 1 and False otherwise.
|
||
|
||
The arguments are of the following types:
|
||
|
||
- b_grid: a list of lists of Boolean values (of dimensions M by M)
|
||
- f_grid: a list of lists of integers (of dimensions M by M)
|
||
- h_grid: a list of lists of integers (of dimensions M by M)
|
||
- i_threshold: an integer
|
||
- w_direction: a string (if wind is blowing), otherwise None (if no wind
|
||
is blowing)
|
||
- i and j: integers (i,j < M)
|
||
|
||
You may assume that all arguments are valid, as defined in Part 1.
|
||
|
||
For example:
|
||
|
||
>>> check_ignition([[True, False], [False, False]], [[2, 2], [2, 2]],
|
||
[[1, 1], [1, 1]], 1, 'N', 0, 1)
|
||
True
|
||
|
||
>>> check_ignition([[True, False], [False, False]], [[2, 0], [2, 2]],
|
||
[[1, 1], [1, 1]], 1, 'N', 1, 0)
|
||
True
|
||
|
||
>>> check_ignition([[True, True, False], [False, False, False],
|
||
[False, False, False]], [[1, 1, 1], [1, 1, 1], [1, 0, 0]], [[2, 2, 1],
|
||
[2, 3, 1], [1, 1, 1]], 1, None, 0, 2)
|
||
False
|
||
|
||
>>> check_ignition([[True, True, False], [False, False, False],
|
||
[False, False, False]], [[1, 1, 1], [1, 1, 1], [1, 0, 0]], [[2, 2, 1],
|
||
[2, 3, 1], [1, 1, 1]], 2, None, 1, 1)
|
||
True
|
||
|
||
--------------------------------------------------------------------------------
|
||
Part 3 - Run the model
|
||
|
||
Your task is to write a function run_model(f_grid, h_grid, i_threshold,
|
||
w_direction, burn_seeds) that takes as arguments the initial fuel load f_grid
|
||
(i.e., at time t = 0), height h_grid, ignition threshold i_threshold, wind
|
||
direction w_direction and a list of cells burn_seeds that are burning at time
|
||
t = 0, and returns a tuple containing (a) the final state of the landscape once
|
||
the fire has stopped burning, and (b) the total number of cells that have been
|
||
burnt by the fire (including any initially burning cells in burn_seeds).
|
||
|
||
The arguments are of the following types:
|
||
|
||
- f_grid: a list of lists (of dimensions M by M)
|
||
- h_grid: a list of lists (of dimensions M by M)
|
||
- i_threshold: an integer
|
||
- w_direction: a string
|
||
- burn_seeds: a list of integer tuples (i, j) where i, j < M
|
||
|
||
You may assume that all arguments are valid, as defined in previous questions.
|
||
You have been provided with a reference version of the function check_ignition
|
||
as described in Part 2.
|
||
|
||
You may find it helpful to define one or more additional functions that carry
|
||
out a single step of the model run, determining the new burning state and fuel
|
||
load at time t + 1 on the basis of the model state at time t.
|
||
|
||
For example:
|
||
|
||
>>> run_model([[2, 2], [2, 2]], [[1, 1], [1, 1]], 1, 'N', [(0, 0)])
|
||
([[0, 0], [0, 0]], 4)
|
||
|
||
>>> run_model([[2, 0], [0, 2]], [[1, 1], [1, 1]], 2, 'S', [(0, 0)])
|
||
([[0, 0], [0, 2]], 1)
|
||
|
||
--------------------------------------------------------------------------------
|
||
Part 4 - Test cases
|
||
|
||
In addition to implementing your solutions, you are also required to submit a
|
||
set of test cases that can be used to test your Part 3 run_model function.
|
||
|
||
You should aim to make your test cases as complete as possible. That is, they
|
||
should be sufficient to pick up incorrect implementations of the model.
|
||
|
||
Your set of test cases may assume that the input passed to your function will be
|
||
of the correct types and will be well-formed.
|
||
|
||
Your test cases suite will be evaluated by running it on several known incorrect
|
||
implementations, in which it should detect incorrect behaviour; ie, returning an
|
||
incorrect final state of the landscape and/or number of cells burnt.
|
||
|
||
You should specify your test cases as a series of calls to the function
|
||
test_run_model(input_args, expected_return_value), where the first argument
|
||
input_args contains a list of f_grid, h_grid, i_threshold, w_direction
|
||
burn_seeds representing the call to the function run_model (described in Part 3)
|
||
and expected_return_value is the expected return from the function run_model,
|
||
namely a list containing the final state of the landscape once the fire has
|
||
stopped burning, and the total number of cells that have been burnt by the fire
|
||
(as in Part 3).
|
||
|
||
That is, you specify both the arguments and return value for run_model as
|
||
arguments to test_run_model.
|
||
|
||
For example, using the first two examples from Part 2:
|
||
|
||
>>> from testcase_tournament import test_fn as test_run_model
|
||
>>> test_run_model([[[2, 2], [2, 2]], [[1, 1], [1, 1]], 1, 'N', [(0, 0)]],
|
||
[[[0, 0], [0, 0]], 4])
|
||
>>> test_run_model([[[2, 0], [0, 2]], [[1, 1], [1, 1]], 2, 'S', [(0, 0)]],
|
||
[[[0, 0], [0, 2]], 1])
|
||
|
||
--------------------------------------------------------------------------------
|
||
Part 5 - Bonus
|
||
|
||
The final part is for bonus marks, and is deliberately quite a bit harder than
|
||
the four basic questions (and the number of marks on offer is deliberately not
|
||
commensurate with the amount of effort required — bonus marks aren't meant to be
|
||
easy to get!). Only attempt this is you have completed the earlier questions,
|
||
and are up for a challenge!
|
||
|
||
In this question, you will use the bushfire model to determine the optimal cell
|
||
or cells in a landscape in which to conduct a prescribed burn in order to best
|
||
protect a town from a future bushfire of unknown timing and origin.
|
||
|
||
For this question, we modify our original definition of a landscape to include a
|
||
town cell, containing a town. The town cell has a non-zero fuel load; that is,
|
||
the town can catch fire.
|
||
|
||
Prescribed burns
|
||
|
||
A prescribed burn is a controlled fire used as part of forest management in
|
||
order to reduce the risk of future uncontrolled fires.
|
||
|
||
In our simulation model, the rules of a prescribed burn are that it will only
|
||
occur on a day with no wind, and will commence on a single prescribed burn cell
|
||
with a non-zero fuel load. A prescribed burn will not be conducted on the cell
|
||
containing the town.
|
||
|
||
A prescribed burn spreads just like a normal bushfire; however, due to the
|
||
controlled nature of the fire, any burning cell contributes only half as many
|
||
points to the ignition factor of adjacent cells as it ordinarily would (taking
|
||
slope into account). That is, if it would normally contribute 0.5, 1 or 2
|
||
points, it will now only contribute 0.25, 0.5, or 1 points. This reduction
|
||
applies both to the original prescribed burn cell and to any cell that
|
||
subsequently catches fire during the prescribed burn. As with a normal bushfire,
|
||
a prescribed burn will continue until no cells remain on fire.
|
||
|
||
Scoring prescribed burn cells
|
||
|
||
We filter out invalid prescribed burn cells and score the remaining valid
|
||
prescribed burn cells as follows:
|
||
|
||
- Any prescribed burn cell that results in the the town cell catching fire is
|
||
deemed invalid.
|
||
- Following the completion of a prescribed burn, we will consider scenarios in
|
||
which potential bushfires start in any (single) seed cell with a non-zero fuel
|
||
load (after the prescribed burn), except for the town cell, on a day with any
|
||
possible wind conditions. Thus, for a landscape of dimensions M, we will
|
||
consider up to (M2−2)×9 bushfire scenarios. 2 is subtracted because we don't
|
||
seed a bushfire on the town cell or cells with zero fuel load, of which there
|
||
is at least one, being the cell in which the prescribed burn was conducted.
|
||
For each seed cell there are 9 possible wind directions to consider, including
|
||
no wind.
|
||
- Valid prescribed burn cells are scored according to the proportion of
|
||
scenarios in which the town cell caught fire.
|
||
|
||
The optimal cell or cells for prescribed burning are those with the lowest
|
||
score; that is, that have been more effective at protecting the town.
|
||
|
||
In the first example below, there are 4 cells with a non-zero fuel load, one of
|
||
which (c1,1) is the town cell. Therefore there are three cells in which a
|
||
prescribed burn can be conducted. None of these will result in the town being
|
||
burnt, therefore they are all valid. When we test the 18 possible bushfire
|
||
scenarios, we find that for one valid prescribed burn cell (c0,1), all
|
||
subsequent bushfires will result in the town catching fire. For the other two
|
||
prescribed burn cells (c0,0 and c1,0), only half of the subsequent bushfires
|
||
will result in the town catching fire; thus, either of these would be the
|
||
optimal location in which to carry out a prescribed burn in this landscape.
|
||
|
||
Your task is to write a function plan_burn(f_grid, h_grid, i_threshold,
|
||
town_cell) that determines the optimal prescribed burn cell or cells. f_grid,
|
||
h_grid and i_threshold are all as defined in Parts 2 and 3. town_cell is a tuple
|
||
containing the coordinates of the town cell.
|
||
|
||
Your function should return a sorted list containing the coordinates of the
|
||
optimal prescribed burn cell or cells, as defined above. If there are no valid
|
||
prescribed burn cells, this list will be empty.
|
||
|
||
For example:
|
||
|
||
>>> plan_burn([[2, 2], [1, 2]], [[1, 2], [1, 2]], 2, (1, 1))
|
||
[(0, 0), (1, 0)]
|
||
|
||
>>> plan_burn([[0, 0, 0, 0, 0], [0, 2, 2, 0, 0], [0, 0, 0, 1, 0],
|
||
[0, 0, 0, 1, 0], [1, 0, 0, 0, 0]], [[2, 2, 2, 2, 2], [2, 1, 2, 2, 2],
|
||
[2, 2, 2, 2, 2], [2, 2, 2, 1, 2], [2, 2, 2, 2, 2]], 2, (3, 3))
|
||
[(1, 1), (1, 2), (2, 3)]
|