Program for Conway’s Game Of Life | Set 2
Given a binary grid[ ][ ] of size N*M, with each cell containing either 0 or 1, where 1 represents an alive cell and the 0 represents a dead cell. The task is to generate the next generation of cells based on the following rules:
- Any live cell with fewer than two live neighbors dies due to under-population.
- Any live cell with two or three live neighbors lives on to the next generation.
- Any live cell with more than three live neighbors dies due to overpopulation.
- Any dead cell with exactly three live neighbors becomes a live cell by reproduction.
Here, the neighbor of a cell includes its adjacent cells as well as diagonal ones, so for each cell, a total of 8 neighbors are there.
Examples:
Input: N = 5, M = 10
0000000000
0001100000
0000100000
0000000000
0000000000
Output:
0000000000
0001100000
0001100000
0000000000
0000000000
Explanation:
The cells at (1, 3), (1, 4) and (2, 4) are alive and have 2 neighbors,
So, according to Rule 2, they live on to the next generation.
The cell at (2, 3) is dead and has exactly 3 neighbors,
So, according to Rule 4, it becomes a live cell.
Input: N = 4, M = 5
00000
01100
00010
00000
Output:
00000
00100
00100
00000
Explanation:
The cells at (1, 1) and (2, 3) have only 1 neighbor,
So, according to Rule 1, they die.
The cell at (1, 2) is alive and has 2 neighbors,
So, according to Rule 2, it lives on to the next generation.
The cell at (2, 2) is dead and has exactly 3 neighbors,
So, according to Rule 4, it becomes a live cell.
Naive Approach:
We have already discussed an approach to this problem in Program for Conway’s Game Of Life | Set 1. In this approach, an extra grid future[ ][ ] of size N*M is created to store the next generation of cells.
Time complexity: O(N*M)
Auxiliary Space: O(N*M)
Efficient Approach:
A space-optimized approach is possible for this problem, which uses no extra space. For every alive cell, increment its value by 1 each time we encounter an alive neighbor for it. And, for every dead cell, decrement its value by 1 each time we encounter an alive neighbor for it. Now, if the value in a cell is smaller than 0, it means it is a dead cell and if the value is greater than 0, it is an alive cell, also the magnitude of value in a cell will represent the number of its alive neighbors. In this way, an extra grid will not be required and a space-optimized solution is obtained. Detailed steps of this approach are as follows:
For the present grid position, we will look at all the neighbors.
- Traverse the whole grid.
- If the value of the neighbor is >= 1(i.e. initial value of the neighbor was 1)
- If, the current cell is >= 1, just increment the current cell value by 1.
Now, grid [ i ][ j ] > 0 will imply that initial grid [ i ][ j ] == 1. - Else, the current cell is <= 0, just decrement the current cell value by 1.
Now, grid [ i ][ j ] <= 0 will imply that initial grid [ i ][ j ] == 0.
- If, the current cell is >= 1, just increment the current cell value by 1.
- Now, generate the required new generation grid using the modified grid.
- If the current cell value is > 0, there are 3 possible cases:
- If the value is < 3 then change it to 0.
- Else if the value is <= 4 then change it to 1.
- Else change the value to 0.
- Else, the current cell value is <= 0.
- If the value is 3 then change it to 1.
- Else change it to 0.
- If the current cell value is > 0, there are 3 possible cases:
Below is the implementation of the above approach:
C++
// C++ implementation of // the above approach #include <bits/stdc++.h> using namespace std; void print(vector<vector< int >> grid) { int p = grid.size(), q = grid[0].size(); for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { cout << grid[i][j]; } cout << endl; } } // Function to check if // index are not out of grid static bool save(vector<vector< int > > grid, int row, int col) { return (grid.size() > row && grid[0].size() > col && row >= 0 && col >= 0); } // Function to get New Generation void solve(vector<vector< int > >& grid) { int p = grid.size(), q = grid[0].size(); int u[] = { 1, -1, 0, 1, -1, 0, 1, -1 }; int v[] = { 0, 0, -1, -1, -1, 1, 1, 1 }; for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { // IF the initial value // of the grid(i, j) is 1 if (grid[i][j] > 0) { for ( int k = 0; k < 8; k++) { if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0) { // If initial value > 0, // just increment it by 1 grid[i][j]++; } } } // IF the initial value // of the grid(i, j) is 0 else { for ( int k = 0; k < 8; k++) { if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0) { // If initial value <= 0 // just decrement it by 1 grid[i][j]--; } } } } } // Generating new Generation. // Now the magnitude of the // grid will represent number // of neighbours for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { // If initial value was 1. if (grid[i][j] > 0) { // Since Any live cell with // < 2 live neighbors dies if (grid[i][j] < 3) grid[i][j] = 0; // Since Any live cell with // 2 or 3 live neighbors live else if (grid[i][j] <= 4) grid[i][j] = 1; // Since Any live cell with // > 3 live neighbors dies else if (grid[i][j] > 4) grid[i][j] = 0; } else { // Since Any dead cell with // exactly 3 live neighbors // becomes a live cell if (grid[i][j] == -3) grid[i][j] = 1; else grid[i][j] = 0; } } } } // Driver code int main () { vector<vector< int >> grid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 0,0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Function to generate // New Generation inplace solve(grid); // Displaying the grid print(grid); return 0; } |
Java
// Java program for // the above approach import java.util.*; import java.lang.*; class GFG{ static void print( int [][] grid) { int p = grid.length, q = grid[ 0 ].length; for ( int i = 0 ; i < p; i++) { for ( int j = 0 ; j < q; j++) { System.out.print(grid[i][j]); } System.out.println();; } } static boolean save( int [][] grid, int row, int col) { return (grid.length > row && grid[ 0 ].length > col && row >= 0 && col >= 0 ); } static void solve( int [][] grid) { int p = grid.length, q = grid[ 0 ].length; // Possible neighboring // indexes int u[] = { 1 , - 1 , 0 , 1 , - 1 , 0 , 1 , - 1 }; int v[] = { 0 , 0 , - 1 , - 1 , - 1 , 1 , 1 , 1 }; for ( int i = 0 ; i < p; i++) { for ( int j = 0 ; j < q; j++) { // IF the initial value // of the grid(i, j) is 1 if (grid[i][j] > 0 ) { for ( int k = 0 ; k < 8 ; k++) { if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0 ) { // If initial value > 0, // just increment it by 1 grid[i][j]++; } } } // IF the initial value // of the grid(i, j) is 0 else { for ( int k = 0 ; k < 8 ; k++) { if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0 ) { // If initial value <= 0 // just decrement it by 1 grid[i][j]--; } } } } } // Generating new Generation. // Now the magnitude of the // grid will represent number // of neighbours for ( int i = 0 ; i < p; i++) { for ( int j = 0 ; j < q; j++) { // If initial value was 1. if (grid[i][j] > 0 ) { // Since Any live cell with // < 2 live neighbors dies if (grid[i][j] < 3 ) grid[i][j] = 0 ; // Since Any live cell with // 2 or 3 live neighbors live else if (grid[i][j] <= 4 ) grid[i][j] = 1 ; // Since Any live cell with // > 3 live neighbors dies else if (grid[i][j] > 4 ) grid[i][j] = 0 ; } else { // Since Any dead cell with // exactly 3 live neighbors // becomes a live cell if (grid[i][j] == - 3 ) grid[i][j] = 1 ; else grid[i][j] = 0 ; } } } } // Driver code public static void main (String[] args) { int [][] grid = {{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // Function to generate // New Generation inplace solve(grid); // Displaying the grid print(grid); } } // This code is contributed by offbeat |
Python3
# Python3 implementation of # the above approach def print2dArr(grid): p = len (grid) q = len (grid[ 0 ]) for i in range (p): for j in range (q): print (grid[i][j], end = '') print () # Function to check if # index are not out of grid def save(grid, row, col): return ( len (grid) > row and len (grid[ 0 ]) > col and row > = 0 and col > = 0 ) # Function to get New Generation def solve(grid): p = len (grid) q = len (grid[ 0 ]) u = [ 1 , - 1 , 0 , 1 , - 1 , 0 , 1 , - 1 ] v = [ 0 , 0 , - 1 , - 1 , - 1 , 1 , 1 , 1 ] for i in range (p): for j in range (q): # IF the initial value # of the grid(i, j) is 1 if (grid[i][j] > 0 ): for k in range ( 8 ): if (save(grid, i + u[k], j + v[k]) and grid[i + u[k]][j + v[k]] > 0 ): # If initial value > 0, # just increment it by 1 grid[i][j] + = 1 # IF the initial value # of the grid(i, j) is 0 else : for k in range ( 8 ): if (save(grid, i + u[k], j + v[k]) and grid[i + u[k]][j + v[k]] > 0 ): # If initial value <= 0 # just decrement it by 1 grid[i][j] - = 1 # Generating new Generation. # Now the magnitude of the # grid will represent number # of neighbours for i in range (p): for j in range (q): # If initial value was 1. if (grid[i][j] > 0 ): # Since Any live cell with # < 2 live neighbors dies if (grid[i][j] < 3 ): grid[i][j] = 0 # Since Any live cell with # 2 or 3 live neighbors live elif (grid[i][j] < = 4 ): grid[i][j] = 1 # Since Any live cell with # > 3 live neighbors dies elif (grid[i][j] > 4 ): grid[i][j] = 0 else : # Since Any dead cell with # exactly 3 live neighbors # becomes a live cell if (grid[i][j] = = - 3 ): grid[i][j] = 1 else : grid[i][j] = 0 # Driver code if __name__ = = '__main__' : grid = [[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ], [ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , ], [ 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , ], [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ], [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ], ] # Function to generate # New Generation inplace solve(grid) # Displaying the grid print2dArr(grid) |
C#
// C# program for // the above approach using System; using System.Text; public class GFG{ static void print( int [,] grid) { int p = grid.GetLength(0), q = grid.GetLength(1); for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { Console.Write(grid[i,j]); } Console.Write( "\n" ); } } static bool save( int [,] grid, int row, int col) { return (grid.GetLength(0) > row && grid.GetLength(1) > col && row >= 0 && col >= 0); } static void solve( int [,] grid) { int p = grid.GetLength(0), q = grid.GetLength(1); // Possible neighboring // indexes int [] u = {1, -1, 0, 1, -1, 0, 1, -1}; int [] v = {0, 0, -1, -1, -1, 1, 1, 1}; for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { // IF the initial value // of the grid(i, j) is 1 if (grid[i,j] > 0) { for ( int k = 0; k < 8; k++) { if (save(grid, i + u[k], j + v[k]) && grid[(i + u[k]),(j + v[k])] > 0) { // If initial value > 0, // just increment it by 1 grid[i,j]++; } } } // IF the initial value // of the grid(i, j) is 0 else { for ( int k = 0; k < 8; k++) { if (save(grid, i + u[k], j + v[k]) && grid[(i + u[k]),(j + v[k])] > 0) { // If initial value <= 0 // just decrement it by 1 grid[i,j]--; } } } } } // Generating new Generation. // Now the magnitude of the // grid will represent number // of neighbours for ( int i = 0; i < p; i++) { for ( int j = 0; j < q; j++) { // If initial value was 1. if (grid[i,j] > 0) { // Since Any live cell with // < 2 live neighbors dies if (grid[i,j] < 3) grid[i,j] = 0; // Since Any live cell with // 2 or 3 live neighbors live else if (grid[i,j] <= 4) grid[i,j] = 1; // Since Any live cell with // > 3 live neighbors dies else if (grid[i,j] > 4) grid[i,j] = 0; } else { // Since Any dead cell with // exactly 3 live neighbors // becomes a live cell if (grid[i,j] == -3) grid[i,j] = 1; else grid[i,j] = 0; } } } } //Driver Code static public void Main (){ int [,] grid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 0,0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Function to generate // New Generation inplace solve(grid); // Displaying the grid print(grid); } } // This code is contributed by shruti456rawal |
Javascript
<script> // JavaScript implementation of // the above approach function print2dArr(grid){ let p = grid.length let q = grid[0].length for (let i=0;i<p;i++){ for (let j=0;j<q;j++){ document.write(grid[i][j], '' ) } document.write( "</br>" ) } } // Function to check if // index are not out of grid function save(grid, row, col){ return grid.length > row && grid[0].length > col && row >= 0 && col >= 0 } // Function to get New Generation function solve(grid){ let p = grid.length let q = grid[0].length let u = [1, -1, 0, 1, -1, 0, 1, -1] let v = [0, 0, -1, -1, -1, 1, 1, 1] for (let i = 0; i < p; i++) { for (let j = 0; j < q; j++) { // IF the initial value // of the grid(i, j) is 1 if (grid[i][j] > 0) { for (let k = 0; k < 8; k++) { if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0) // If initial value > 0, // just increment it by 1 grid[i][j] += 1 } } // IF the initial value // of the grid(i, j) is 0 else { for (let k = 0;k<8;k++){ if (save(grid, i + u[k], j + v[k]) && grid[i + u[k]][j + v[k]] > 0) // If initial value <= 0 // just decrement it by 1 grid[i][j] -= 1 } } } } // Generating new Generation. // Now the magnitude of the // grid will represent number // of neighbours for (let i = 0; i < p; i++) { for (let j = 0; j < q; j++) { // If initial value was 1. if (grid[i][j] > 0){ // Since Any live cell with // < 2 live neighbors dies if (grid[i][j] < 3) grid[i][j] = 0 // Since Any live cell with // 2 or 3 live neighbors live else if (grid[i][j] <= 4) grid[i][j] = 1 // Since Any live cell with // > 3 live neighbors dies else if (grid[i][j] > 4) grid[i][j] = 0 } else { // Since Any dead cell with // exactly 3 live neighbors // becomes a live cell if (grid[i][j] == -3) grid[i][j] = 1 else grid[i][j] = 0 } } } } // Driver code let grid = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], ] // Function to generate // New Generation inplace solve(grid) // Displaying the grid print2dArr(grid) // This code is contributed by shinjanpatra </script> |
0000000000 0001100000 0001100000 0000000000 0000000000
Time complexity: O(N*M)
Auxiliary Space: O(1)
Please Login to comment...