The second project was to make a program that would simulate "Conway's Game of Life". This game has a board full of dead and alive cells and they follow the following rules (from Wikipedia):
- Any live cell with fewer than two live neighbours dies, as if caused by under-population.
- Any live cell with two or three live neighbours lives on to the next generation.
- Any live cell with more than three live neighbours dies, as if by over-population.
- Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
The end result is a screen of auto-advancing changing cell patterns.
The first task was to create a Cell class. This would need to store, for each cell, a boolean saying whether it is alive or dead, and a way to change this info. I made methods for both.
The second task was to make a class for the grid that would hold the cells. I made a 2D array of Cell objects, and added the required methods, which did things like returning the total rows and columns, returning the cell at a specific location, and then the annoying one, getNeighbors. Get neighbors would say what the 8 cells in a square around the specified one are. My approach to this last method was basically to make an arraylist within it, change getCell so that it only returned a cell if we are not asking for one less than or greater than the number of rows or columns (important because of the edge cells and such), and then make an entry in the arraylist corresponding to each kind of position in relation to the cell out of the eight. Choosing from an arraylist made it easier, and so the task of making nine if statements to check where the location of the cell was in relation to the entire grid and then returning all neighbors that must exist was made a bit easier.
The third task was to download the provided LandscapeDisplay class and add needed draw methods to both the cell and landscape classes. I just looped through the grid in landscape and called the draw method on each cell. Then I made the actual draw method for a cell, shown below:
I pass in the graphics object, which is where the panel to draw on is, and I make a rectangle for each cell. If it is alive, I make it look different than if it is dead. I have to specify a position and scale, as well.
Task 4 was to make an updateState method for the cell class. I passed in the neighbors and made a list of the ones that were alive by filtering them out. Then, I used if statements to set cells to alive or dead depending on the aforementioned rules.
In Task 5, I made an advance method in the landscape class. My approach to this was to first make a temporary landscape. Then, I copied the state (dead or alive) of the original into the new one. As I did this, I was updating each cell's state based on the original landscape (since working with the same, currently-changing landscape as reference would throw the check off). After I was done, I copied the temporary landscape into the original so it would be displayed. My code for this is the following:
Task 6 was basically to test out the game using a simulation class. In the main method, I displayed the first screen, waited, then repainted it, waited, and repeated this. As an extension, I added command-line input so that the user could decide how many rows/columns to have, and how many iterations of the pattern to have. I had an error message telling the user how to use the program, as well, seen below:
We also had to save the simulation as a gif, included here. Note that this is the "toad" example from wikipedia, used to test that my program works. I made a method for choosing this and also for choosing a random pattern to follow.
As another extension, I was creative with the visual representation in that I added color to the alive cells, had dead cells just be blank instead of empty squares, and let the user decide how big the squares could be, because I was tired of seeing the tiny squares. I imported java.awt.Color and used orange as a fill color rather than the default black. I then made the else statement for the getAlive method in cell not draw anything instead of drawing empty blocks. And to achieve the size change of the blocks, I made another argument in the landscape display class called "blockSize" and had the gridscale get multiplied by that in the constructor class. Here is a picture of a prettier grid:
This project taught me how to use graphics to draw on a screen, and how to save images through java. I also found that I was able to finish it a lot faster and with less help than the last project, so it feels like I'm learning at a good pace. Thinking out how to get the correct neighbors and also how to update the grid was a useful experience.
Thanks to: Melody