001package edu.pdx.cs410J.whitlock; 002 003import com.google.common.annotations.VisibleForTesting; 004 005import java.io.*; 006 007/** 008 * This class is represents a <code>Student</code>. 009 */ 010public class GameOfLife { 011 012 static final char DEAD_CELL = '.'; 013 private static final char ALIVE_CELL = '*'; 014 015 private char[][] grid; 016 private int nextUnpopulatedRow; 017 private final int rowCount; 018 private final int columnCount; 019 020 public GameOfLife(int rowCount, int columnCount) { 021 this.grid = new char[rowCount][columnCount]; 022 this.nextUnpopulatedRow = 0; 023 this.rowCount = rowCount; 024 this.columnCount = columnCount; 025 } 026 027 /** 028 * Main program that parses the command line, creates a 029 * <code>Student</code>, and prints a description of the gameoflife to 030 * standard out by invoking its <code>toString</code> method. 031 */ 032 public static void main(String[] args) throws InterruptedException, IOException { 033 if (args.length == 0) { 034 System.err.println("** Missing file name"); 035 System.exit(1); 036 } 037 038 String fileName = args[0]; 039 GameOfLife game = readGameFromFile(new File(fileName)); 040 041 while (gameHasLiveCells(game)) { 042 printGame(game); 043 game.computeNextGeneration(); 044 Thread.sleep(1000); 045 } 046 } 047 048 @VisibleForTesting 049 static boolean gameHasLiveCells(GameOfLife game) { 050 for (int row = 0; row < game.getRowCount(); row++) { 051 if (rowContainAliveCell(game, row) != -1) { 052 return true; 053 } 054 } 055 056 return false; 057 } 058 059 private static int rowContainAliveCell(GameOfLife game, int row) { 060 return game.getRow(row).indexOf(GameOfLife.ALIVE_CELL); 061 } 062 063 private static void printGame(GameOfLife game) { 064 for (int row = 0; row < game.getRowCount(); row++) { 065 System.out.println(game.getRow(row)); 066 } 067 068 System.out.println(); 069 } 070 071 private static GameOfLife readGameFromFile(File file) throws IOException { 072 return parseTextFormat(new FileReader(file)); 073 } 074 075 void addRow(String row) { 076 this.grid[this.nextUnpopulatedRow] = row.toCharArray(); 077 this.nextUnpopulatedRow++; 078 } 079 080 void computeNextGeneration() { 081 char[][] newGrid = new char[this.rowCount][this.columnCount]; 082 083 for (int row = 0; row < this.rowCount; row++) { 084 newGrid[row] = new char[this.columnCount]; 085 086 for (int column = 0; column < this.columnCount; column++) { 087 newGrid[row][column] = getNextGenerationCell(row, column); 088 } 089 } 090 091 this.grid = newGrid; 092 } 093 094 private char getNextGenerationCell(int row, int column) { 095 char cell = getCell(row, column); 096 int numberOfLiveNeighbors = getNumberOfLiveNeighbors(row, column); 097 if (cell == ALIVE_CELL) { 098 if (numberOfLiveNeighbors < 2) { 099 return DEAD_CELL; 100 101 } else if (numberOfLiveNeighbors > 3) { 102 return DEAD_CELL; 103 104 } else if (numberOfLiveNeighbors == 2 || numberOfLiveNeighbors == 3){ 105 return ALIVE_CELL; 106 } 107 108 } else { 109 assert cell == DEAD_CELL; 110 111 if (numberOfLiveNeighbors == 3) { 112 return ALIVE_CELL; 113 } 114 } 115 return DEAD_CELL; 116 } 117 118 @VisibleForTesting 119 int getNumberOfLiveNeighbors(int row, int column) { 120 int numberLiveNeighbors = 0; 121 122 for (int i = row - 1; i <= row + 1; i++) { 123 for (int j = column - 1; j <= column + 1; j++) { 124 if (!(i == row && j == column)) { 125 if (cellIsAlive(i, j)) { 126 numberLiveNeighbors++; 127 } 128 } 129 } 130 } 131 132 return numberLiveNeighbors; 133 } 134 135 private boolean cellIsAlive(int row, int column) { 136 if (row < 0) { 137 return false; 138 139 } else if (column < 0) { 140 return false; 141 142 } else if (column >= this.columnCount) { 143 return false; 144 145 } else if (row >= this.rowCount) { 146 return false; 147 148 } else { 149 return getCell(row, column) == ALIVE_CELL; 150 } 151 } 152 153 @VisibleForTesting 154 char getCell(int row, int column) { 155 return this.grid[row][column]; 156 } 157 158 String getRow(int rowIndex) { 159 return new String(this.grid[rowIndex]); 160 } 161 162 @VisibleForTesting 163 int getRowCount() { 164 return rowCount; 165 } 166 167 @VisibleForTesting 168 static GameOfLife parseTextFormat(Reader reader) throws IOException { 169 BufferedReader br = new BufferedReader(reader); 170 171 int rowCount = Integer.parseInt(br.readLine()); 172 int columnCount = Integer.parseInt(br.readLine()); 173 174 GameOfLife game = new GameOfLife(rowCount, columnCount); 175 for (int row = 0; row < rowCount; row++) { 176 game.addRow(br.readLine()); 177 } 178 179 return game; 180 } 181}