/** * ConwayLife.java * The Game of Life is ideally played on an infinite two-dimensional orthogonal grid of * square cells, each of which is in one of two possible states, alive or dead, or * "populated" or "unpopulated". Every cell interacts with its eight neighbours, which * are the cells that are horizontally, vertically, or diagonally adjacent. At each step * in time, the following transitions occur: * (1) Any live cell with fewer than 2 live neighbours dies, as if caused by underpopulation. * (2) Any live cell with 2 or 3 live neighbours lives on to the next generation. * (3) Any live cell with more than 3 live neighbours dies, as if by overpopulation. * (4) Any dead cell with exactly 3 live neighbours becomes a live cell, as if by reproduction. * The initial pattern constitutes the seed of the system. The first generation is created by * applying the above rules simultaneously to every cell in the seed - births and deaths occur * simultaneously, and the discrete moment at which this happens is sometimes called a tick * (in other words, each generation is a pure function of the preceding one). The rules * continue to be applied repeatedly to create further generations. * @author Your Name Here * @version 1.0 * @since 1/8/2017 */ import java.util.Scanner; import java.awt.Color; import java.awt.Font; public class ConwayLife { /** The board object. If a cell is alive, the value of the cell is true, and if * the cell is dead, the value of the cell is false. */ private boolean [][] board; /** The number of rows for the board. Since the board is square, this is also the * number of columns for the board. */ private final int NUMBEROFROWS = 150; /** The edge length, to give the entire board a frame. */ private final double EDGE = 0.02; /** Since the side length is 1, this SIDE will use everything but the edge for the * drawing area. */ private final double SIDE = 1 - 2 * EDGE; /* The width of an individual cell. */ private final double CELLWIDTH = SIDE / NUMBEROFROWS; /** * Creates a ConwayLife object, with a sized graphics canvas, and a 2D array * of boolean values, with all of them set to false (no live cells) to start with. */ public ConwayLife ( ) { StdDraw.setCanvasSize(800, 800); board = new boolean [NUMBEROFROWS][NUMBEROFROWS]; for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[i].length; j++) { board [i][j] = false; } } } /** * Sets up and runs the game of Conway's Life. * @param args An array of String arguments (the user can pass the name * of a text file that indicates the live cells to start with). If no argument * is entered, "p1.txt" is the text file used by default. */ public static void main(String [] args) { String textFile = "p1.txt"; if(args.length > 0) { textFile = args[0]; } ConwayLife life = new ConwayLife(); life.initializeLife(textFile); life.runLife(); } public void initializeLife(String textFile) { Scanner infile = OpenFile.openToRead(textFile); String temp = null; int col = 0; while(infile.hasNext()) { temp = infile.nextLine(); for(int row = 0; row < temp.length(); row++) { if(temp.charAt(row) == '*' && row < board.length && col < board[row].length) { board[row][col] = true; } } col++; } infile.close(); /* Scanner infile = OpenFile.openToRead(textFile); // This block of code could be used int row = 0, col = 0; // to read in ordered pairs for live while(infile.hasNext()) // cells from a text file. { row = infile.nextInt(); col = infile.nextInt(); board[row][col] = true; } infile.close(); */ // int aliveCells = 2000; // This block of code could be used to // for(int i = 0; i < aliveCells; i++) // generate a random configuration of // { // live cells. // int randomRow = (int)(Math.random() * board.length); // int randomCol = (int)(Math.random() * board[0].length); // board[randomRow][randomCol] = true; // } } /** * Runs a loop to show 1200 generations of Conway's Life. */ public void runLife ( ) { int gencount = 0; StdDraw.show(10); while(gencount <= 1200) { showLife(gencount); generateNext(); if(gencount == 0) { StdDraw.show(500); } else { StdDraw.show(50); } gencount++; } } /** * Draws the current generation of Conway's Life to the canvas. * @param gencount The number of the current generation. */ public void showLife(int gencount) { StdDraw.setPenColor(new Color(0,0,0)); StdDraw.filledSquare(0.5,0.5,0.5); StdDraw.setPenColor(new Color(255,255,255)); StdDraw.filledSquare(0.5,0.5,SIDE/2); for ( int i = 0; i < board.length; i++ ) { for ( int j = 0; j < board[i].length; j++ ) { if(board[i][j] == true) { StdDraw.setPenColor(new Color(255,0,0)); StdDraw.filledSquare(EDGE + CELLWIDTH * i + CELLWIDTH/2, EDGE + CELLWIDTH * j + CELLWIDTH/2, CELLWIDTH / 2.0); } } } StdDraw.setPenColor(new Color(0,0,0)); StdDraw.text(0.04, 0.96, "" + gencount); } /** * Uses the rule for Conway's Life to generate the next generation (see the comment * block at the top of this class). The next generation if saved in a new 2D array, * and, once created, is used to replace the previous generation (previous 2D array). */ public void generateNext ( ) { boolean [][] nextboard = new boolean [board.length][board[0].length]; for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[i].length; j++) { if(countNeighbors(i, j) > 0) // Apply the rules { // here, by changing/modifying nextboard[i][j] = true; // this if . . . } } } board = nextboard; } /** * Counts the neighbors of a given cell, identified by row and col. The special * cases of edges and corners must be considered. * @param row The row of the current cell. * @param col The column of the current cell. */ public int countNeighbors(int row, int col) { int neighborcount = 0; if(board[row][col] == true) { neighborcount++; } return neighborcount; // for(int i = -1; i <= 1; i++) // This nested loop template // { // is here to help you // for(int j = -1; j <= 1; j++) // get started. // { // } // } } }