Course web page: Introduction to Computer Science for non-majors II James Tam Return to the course web page

CPSC 219: Assignment 3

Due Tue Mar 7 at 4 PM


The "Game of Life" is a biological simulation created by John Conway and consists of a "biosphere" that is divided into cells. Each cell is inhabited by a life form that I will refer to as "the Critter".  Critters will live or die depending upon a simple set of rules (described below). 


They can be found either through the UNIX course directory: /home/219/assignments/assignment3 or the [shortcut web link]. It will include some starting code: "" and a parts of "", "", "". The starting code just initializes the 7 biospheres and displays them. You will of course need to modify the starting code significantly to fulfill the requirements of the assignment. Also you will find a few text files that show sample runs of some of the more complex biosphere's and some sample debugging messages in the assignment directory or via the [shortcut web link]

Assignment description

For this assignment the biosphere is simulated with a 10  x 10 array of 'Critters' (Figure 1). Empty elements will be displayed as spaces (a 'Critter' object whose appearance is set to a space), while elements containing a 'Critter' will either appear as a '*' (Regular Critter) or a '!' (Fertile Critter). Any of the 100 squares can contain a Critter. The simulation will begin with the Critters in some starting pattern as selected by the user (Figure 1: Top). I suggest that you start by using the simpler biospheres first and work your way up to the more complex ones.   The more biospheres that your program can properly handle, the higher your grade will be. After initializing the starting positions, the program will simulate the births and deaths of the critters over time on a turn-by-turn basis. The user can either hit <enter> to run another turn, 'q' or 'Q' to end the simulation. To help you test/debug your program you should make use of the 'Mode' class (described below). Debug mode can be toggled by entering 'd' or 'D' when prompted to proceed to another turn.

Figure 1: A time unit passing in the simulation (from 'previous' to 'current' generation)

For each turn that passes your program must scan the entire biosphere:

  1. Squares that currently contain a critter: the program determines which critters die and which critters are unaffected by the turn change.
  2. Squares that are currently empty: the program determines if a new critter will be born into a square.

The births and deaths of critters is based solely upon the number of neighbors. You are to assume that all births and deaths occur simultaneously. Thus you need two arrays of type Critter. One array, which I refer to as 'previous' in "", contains the positions of the critters previous to the turn and is used to determine how many critters neighbor a particular square.  The second array, which I call 'current' in "", will initially contain the same pattern of critters as the other array.  As the program scans the previous array, critters will die from and be born into the 'current' array.  Make sure that you do not change the pattern of critters of the previous array while you are scanning  because as I said earlier, births and deaths occur simultaneously.

Birth and death conditions for Critters:

1) If a square contains a critter:

a) The critter will die if:  (i) It has 0 or 1 neighbors - it dies of loneliness    (ii) It has 4 to 8 neighbors - it dies of overcrowding. 

b) The critter will go on living as-is (won't die) if it has 2 - 3 neighbors.

2) If the square is empty: a critter will be born there if it has exactly 3 neighbors. (Fertile critters count as two neighbors)

How do you determine the neighbors for a particular critter? Picture the following two-dimensional array that is a subset of the biosphere array:


The square marked with an "X" is a square where we are trying to determine if a birth or death will occur.  In the cases below I will use a "*" (star) to represent the neighboring critters.  The squares that you need to scan will be the squares adjacent to the square in middle (i.e., above, below, left side, right side, and the four diagonals).  Note: In the examples below I assume that the square to be scanned is an inner square, you will have to write up the exceptional conditions for other cases (e.g., the top and bottom rows, far left and far right columns as well as the four corners).

e.g. 1, (critter already in square to be scanned) - critter dies of loneliness (no neighbors or just one neighbor).

No neighbors                                                                              One neighbor

e.g. 2, (critter already in square to be scanned) - critter dies from overcrowding (in this example the critter has four neighbors - it also dies if there are more than four neighbors) 

Four neighbors

e.g. 3, (empty square) - critter will born into the empty square because there is exactly 3 neighbors. 

Empty square (critter born)

e.g. 4, (critter already in square to be scanned) - no change to the critter (two or three neighbors)

Two neighbors

How does all of this scanning relate to the 10 x 10 biosphere? You must perform a neighbor count for each of the 100 squares. 

Fertile Critters '!':

When counting neighbors to determine births, Fertile Critters are counted as two critters.  When counting neighbors to determine deaths Fertile Critters are counted as one neighbor just like Regular Critters. Except for determining births Regular and Fertile critters are treated identically. The location of Fertile critters is fixed when the program starts. Critters cannot change from one state to another. The only type of critters that can be born into the simulation are Regular (and not Fertile) Critters.

Required classes for this program:

UserInterface: similar to the class with the same name covered by the TAs in tutorial which can be found at [this link] or in UNIX under /home/219/tutorials/jan29_feb4/userInterface is responsible for all input and output. e.g., displaying the initial menu (biosphere selection), getting user input and the end of each turn, determining if the user's selection was valid/determining which option was selected.

Mode: Its sole purpose is to determine if the program is operating in debugging mode. By default the program will not be operating in debugging mode.

public class Mode {
     public static boolean debug = false;

When the program is in debugging mode, messages about the state of the program will be displayed. The exact content of the messages is left to your discretion but this mode should be implemented early on to aid in testing/debugging. Example debugging message:  if debug mode is on when checking for births the program could display the (row/column) being checked, the neighbor count and if a birth will occur at that location. (You can then compare the resulting debugging messages vs. the values you expect from manually tracing your program).

method () {
     // Toggle debug mode
    if (Mode.debug == false)
          Mode.debug = true; // Same logic to toggle debugging to off.

    // Example of displaying debugging messages only when the program is in debug mode
   if (Mode.debug == true)
         System.out.println("<<< This is a purely simulated debugging message >>>");

Unlike the other classes this class can be purely static (it need not be instantiated). More details to be provided in lecture "Advanced Java" section (so don't miss it or make sure you get the notes from someone if you can't attend).

Critter: Instances of this class will store information about each critter. At an absolute minimum your implementation of the Critter class must include an attribute that is used to store information about the critter's appearance 

e.g., private char appearance;

Whenever the your program runs through the loops to display individual squares of the biosphere, the character that is displayed for a particular square will be determined by the appearance of the critter (star, exclamation mark or a space) i.e., the Biosphere's 'display()' method will call the Critter classes' appropriate 'display()' method for each square in the biosphere.

Biosphere: This class will store information about the simulated world (not coincidentally called a 'biosphere'). As noted the biosphere will take the form of an array of references to Critter objects. All data and actions directly related to the simulation world will be the attributes and methods of this class. One important task that should be handled by this class will be the maintenance of the biosphere: scanning the squares in order to determine where Critters will be born and where they will die.  Break down this main task into sub-methods as much as possible e.g., the main job of scanning the biosphere should be broken down into smaller jobs such as: i) scanning the inner parts of the biosphere (rows 1 - 8 and columns 1- 8 = 64 squares) ii) scanning the top row only (row=0) iii) scanning the bottom row (row=9) iv) scanning the left-most column (column=0) v) scanning the right-most column (column=9) vi) scanning the four corners.  Your grade could be adversely affected because of the loss of style marks if you only implemented one very large method that handled all the above tasks.

GameOfLife: The 'Driver' for the program that should contain a reference to the user interface class:

public static void main (String [] args) {
    UserInterface anInterface = new UserInterface ();
                 :                        :       


Note: the starting driver in the assignment directory only implements very bare bones functionality. Because it has no user interaction (runs simulation for only one turn) it directly instantiates a biosphere in main(). You should re-write the driver so an interface is instantiated here and the user interface class instantiates and calls methods of class "Biosphere".

UML class diagram

You should create a UML diagram for class "Biosphere" and class "Critter". The diagram should be the 'full' version and show parameters and return values of methods as well the relationship between the two classes plus multiplicity (see the notes which introduce Object-Oriented concepts). The class diagram can be drawn using any structured drawing program (even PowerPoint). However it must be correct and it must be understandable by the marker. The image that you submit via D2L must be in one of the following formats: 'gif', 'jpg', 'png', 'pdf'' and of course PowerPoint.

Using pre-written Java code

You will need to use the built in code class Scanner for input. And of course you must use the starting code in the A3 directory: /home/219/assignments/assignment3/code. Beyond that (and common sense operators and functions such as those for output and mathematical operators), unless you told otherwise, you will need to write your own code and cannot use other pre-written Java classes or operators (as usual and specified below: Point #7)

Points to keep in mind:

  1. Due time: All assignments are due at 4 PM on the due dates listed on the course web page.  Late assignments or components of assignments will not be accepted for marking without approval for an extension beforehand. The latest versions of the files that you have submitted in D2L as of the due date is what will be marked.
  2. Extensions may be granted for reasonable cases by the course instructor with the receipt of the appropriate documentation (e.g., a doctor's note). Typical examples of reasonable cases for an extension include: illness or a death in the family. Cases where extensions will not be granted include situations that are typical of student life: having multiple due dates, work commitments etc. Tutorial instructors (TA's) will not be able to provide extension on their own and must receive permission from the course instructor first. (Note: Forgetting to hand your assignment or a component of your assignment in does not constitute a sufficient reason for handing your assignment late).
  3. Method of submission: You are to submit your assignment using D2L [help link]. Make sure that you [check the contents of your submitted files] (e.g., is the file okay or was it corrupted, is it the correct version etc.). It's your responsibility to do this! (Make sure that you submit your assignment with enough time before it comes due for you to do a check).
  4. Identifying information: All assignments should include contact information (full name and student ID number) at the very top of your program in the class where the 'main()' method resides. (Note other documentation is also required for most assignments).
  5. Collaboration: Assignments must reflect individual work; group work is not allowed in this class nor can you copy the work of others.  For more detailed information as to what constitutes academic misconduct (i.e., cheating) for this course please read the following [link].
  6. Execution: programs must run on the computer science network running Java 8.x. If you write you code in the lab and work remotely using a remote login program such as Putty or SSH then should already be using the correct version. If you choose to install Java on your own computer, then it is your responsibility to ensure that your program will run properly on the CPSC Linux computers. It's not recommended that you use an IDE for writing your programs but if you use one then make sure that you submit your program in the form of text ".java" file or files. If you only submit your byte code files (e.g. Driver.class) then you will not be awarded any credit.
  7. Use of pre-created Java libraries: unless otherwise told you are to write the code yourself and not use any pre-created functions from the Java libraries. For this assignment the usual acceptable functions include: System.out.print(), System.out.println(), the methods of the Console class and for some assignments the methods of the Random class. Look at the particular assignment description for a list of other classes that you are allowed to use and still get credit in an assignment submission.
  8. Style conventions, programming decomposition: the marking points from the previous assignment also apply to this assignment. The one blanket exception is the use of a static debugging flag (or flags) if you choose to implement multiple flags.

D2L configuration:


You will likely find this assignment fairly challenging so here are some [tips].