Java assignment and the due line is on 16th March 2021. Please take a look at the file attached.

Assignment Overview:

This program is about John Conway’s “Game of Life” (cellular automata). The game of life begins with a 2D array of cells, each of which is alive or dead. The 2D array of cells evolves over a sequence of time ticks as follows: at each time tick, every cell simultaneously transitions to its next state by looking at itself and its (up to) eight neighbors (the cells immediately above, below, either side of it, or diagonally adjacent to it). Here are pictures showing how the neighbors of a cell are defined:

Each cell that is not on an edge of the 2D array (i.e., in the middle) has eight neighbors, like cell c in the following diagram:

c

(The darker cells are the neighbors of c in this diagram.)

  • Each cell that is on an edge of the 2D array (except corner cells) has five neighbors, like cells ct, cr,

cb, and cl in the following diagram:

ct

cr

cl

cb

  • Each corner cell of the 2D array has only three neighbors:

c1

c2

c4

c3

Here are the rules for computing the next state of a cell:

  • If the cell is currently alive and has exactly two or three live neighbors, it is alive after the transition.

If the cell is currently alive but does NOT have exactly two or three live neighbors, it is dead after the transition.

  • If the cell is currently dead and has exactly three live neighbors, then it is alive after the transition.

If the cell is currently dead, but does not have exactly three live neighbors, then it stays dead after the transition.

Here’s a sample sequence of transitions from a starting board to show you how the rules work (the dark cells are alive, and the white cells are dead):

At time tick 0: At time tick 1: At time tick 2: At time tick 3:



Testing Your Code

We have provided sample test files for each phase to help you verify that your code is working to the assignment specifications (e.g., correct method headers). These files are only starting points for testing your code. Part of developing your skills as a programmer is to think through additional important test cases and to write your own code to test these cases. The test files should give you a sense what this additional code could consist of.

Phase 1:

We are going to implement the Game of Life using two-dimensional arrays of ints (called “boards”). Each int in a board is a cell — if the cell is alive, then the corresponding int is 1, and if the cell is dead, then the corresponding int is 0.

At each time tick, all the cells evolve simultaneously — we get a new board. We are going to store all the different boards, starting at time tick 0, in an array of boards — we’re really going to be working with a three-dimensional array of ints. The extra dimension in the array represents time.

In this phase, implement a simple class GameOfLife, which should have:

Two instance variables: the three dimensional array of ints representing the boards over time, and another variable (an int) that contains the current time tick — that is, the variable tells you how many times the starting board at time tick 0) has been evolved so far.

A class (static) method cloneOneBoard that accepts a board (a 2D array of ints) as a parameter and returns a clone (deep copy) of it. Use the following header:

public static int[][] cloneOneBoard( int[][] board )

A constructor that accepts a starting board (a 2D array of ints) and a number, n, of time ticks (an int). The constructor should initialize the 3D array instance variable so that it can hold boards for n time ticks (including the starting board at time tick 0). (You should initialize the instance variable

— but only allocate the time dimension (the first dimension). We will add the boards for various time ticks later.) The current time tick instance variable should be set to 0. Finally, the constructor should also create a clone of the starting board and make the clone be the board at time tick 0 in the 3D array instance variable.

  • Two accessor methods:

    • getCurrentTick, which returns the current time tick — that is, it returns the time tick of the most recently created board stored in the 3D array instance variable.

    • getMaxTick, which returns the time tick that would be associated with the last position in the 3D array instance variable — that is, if we filled up the 3D array instance variable completely, what would be the time tick associated with the last board created?

(Remember: Time tick 0 is the time tick of the starting board.)

An instance method newState that accepts a cell’s current state and the number of live neighbours it currently has. The method should return the new state of the cell after the next time tick, using the rules above. Use the following header:

public int newState( int cellCurrentState, int numLiveNeighbours )

An instance method evolveOnce that first checks if the current time tick is less that the length of the time dimension (the first dimension) of the array of boards — this check ensures that we have room for one more board in the array of boards. If there is room for one more board in the array, then it creates a new board (the same size as the starting board), puts it into the 3D array as the board at the next time tick, transitions all cells (puts their new states into the new board), and increments the current time tick to the new time tick. (If there is no room for one more board in the array of boards, then this method should do nothing.) Use the following header:

public void evolveOnce()

The code to put the new states of the cells into the new boards is too long to all be in one method. So evolveOnce should call smaller helper methods to do parts of the work. Here are some helper methods that you must write for evolveOnce to call. Each helper method is passed references to the current board and the new board, and puts the new states of only some of the cells into the new board:

    • evolveCorners puts the new states of just the corner cells into the new board, based on states in the current board — that is, this method evolves cells that have exactly 3 neighbours. Use the following header:

public void evolveCorners( int[][] currentBoard, int[][] newBoard )

    • evolveEdges puts the new states of just cells on the edges of the board (except for the corner cells) into the new board, based on states in the current board — that is, this method evolves cells that have exactly 5 neighbours. Use the following header:

public void evolveEdges( int[][] currentBoard, int[][] newBoard )

    • evolveMiddle puts the new states of just cells in the middle of the board into the new board, based on states in the current board — that is, this method evolves cells that have exactly 8 neighbours. Use the following header:

public void evolveMiddle( int[][] currentBoard, int[][] newBoard )

Warning: For each of the helper methods, make sure that you look at states in currentBoard (not in

newBoard) when computing the number of live neighbours a cell has.

A toString method that returns a String representation of the most recent board (the current board). Use the current time tick to figure out which board in the array is the most recent board. (Every row should start with 3 blanks and there should be a newline character “\n” between each pair of rows.)

An equals method that accepts a board as a parameter. The method should return true if the current board in the array of boards and the parameter board are the same size and the cells are the same; otherwise, the method should return false.

Note: You should add more helper methods as needed to make the required methods short.

You can test your class using the supplied test program TestA2Phase1.java. You should get the output below.

Phase 1 Testing:

Testing the newState method:

live

cell

with

live

neighbors

will

be

dead

dead

cell

with

live

neighbors

will

be

dead

live

cell

with

live

neighbors

will

be

live

dead

cell

with

live

neighbors

will

be

dead

live

cell

with

live

neighbors

will

be

live

dead

cell

with

live

neighbors

will

be

live

live

cell

with

live

neighbors

will

be

dead

dead

cell

with

live

neighbors

will

be

dead

Now trying multiple evolutions of the whole board: Maximum time tick allowed: 9

At time tick 0: Current time tick = 0

001

111

010

At time tick 1:

Current time tick = 1 001

101

111

At time tick 2:

Current time tick = 2 010

101

101

At time tick 3:

Current time tick = 3 010

101

000

Current time tick at very end: 3

At least one cell still alive (should print true): true

Phase 2:

In this phase, we’re going to read in a starting board from a file. Each line of the file contains exactly one

int, except the first line, which contains exactly two ints. A starting board is stored in a file as follows:

The first row contains the number of rows in the starting board followed by at least one blank followed by the number of columns in the starting board.

The following lines contain the cells (1 for a live cell and 0 for a dead cell), one cell per line, row by row. The cells in row 0 appear first (one per line, starting with column 0), then the cells in row 1 (one per line, starting with column 0), and so on.

For example, consider the following starting board:

It would appear as follows in a file:

3 3

Notice that, in the diagram above, Row 0 is the top row and Row 2 is the bottom row. (Of course, Column 0 is the leftmost column and Column 2 is the rightmost column in the diagram.)

Modify the GameOfLife class as follows:

Add a new instance method readBoard that reads in and returns the starting board stored in the file whose name is in the parameter fileName (see the header below). If anything goes wrong with reading the starting board, this method should simply throw the exception to the calling method — that is, readBoard should not handle exceptions. Use the following header:

public int[][] readBoard( String fileName ) throws IOException

Method readBoard should read the starting board using a BufferedReader.

Once method readBoard has the number of rows and number of columns in the starting board, readBoard should allocate a new two-dimensional array of that size. Then readBoard should read in the cells and put them into the appropriate positions in the new array. Finally, it should return the new array.

You can assume that the number of rows, the number of columns, and the cell states will all be appropriate values in the input file — you don’t have to check them for bad values.

Also add a new constructor to the class, which is very similar to the first constructor you created. This constructor should be passed the name of a file (a String) and a number, n, of time ticks (an int). The constructor should initialize the 3D array instance variable so that it can hold boards for n time ticks (including the starting board at time tick 0). (You should initialize the instance variable — but only allocate the time dimension (the first dimension). We will add the boards for various time ticks later.) The current time tick instance variable should be set to 0. Finally, the constructor should call readBoard to get the starting board from the file, and make the starting board returned by readBoard be the board at time tick 0 in the 3D array instance variable.

Method readBoard may throw an exception. The constructor should not handle any exception thrown by readBoard. Instead, you should add throws IOException to the constructor’s header. Whoever calls this constructor must handle the exception.

You can test your class using the supplied test program TestA2Phase2.java. You should get the output below.

Phase 2 Testing (using file "testFile.txt")

At time tick 0: 001

111

010

At time tick 1: 001

101

111

At time tick 2: 010

101

101

At time tick 3:

010

101

000

At least one cell still alive (should print true): true

Phase 3:

In this phase, we will add the ability to write a sequence of boards (from the starting board to the current time tick) to a file.

Modify the GameOfLife class as follows:

Add a new instance method writeBoardSequence that creates a file whose name is in the parameter fileName (see the header below) and write the boards currently stored in the three-dimensional array instance variable to the file. The method should write out the following to the new file, in the given order, one integer per line (except the second line, which should contain two integers):

    • The number of boards currently stored in the three-dimensional array instance variable on the first line.

    • The number of rows in a board, followed by a blank, followed by the number of columns in a board on the second line.

    • Each of the boards, starting with the starting board and ending with the most recently created board. The cells in each board should be printed out row by row. The cells in row 0 appear first (one per line, starting with column 0), then the cells in row 1 (one per line, starting with column 0), and so on.

There should be no blank lines in the file; there should be one integer per line (except the second line should contain two integers).

If anything goes wrong with writing the sequence of boards, this method should simply throw the exception to the calling method — that is, writeBoardSequence should not handle exceptions. Use the following header:

public void writeBoardSequence(String fileName ) throws IOException

You can test your class using the supplied test program TestA2Phase3.java. It should print

Phase 3 Testing (creating output file "test3File.txt")

on the console and then create a file test3File.txt that contains the following lines:

3 3

1

Hand In
  • Submit your GameOfLife.java file.

  • Make sure your file does not specify a package at the top!

1