Results 1 to 4 of 4
  1. #1
    unreal4evr is offline Member
    Join Date
    Mar 2009
    Posts
    4
    Rep Power
    0

    Default A more efficient Game of Life

    Hello, this is my first post to Java Forums, so hopefully all goes well.

    I've finished implementing the code for a 2D boolean array-based implementation for John Conway's Game Of Life. The program functions properly (without-errors) under all conditions, however I would like to improve it's effiicency.

    I've pasted the section of the code in question below. This will probably make most experienced programmers laugh or cry, but I am beginner, so that's to be expected.

    What I'm looking for is some detailed and specific ways to improve the code to make it less stressful on the CPU, and make it easier to read. In particular, I'm looking for ways to get rid of the excessive if statements for neighbor checking, and to reduce the number of cells checked by the nextGeneration methods (to only cells that will be subject to surviving, dying, or being vivified).


    ALIVE and DEAD are boolean constants that correspond to true and false respectively.
    MAX_ROWS and MAX_COLS are int constants defining he limits of the grid (array size).

    Java Code:
    // copyMap:
        // Precondtions: None.
        // Postcondtion: 'map' is a deep copy of 'sourceMap'.
        //
        private void copyMap(boolean sourceMap[][]) {
            for(int r = 0; r < MAX_ROWS; r++){
            	for(int c = 0; c < MAX_COLS; c++){
            		map[r][c] = sourceMap[r][c];
            	}
            }
    
        }
    
        // clearMap:
        // Precondtions: None.
        // Postcondtion: Sets all cells of the 'targetMap' to DEAD.
        //
        private void clearMap(boolean targetMap[][]) {
        	 for(int r = 0; r < MAX_ROWS; r++){
             	for(int c = 0; c < MAX_COLS; c++){
             		targetMap[r][c] = DEAD;
             	}
             }
    
        }
    
        //  getFlatNeighborCount:
        //  Precondtions:  0 <= row < MAX_ROWS and 0 <= col < MAX_COLS.
        //  Postcondtion:  A count of all LIVE neighbors of the cell at [row, col] is
        //                 returned where its neighbors are all the ADJACENT cells
        //                 including those
        //                 a) In the rows BELOW and ABOVE the cell (if any exist).
        //                 b) In the columns LEFT and RIGHT of the cell (if any exist).
        //                 Thus, a cell adjacent to a board edge (or corner) has
        //                 fewer neighbors than other cells.
        //
        private int getFlatNeighborCount(int row, int col){
            int count = 0;
            if(row - 1 >= 0 && map[row - 1][col]){
            	count++;
            }
            if(row + 1 < MAX_ROWS && map[row + 1][col]){
            	count++;
            }
            if(col - 1 >= 0 && map[row][col - 1]){
            	count++;
            }
            if(col + 1 < MAX_COLS && map[row][col + 1]){
            	count++;
            }
            if((row - 1 >= 0 && col - 1 >= 0) && map[row -1][col -1]){
            	count++;
            }
            if((row - 1 >= 0 && col + 1 < MAX_COLS) && map[row - 1][col + 1]){
            	count++;
            }
            if((row + 1 < MAX_ROWS && col - 1 >= 0) && map[row + 1][col -1]){
            	count++;
            }
            if((row + 1 < MAX_ROWS && col + 1 < MAX_COLS) && map[row + 1][col + 1]){
            	count++;
            }
            return count;
        }
    
    
        // nextGenerationForFlatGrid:
        // Precondtions: None
        // Postcondtion: The next generation of live and dead cells is calculated using
        //               a) the FLAT neighbor counts.
        //               b) the current birth, survival and death count rules.
        //               c) the rules are applied to the counts obtained from the current
        //                  generation's configuration of live and dead cells.
        //               The current 'map' is updated to the next generation's configuration
        //               of live and dead cells.
        //		     d) the global variable 'generation' is increased by 1
        //	
        public  void nextGenerationForFlatGrid() {
        	for(int row = 0; row < MAX_ROWS; row++){
             	for(int col = 0; col < MAX_COLS; col++){
             		int neighborCount = getFlatNeighborCount(row, col);
             		if(!map[row][col] && neighborCount == 3){
             			newMap[row][col] = ALIVE;
             		}
             		else if(map[row][col] && (neighborCount == 2 || neighborCount == 3)){
             			newMap[row][col] = ALIVE;
             		}
             		else if(map[row][col] && neighborCount <= 1){
             			newMap[row][col] = DEAD;
             		}
             		else if(map[row][col] && neighborCount >= 4){
             			newMap[row][col] = DEAD;
             		}
             	}
             }
        	copyMap(newMap);
        	clearMap(newMap);
        	generation++;
        }
        
    
    
    
        // ==> 5. Implement the game of life for torus grid.
        
         /**getTorusNeighborCount
         *   Preconditions:  0 <= row < MAX_ROWS and 0 <= col < MAX_COLS.
         *   Postconditions: The count is increased for each living adjacent neighbor.
         *    This counts only neighbors located on adjacent edges of the grid.
         *    The count is returned when finished.
         */
        public int getTorusNeighborCount(int row, int col){
        	int count = 0;
        	if((row == MAX_ROWS - 1) && map[0][col]){
        		count++;
        	}
        	if((row == MAX_ROWS - 1 && col > 0) && map[0][col - 1]){
        		count++;
        	}
        	if((row == MAX_ROWS - 1 && col < MAX_COLS - 1) && map[0][col + 1]){
        		count++;
        	}
        	if(row == 0 && map[MAX_ROWS - 1][col]){
        		count++;
        	}
        	if((row == 0 && col > 0) && map[MAX_ROWS - 1][col - 1]){
        		count++;
        	}
        	if((row == 0 && col < MAX_COLS - 1) && map[MAX_ROWS - 1][col + 1]){
        		count++;
        	}
        	if((col == MAX_COLS - 1) && map[row][0]){
        		count++;
        	}
        	if((col == MAX_COLS - 1 && row > 0) && map[row - 1][0]){
        		count++;
        	}
        	if((col == MAX_COLS - 1 && row < MAX_ROWS - 1) && map[row + 1][0]){
        		count++;
        	}
        	if((col == 0) && map[row][MAX_COLS - 1]){
        		count++;
        	}
        	if((col == 0 && row > 0) && map[row - 1][MAX_COLS - 1]){
        		count++;
        	}
        	if((col == 0 && row < MAX_ROWS - 1) && map[row + 1][MAX_COLS - 1]){
        		count++;
        	}
        	if((row == 0 && col == 0) && map[MAX_ROWS - 1][MAX_COLS - 1]){
            	count++;
            }
        	if((row == MAX_ROWS - 1 && col == 0) && map[0][MAX_COLS - 1]){
        		count++;
        	}
        	if((row == 0 && col == MAX_COLS - 1) && map[MAX_ROWS - 1][0]){
        		count++;
        	}
        	if((row == MAX_ROWS - 1 && col == MAX_COLS - 1) && map[0][0]){
        		count++;
        	}
        	return count;
        }
    
        /** nextGenerationForTorusGrid()
         * Precondition: None
         * Postcondition: The grid is updated utilizing the FLAT and TORUS neighbor counts.
         * The same birth, survival and death rules apply as with the next FLAT generation.
         * The generation variable is increased by 1.
         * 
         */
        public  void nextGenerationForTorusGrid() {
        	for(int row = 0; row < MAX_ROWS; row++){
             	for(int col = 0; col < MAX_COLS; col++){
             		int neighborCount = getFlatNeighborCount(row, col) + getTorusNeighborCount(row, col);
             		if(!map[row][col] && neighborCount == 3){
             			newMap[row][col] = ALIVE;
             		}
             		else if(map[row][col] && (neighborCount == 2 || neighborCount == 3)){
             			newMap[row][col] = ALIVE;
             		}
             		else if(map[row][col] && neighborCount <= 1){
             			newMap[row][col] = DEAD;
             		}
             		else if(map[row][col] && neighborCount >= 4){
             			newMap[row][col] = DEAD;
             		}
             	}
             }
        	copyMap(newMap);
        	clearMap(newMap);
        	generation++;
        }
    Sorry if the brackets aren't lining up, for some reason it's not pasting properly..... :(

  2. #2
    emceenugget is offline Senior Member
    Join Date
    Sep 2008
    Posts
    564
    Rep Power
    6

    Default

    you can tack some of your if-statements together to if-else if-else statements. no reason to check if row == max_rows if we already confirmed row == 0, and so forth. you can also nest them, so you don't have to keep checking if row == 0 until we find out that col == max_cols.

    all-in-all, improvements on your code will help you towards better coding behavior that will make larger programs you make be more efficient. but this one is too simple to experience a notable lag. unless your board is insanely large.

  3. #3
    unreal4evr is offline Member
    Join Date
    Mar 2009
    Posts
    4
    Rep Power
    0

    Default

    Ahh, that's true. When I wrote this I simply split the grid up into sections where neighbors would be, and wrote an if statement for each possibility.
    I didn't consider the else's since I wanted to make sure the program didn't miss any case. I usually write if-else's for efficiency too.

    Thanks!

  4. #4
    unreal4evr is offline Member
    Join Date
    Mar 2009
    Posts
    4
    Rep Power
    0

    Default

    Ok, here's my re-worked code for the flat and torus neighbor counts.
    I nested my statements for the flat and torus, and also used Math.abs() to cut my statements for torus in half, making it easier to read.

    Thanks again for the help!!

    Java Code:
        //  getFlatNeighborCount:
        //  Precondtions:  0 <= row < MAX_ROWS and 0 <= col < MAX_COLS.
        //  Postcondtion:  A count of all LIVE neighbors of the cell at [row, col] is
        //                 returned where its neighbors are all the ADJACENT cells
        //                 including those
        //                 a) In the rows BELOW and ABOVE the cell (if any exist).
        //                 b) In the columns LEFT and RIGHT of the cell (if any exist).
        //                 Thus, a cell adjacent to a board edge (or corner) has
        //                 fewer neighbors than other cells.
        //
        private int getFlatNeighborCount(int row, int col){
            int count = 0;
            if(row - 1 >= 0){
            	if(map[row - 1][col]){
            	count++;
            	}
            	if(col - 1 >= 0 && map[row - 1][col -1]){
            	count++;
            	}
            	
            }
            if(row + 1 < MAX_ROWS){
            	if(map[row + 1][col]){
            	count++;
            	}
            	if(col + 1 < MAX_COLS && map[row + 1][col + 1]){
            	count++;
            	}
            }
            if(col - 1 >= 0){
            	if(col - 1 >= 0 && map[row][col - 1]){
            	count++;
            	}
            	if(row + 1 < MAX_ROWS && map[row + 1][col - 1]){
            	count++;
            	}
            }
            if(col + 1 < MAX_COLS){
            	if(map[row][col + 1]){
            	count++;
            	}
            	if(row - 1 >= 0 && map[row - 1][col + 1]){
            	count++;
            	}
            }
            return count;
        }
    
        // ==> 5. Implement the game of life for torus grid.
        
         /**getTorusNeighborCount
         *   Preconditions:  0 <= row < MAX_ROWS and 0 <= col < MAX_COLS.
         *   Postconditions: The count is increased for each living adjacent neighbor.
         *    This counts only neighbors located on adjacent edges of the grid.
         *    The count is returned when finished.
         */
        public int getTorusNeighborCount(int row, int col){
        	if((row == 0 || row == BOTTOM) || (col == 0 || col == FAR_RIGHT)){
    	    	int count = 0;
    	    	final int ROW_EDGE = Math.abs(row - BOTTOM);
    	    	final int COL_EDGE = Math.abs(col - FAR_RIGHT);
    	    	if(row == BOTTOM || row == 0){
    		    	if(map[ROW_EDGE][col]){
    		    		count++;
    		    	}
    		    	if(col > 0 && map[ROW_EDGE][col - 1]){
    		    		count++;
    		    	}
    		    	if(col < FAR_RIGHT && map[ROW_EDGE][col + 1]){
    		    		count++;
    		    	}
    		    	if(map[ROW_EDGE][COL_EDGE]){
    		    		count++;
    		    	}
    	    	}
    	    	else{
    			if(map[row][COL_EDGE]){
    				count++;
    		    	}
    		    	if(row > 0 && map[row - 1][COL_EDGE]){
    		    		count++;
    		    	}
    		    	if(row < BOTTOM && map[row + 1][COL_EDGE]){
    		    		count++;
    		    	}
    		    	if(map[ROW_EDGE][COL_EDGE]){
    		    		count++;
    		    	}
    	    	}
    	    	return count;
        	}
        	else{
        		return 0;
        	}
        }

Similar Threads

  1. Efficient Perfect Number
    By Lite3864 in forum New To Java
    Replies: 4
    Last Post: 11-23-2008, 01:07 AM
  2. Game of Life assignment
    By javan00b in forum New To Java
    Replies: 4
    Last Post: 04-28-2008, 05:49 AM
  3. Servlet Life Cycle
    By Java Tip in forum Java Tip
    Replies: 0
    Last Post: 11-28-2007, 09:57 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •