11package core .entities ;
22
3+ import java .util .Arrays ;
4+ import java .util .concurrent .atomic .AtomicInteger ;
5+
36public class GameOfLifeRules {
47
58 /**
69 * See class GameOfLifeRules for rules. This method takes a simulated grid and updates the status 1 tick in accordance to the game rules.
710 * @param grid A game of life grid.
11+ * @param iteration a tracker for checking the age of the simulation.
812 * @return The simulated game of life grid one game tick forward.
913 */
10- public boolean [][] applyRulesToGrid (boolean [][] grid ) {
14+ public boolean [][] applyRulesToGrid (boolean [][] grid , AtomicInteger iteration ) {
1115 /*
1216 * To ensure all square updates are applied at the same time we clone the simulated grid.
1317 * This allows for applying the updates in bulk by replacing the simulated grid with the altered grid
1418 * on an event of our choosing.
19+ * Alternatively this could be created as a queue of changes (more work needed). This would allow for
20+ * changes to be streamed and would avoid the need for cloning the original array. This way even a large
21+ * grid could remain responsive. Streaming changes as nodes would also allow for backtracking.
1522 */
16- boolean [][] outputGrid = grid . clone ( );
23+ boolean [][] outputGrid = EntityUtility . deepCopy ( grid );
1724 for (int rowIndex = 0 ; rowIndex < outputGrid .length ; rowIndex ++) {
1825 for (int colIndex = 0 ; colIndex < outputGrid [0 ].length ; colIndex ++) {
19- boolean squareActiveStatus = outputGrid [rowIndex ][colIndex ];
26+ boolean squareActiveStatus = grid [rowIndex ][colIndex ];
2027 int neighborCount = countActiveNeighbors (grid ,colIndex ,rowIndex );
2128 if (squareActiveStatus ) {
2229 // Square is active
2330 switch (neighborCount ) {
2431 case 0 :
2532 case 1 :
2633 // Death by solitude
27- outputGrid [rowIndex ][colIndex ] = applyDeathBySolitude ();
28- break ;
34+ outputGrid [rowIndex ][colIndex ] = applyDeathBySolitude (iteration , colIndex , rowIndex );
35+ continue ;
2936 case 2 :
3037 case 3 :
3138 // Cell survives
32- break ;
39+ continue ;
3340 case 4 :
3441 case 5 :
3542 case 6 :
3643 case 7 :
3744 case 8 :
3845 // Death by overpopulation
39- outputGrid [rowIndex ][colIndex ] = applyDeathByOverPopulation ();
40- break ;
46+ outputGrid [rowIndex ][colIndex ] = applyDeathByOverPopulation (iteration , colIndex ,rowIndex );
4147 }
4248 } else {
4349 // Square is not active
4450 if (neighborCount == 3 ) {
4551 // Cell becomes active
46- outputGrid [rowIndex ][colIndex ] = applyGrowPopulation ();
47- break ;
52+ outputGrid [rowIndex ][colIndex ] = applyGrowPopulation (iteration , colIndex ,rowIndex );
4853 }
4954 }
5055 }
5156 }
57+ iteration .incrementAndGet ();
5258 return outputGrid ;
5359 }
5460
55- private boolean applyDeathBySolitude () {
61+ private boolean applyDeathBySolitude (AtomicInteger iteration , int x , int y ) {
62+ reportToConsole ("Cell killed due to solitude at (" + x + ", " + y + ") during iteration " + iteration .get ());
5663 return false ;
5764 // FIXME: Amend with logic to handle cases around the edges of the boundaries of SIMULATED_GRID.
5865 }
5966
60- private boolean applyDeathByOverPopulation () {
67+ private boolean applyDeathByOverPopulation (AtomicInteger iteration , int x , int y ) {
68+ reportToConsole ("Cell killed due to overpopulation at (" + x + ", " + y + ") during iteration " + iteration .get ());
6169 return false ;
6270 // FIXME: Amend with logic to handle cases around the edges of the boundaries of SIMULATED_GRID.
6371 }
6472
65- private boolean applyGrowPopulation () {
73+ private boolean applyGrowPopulation (AtomicInteger iteration , int x , int y ) {
74+ reportToConsole ("Cell grown at (" + x + ", " + y + ") during iteration " + iteration .get ());
6675 return true ;
6776 // FIXME: Amend with logic to handle cases around the edges of the boundaries of SIMULATED_GRID.
6877 }
6978
79+ /**
80+ * Counts the number of active cells within a 3x3 grid centered on x,y.
81+ * @param grid the simulation grid.
82+ * @param x the center x index
83+ * @param y the center y index
84+ * @return count of active cells within a 3x3 grid centered on x,y
85+ */
7086 private int countActiveNeighbors (boolean [][] grid , int x , int y ) {
7187 int neighborIterator = 0 ;
72- for (int rowIndex = x -1 ; rowIndex <= x + 3 ; rowIndex ++) {
88+ for (int rowIndex = y -1 ; rowIndex <= y + 1 ; rowIndex ++) {
7389 // Indexes outside the scope of the simulation will be treated as dead.
74- if (rowIndex < 0 || rowIndex >= EntityGrid . getEntityGrid (). getGridSize () ){
90+ if (rowIndex < 0 || rowIndex >= grid . length ){
7591 continue ;
7692 }
77- for (int colIndex = y -1 ; colIndex <= y + 3 ; colIndex ++) {
93+ for (int colIndex = x -1 ; colIndex <= x + 1 ; colIndex ++) {
7894 // Indexes outside the scope of the simulation will be treated as dead.
79- if (colIndex < 0 || colIndex >= EntityGrid .getEntityGrid ().getGridSize ()){
95+ // FIXME in certain cases this could result in spaceships that turn on the simulation edge. This shouldn't happen.
96+ if (colIndex < 0 || colIndex >= grid [rowIndex ].length ){
8097 continue ;
8198 }
8299 // Only count neighbor cells so we skip the center of the 3x3
@@ -91,4 +108,8 @@ private int countActiveNeighbors(boolean[][] grid, int x, int y) {
91108 // FIXME: Amend with logic to handle cases around the edges of the boundaries of SIMULATED_GRID.
92109 return neighborIterator ;
93110 }
111+
112+ private void reportToConsole (String s ) {
113+ System .out .println (s );
114+ }
94115}
0 commit comments