Download and extract the contents of this zip file of Python code into the assignment directory on your computer.
Download and save this eclipse project archive file but do not extract it. Copy or move the file into the assignment directory on your computer.
In eclipse, import the project archive using the following steps:
A1_project.zip
Submit your work on onq under Assignment 1. You should upload two files:
ForestFire.java
(counts for 80% of the final grade)Demo.java
(counts for 20% of the final grade)DO NOT upload a zip file containing your work. Doing so greatly slows down the processing of assignments, and you will receive a grade of zero on this assignment if you do so.
Your class should both be in the package soc
(the same package that they appear in in the project file). DO NOT change the package name or remove the package name from your files.
When marking your work the teaching assistants will be looking for the following:
A cellular automaton consists of a regular grid of cells where each cell can be in one of a finite number of states. For example, in John Conway’s famous Conway’s Game of Life each cell is either on or off (alive or dead).
Over time, the state of a cell may change. The way that a cell changes is governed by a set of rules. Mathematicians and scientists have observed that very simple rules are capable of producing surprising behaviour. One example from the Game of Life is the Gosper gliding gun shown below (by Lucas Vieira, license):
In the above example, there are no rules that explicitly describe the pattern of cells that emerge. Instead the pattern is a result of the initial configuration of cells and the rules of The Game of Life.
Mathematicians and scientists have also observed that certain cellular automata exhibit self-organizing criticality. (Very) loosely speaking, self-organizing criticality in a cellular automaton is the phenomenon where an automaton tends to produce some sort of complex behaviour that is insensitive to the initial starting states of the cells. One example of such an automaton is the Forest-fire model.
The Forest-fire model is a very simple model of the evolution of a forest over a long period of time. In the model, the forest is represented by a regular grid of cells where each cell is in one of three possible states:
The lifetime of a tree starts when it is born and the lifetime ends when the tree dies by burning in a forest fire. To update the state of a cell, we apply the following four rules to all cells simultaneously:
An example of the patterns produced by the Forest-fire model are shown below:
In the animated GIF above, empty cells are shown in black, trees are shown in green, and burning cells are shown in red.
Rule #2 of the Forest-fire model requires examining the nearby cells of the cell being updated. There are many ways to define which cells are “near” to another cell. One of the simplest definitions is the Moore neighbourhood.
The Moore neighborhood of a cell is the \(3 \times 3\) region surrounding the cell (including the cell itself). The following image shows the Moore neighbourhood for the cell coloured blue:
For cells located on the edges of the automaton, some cells in the neighborhood are missing. In such cases, we assume the missing cells are empty (contain no tree and is not burning). In the two images below, cells colored red are cells of the neighborhood that are beyond the border of the forest and are assumed to be empty:
In Python, we can represent the state of a cell using something called an enumeration. An enumeration is a set of names that represent a set of related constants, for example:
The Forest-fire model has three states which we can implement as a Python enumeration named state
like so:
# state.py
from enum import Enum
class state(Enum):
= 1
EMPTY = 2
OCCUPIED = 3 BURNING
Using a Python enumeration is simple: write the name of the enumeration (state
) followed by a period (.
) followed by the name of the constant. For example:
from state import state
= state.EMPTY
s = state.BURNING
t if s == t:
print('equal states')
else:
print('different states')
Each row of the Forest-fire model grid is simply a list of state
values. For example:
= [state.EMPTY, state.EMPTY, state.EMPTY, state.OCCUPIED, state.EMPTY] cells
is a row of length \(5\) made up of cells that are empty, empty, empty, occupied by a tree, and empty. If there is more than one row, then we can use a list of lists, which is often called a two-dimensional list. For example:
= [[state.OCCUPIED, state.EMPTY, state.OCCUPIED, state.OCCUPIED, state.OCCUPIED],
cells
[state.OCCUPIED, state.BURNING, state.OCCUPIED, state.OCCUPIED, state.EMPTY], [state.OCCUPIED, state.EMPTY, state.OCCUPIED, state.OCCUPIED, state.OCCUPIED]]
cells
refers to a list of \(3\) rows where each row has length \(5\). cells
actually refers to a list where each element is a list of state
values. For example, we can get the third row of cells like so:
= cells[2] a_row
To access the value of a cell, we use two indexes: A row index, r
, and a column index, c
:
= 0
r = 2
c = cell[r][c] # third element in first row
val # cell[r] is the list representing the first row
The only burning cell in cells
has a row index of 1
and a column index of 1
.
Java also has enumerations, and you use them in a similar way as in Python. An enumeration in Java is a special kind of class so we name our Java enumeration State
:
// State.java
package soc;
public enum State {
EMPTY,
OCCUPIED,
BURNING }
// StateDemo.java
package soc;
public class StateDemo {
public static void main(String[] args) {
State s = State.EMPTY;
State t = State.BURNING;
// print states
System.out.println(s); // prints EMPTY
System.out.println(t); // prints BURNING
// test if states are equal
if (s == t) {
System.out.println("equal states");
}else {
System.out.println("different states");
}
} }
In Java, we can use a two-dimensional array of State
values to represent a Forest-fire grid. For example:
State[][] cells = {
State.OCCUPIED, State.EMPTY, State.OCCUPIED, State.OCCUPIED, State.OCCUPIED},
{State.OCCUPIED, State.BURNING, State.OCCUPIED, State.OCCUPIED, State.EMPTY},
{State.OCCUPIED, State.EMPTY, State.OCCUPIED, State.OCCUPIED, State.OCCUPIED}
{ };
cells
refers to a two-dimensional array having \(3\) rows and \(5\) columns. cells
actually refers to an array where each element is an array of State
values. For example, we can get the third row of cells like so:
State[] aRow = cells[2];
To access the value of a cell, we use two indexes: A row index, r
, and a column index, c
:
int r = 0;
int c = 2;
boolean val = cells[r][c]; // third element in first row
// cells[r] is the array representing the first row
The only burning cell in cells
has a row index of 1
and a column index of 1
.
In Java, we can make a new two-dimensional array in the same way that we make a new one-dimensional array:
int numRows = 10;
int numCols = 8;
State[][] cells = new State[numRows][numCols];
In the above example, all of the array elements will be set to null
which means that each element refers to no object. It is up to the programmer to replace each element with a State
object.
We can loop over all of the elements of the array using a pair of nested loops. For example, we can set each element of cells
to State.EMPTY
like so:
int numRows = 10;
int numCols = 8;
State[][] cells = new State[numRows][numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
State.EMPTY;
cells[r][c] =
} }
In the A1_python_code.zip
file, you will find three files that are already complete (you should not edit these in this assignment):
state.py
forest_fire.py
demo.py
state.py
is a module that defines the state
enumeration.
forest_fire.py
is a module that contains functions that are fundamental to the Forest-fire model.
demo.py
is a small Python program that calls the functions in the forest_fire
module and prints the output to the terminal.
Your task is to translate the functions in forest_fire.py
to their corresponding Java methods in the class ForestFire.java
, and to translate demo.py
into a main
method in the class Demo.java
.
In the Java project file that you have imported into eclipse, you will find five files:
State.java
(complete)StateDemo.java
(complete)ForestFireIndexException.java
(complete)ForestFire.java
(incomplete)Demo.java
(incomplete)State.java
is the already completed implementation of the State
enumeration.
StateDemo.java
is the already completed implementation of a main
method that uses the State
enumeration. You might want to refer to this program for examples of how to use the State
enumeration.
ForestFireIndexException.java
is the already completed implementation of a class that represents an exception (see below).
ForestFire.java
is the partially completed implementation of the ForestFire
class.
Demo.java
is the partially completed implementation of the Demo
class.
Your task is to:
forest_fire.py
into the methods in ForestFire.java
demo.py
into the main
method of Demo.java
The Python program is written in such a way that you can almost translate each line of Python into the equivalent line of Java.
Notice that the Python function names are not conventional Java method names. When you translate a function to a method, you must make sure that you use the usual Java convention for naming. For the example, the Python function:
def is_burning(cells, row, col)
must be be translated to the Java method:
public static boolean isBurning(State[][] cells, int row, int col)
(observe that the name of the method is in lower camelCase and has no underscores in it).
When you translate a function, you must not change the order of the parameters. Whoever grades your assignment will be using an already created test program that assumes you have correctly translated each Python function so that it has the expected Java method name and the parameters in the same order.
Many functions have certain conditions on the inputs to the function. For example, the Python function math.sqrt
requires that the input to the function be a non-negative numeric value. When writing a function that has conditions on its inputs, it is often good programming practice to test if the conditions are satisfied before proceeding. If the conditions are not satisfied, then the programmer may choose to raise an exception.
In Python, raising an exception involves creating an exception object and then using the raise
keyword to pass the exception object to the Python interpreter. In the module forest_fire.py
you will find a few instances that resemble the following:
if some_condition:
raise ValueError()
In the example above, a ValueError
exception object is created and passed to the interpreter. There are many choices for the type of exception object, but only ValueError
is used in this assignment.
A function stops running when an exception is raised. Unless the caller handles the exception, the program will stop running and an error message will be printed.
Exceptions are similar in Java except that Java uses the terminology “to throw an exception”. Where a Python function raises a ValueError
, your Java method should throw a ForestFireIndexException
:
if (some_condition) {
throw new ForestFireIndexException();
}
Demo.java
After implementing ForestFire.java
, you should complete the implementation of the main
method in Demo.java
. It should repeat all of the same steps as the Python program demo.py
and should produce the following output:
number of rows = 3
number of columns = 5
index ok? = true
index ok? = false
index ok? = false
copy = [[OCCUPIED, EMPTY, OCCUPIED, OCCUPIED, OCCUPIED], [OCCUPIED, BURNING, OCCUPIED, OCCUPIED, EMPTY], [OCCUPIED, EMPTY, OCCUPIED, OCCUPIED, OCCUPIED]]
T-TTT
T#TT-
T-TTT
T-T
T#T
T-T
T--
TT-
---
is burning = false
is burning = false
T#
#-
num burning = 2
When printing a two-dimensional array, you can use the method Arrays.toDeepString
to the get the string representation of the array (Arrays.toString
works only for one-dimensional arrays).
You do not need to document your code for this assignment. Later assignments will have you writing proper Java documentation.
In Assignment 2, we will complete the implementation of the Forest-fire model.