# GMLHow to create Game of Life in GMS1.4 / GMS2

#### AlexDerFerri

##### Member
CONWAY'S GAME OF LIFE algorithm in GML

GM Version
: Studio 1.4 / 2
Target Platform: All
Summary: A nice Game of Life algorithm using GML.
This method uses the GML data structure called ds_grid to make the algorithm run faster.
We will make two grids: one for the real world and one for the calculations.
After we have made all the calculations and put into the calculation grid, we will copy the results into the real world grid. If we made everything in one grid the results would be incorrect, because each game rule would prevail over the next ones as they would be called sequentially.
The code is full of comments in order to make the game logic clearer.
I'm sorry if the tutorial might look too long but I will hopefully make a YouTube tutorial video.

Here are the game rules:
1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
2. Any live cell with two or three live neighbours lives on to the next generation.
3. Any live cell with more than three live neighbours dies, as if by overpopulation.
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

1) First, let's create a new sprite 16x16 wide and make two image frames, one for the DEAD cell and one for the ALIVE cell.

2) Let's create a new script and write some macros:
Code:
``````#macro TILE_SIZE 16                // Size of each individual cell
#macro ALIVE 1                    // The cell alive state
#macro ONE_SECOND room_speed    // One game second``````
3) Let's create a new object called oController. This object will hold all the game logic and draw the game grid:

4) Add a new Create Event and initialize the oController object:
Code:
``````/// Init controller

// Create the world grid and the calculation grid
worldWidth  = (room_width div TILE_SIZE);                // How many horizontal cells?
worldHeight = (room_height div TILE_SIZE);                // How many vertical cells?
worldGrid   = ds_grid_create(worldWidth, worldHeight);  // Create a grid 40x40 (cells) wide
calculationGrid = ds_grid_create(worldWidth, worldHeight);  // Create a grid 40x40 (cells) wide

// Clear the world grid and the calculation grid - all the cells are marked as DEAD cells

// Init world grid -
startingPopoulation = 50;    // How many cells are ALIVE at the start of the game
initWorld(worldGrid, worldWidth, worldHeight, startingPopoulation); // Create population

// Update time - how fast the cells update their state
updateTime = ONE_SECOND/6;

// Calculate Popoulation - keep track of how many cells are ALIVE
population  = calculatePopolation(worldGrid, worldWidth, worldHeight);

// Whether the game is paused or not
gamePaused = false;``````
5) Create a new script and rename it initWorld; this will initialize the world grid generating random ALIVE cells along the whole grid.

Code:
``````///initWorld(grid, w, h, max_population);

var grid = argument0;                // The world grid
var w = argument1;                    // The world grid width
var h = argument2;                    // The world grid height
var maxPopulation = argument3;        // Max number of ALIVE cells at the start of the game

var counter = 0;                    // Keep track of how many ALIVE cells are being created

// Loop through the world grid
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
// Reached max population - break the loop
if (counter > maxPopulation) break;
// Chance to create ALIVE cell
if (irandom(10) < 1) {
// Set the world grid cell to ALIVE state
grid[# i, j] = ALIVE;
// Increase counter - a new ALIVE cell is being created
counter++;
}
}
}``````
6) Create a new script and rename it calculatePopulation. This script will return the number of ALIVE cells.

Code:
``````///calculatePopulation(grid, w, h);

var grid = argument0;            // The world grid
var w = argument1;                // The world grid width
var h = argument2;                // The world grid height

var counter = 0;                // Keep track of how many ALIVE cells are in the world grid

// Loop through the grid
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
// An ALIVE cell is being found - increase the population counter
if (grid[# i, j] == ALIVE) counter++;
}
}

// Return the number of ALIVE cells
return counter;``````
7) Let's create a new Draw Event in the oController objects and write some code:

Code:
``````/// Draw world

drawWorld(worldGrid, worldWidth, worldHeight);

// The colour of the text
var textColour = c_red;

// Draw Population counter
draw_set_colour(textColour);
draw_text(32, 32, "Population: " + string(population));
draw_set_colour(c_white);

// Draw world speed
draw_set_colour(textColour);
draw_text(32, 64, "World Speed: " + string(updateTime));
draw_set_colour(c_white);

// Draw game state - game is currently paused
if (gamePaused) {
draw_set_colour(textColour);
draw_text(32, 96, "Game Paused");
draw_set_colour(c_white);
}``````

8) Let's add a new script and rename it drawWorld. This script will loop though the world grid and draw all the cells. The cells will be white (image_index = 0) if the cell is DEAD and blue (image_index = 1) if the cell is ALIVE.

Code:
``````///drawWorld(grid, w, h);

var grid = argument0;           // The world grid
var w = argument1;                // The world grid width
var h = argument2;                // The world grid height

// Loop through the grid
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
// Get x and y world position
var xPos = i * TILE_SIZE;
var yPos = j * TILE_SIZE;
// Get the subimage of the cell sprite - DEAD (0) or ALIVE (1)
var subImage = grid[# i, j];
// Draw the cell sprite at the given position and with the right subimage
draw_sprite(sCell, subImage, xPos, yPos);
}
}``````
9) Let's add a Step Event in the oController object and write some code:

Code:
``````/// Update world
if (alarm[0] == -1 && !gamePaused) {
alarm[0] = updateTime;
}

// Increase / decrease update speed
speedFactor = 0.1;                    // The speed increase/decrease factor
maxSpeed = ONE_SECOND * 2;            // Max speed limit
minSpeed = ONE_SECOND / 20;            // Min speed limit

if (keyboard_check_pressed(vk_down)) {
// Increase update speed
updateTime = min(updateTime + speedFactor, maxSpeed);
} else if (keyboard_check_pressed(vk_up)) {
// Decrease update speed
updateTime = max(updateTime - speedFactor, minSpeed);
}

// Pause/unpause the game
if (keyboard_check_pressed(vk_space)) {
// Resume the game
if (!gamePaused) alarm[0] = updateTime;
// Pause / unpause the game
gamePaused = !gamePaused;
}

// Create ALIVE cell at mouse position
if (mouse_check_button_pressed(mb_left)) {
// Get world grid position
var xGrid = mouse_x div TILE_SIZE;
var yGrid = mouse_y div TILE_SIZE;

worldGrid[# xGrid, yGrid] = ALIVE;

// Pause the game - avoid cells update during creation
gamePaused = true;
}``````

10) Let's add a new Alarm0 event in the oController object:

Code:
``````/// Update World
updateWorld(worldGrid, worldWidth, worldHeight);

// Update real World (copy the calcuaztio grid values into the real world grid
for (var i = 0; i < worldWidth; i++) {
for (var j = 0; j < worldHeight; j++) {
// Copy calculation grid to world grid
worldGrid[# i, j] = calculationGrid[# i, j];
// Reset calculation grid
}
}
// Calculate Population
population  = calculatePopolation(worldGrid, worldWidth, worldHeight);``````
11) Let's add a new script and rename it updateWorld(), this script will update all the world grid. As it is called in the alarm[0] of the oController object, it will not run each steps.

Code:
``````///updateWorld(grid, width, height);

var grid = argument0;            // The world grid
var w = argument1;                // The world grid width
var h = argument2;                // The world grid height

// Loop through the grid
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
// Check all cases
checkAdjacent0(grid, i, j);  // Cell dies if there are less than 2 adjacent ALIVE cells
checkAdjacent1(grid, i, j);  // Cell survive if there are 2 or 3 adjacent ALIVE cells
checkAdjacent2(grid, i, j);  // Cell dies if there are more than 3 adjacent ALIVE cells
}
}``````
11) Now here it comes the most important part of the algorithm.
We will create 4 scripts, one for each game rule:
1 - Cell dies if there are less than 2 adjacent ALIVE cells
2 - Cell survive if there are 2 or 3 adjacent ALIVE cells
3 - Cell dies if there are more than 3 adjacent ALIVE cells
4 - Dead cell with exactly 3 adjacent ALIVE cells, becomes ALIVE

IMPORTANT: All these scripts will check the world grid and put the given results into the calculation grid.

Code:
``````//checkAdjacent0(grid, x, y);

var grid = argument0;
var xGrid = argument1;
var yGrid = argument2;

var counter = 0;

// RULE: Cell dies if there are less than 2 adjacent ALIVE cells

// Check if the cell is ALIVE
if (grid[# xGrid, yGrid] == ALIVE) {

// Top-left
if (xGrid != 0 && grid[# xGrid - 1, yGrid - 1] == ALIVE) {
counter++;
}
// Top
if (yGrid != 0 && grid[# xGrid, yGrid - 1] == ALIVE) {
counter++;
}
// Top-right
if (xGrid != worldWidth && yGrid != 0 && grid[# xGrid + 1, yGrid - 1] == ALIVE) {
counter++;
}
// Right
if (xGrid != worldWidth && grid[# xGrid + 1, yGrid] == ALIVE) {
counter++;
}
// Bottom-right
if (xGrid != worldWidth && yGrid != worldHeight && grid[# xGrid + 1, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom
if (yGrid != worldHeight && grid[# xGrid, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom-left
if (xGrid != 0 && yGrid != worldHeight && grid[# xGrid - 1, yGrid + 1] == ALIVE) {
counter++;
}
// Left
if (xGrid != 0 && grid[# xGrid - 1, yGrid] == ALIVE) {
counter++;
}

// There are less than 2 ALIVE cells so current cell becomes a DEAD cell
if (counter < 2) {
}
}

exit;``````
Code:
``````//checkAdjacent1(grid, x, y);

var grid = argument0;
var xGrid = argument1;
var yGrid = argument2;

var counter = 0;

// RULE: Cell survives if there are 2 or 3 adjacent ALIVE cells

if (grid[# xGrid, yGrid] == ALIVE) {

// Top-left
if (xGrid != 0 && grid[# xGrid - 1, yGrid - 1] == ALIVE) {
counter++;
}
// Top
if (yGrid != 0 && grid[# xGrid, yGrid - 1] == ALIVE) {
counter++;
}
// Top-right
if (xGrid != worldWidth && yGrid != 0 && grid[# xGrid + 1, yGrid - 1] == ALIVE) {
counter++;
}
// Right
if (xGrid != worldWidth && grid[# xGrid + 1, yGrid] == ALIVE) {
counter++;
}
// Bottom-right
if (xGrid != worldWidth && yGrid != worldHeight && grid[# xGrid + 1, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom
if (yGrid != worldHeight && grid[# xGrid, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom-left
if (xGrid != 0 && yGrid != worldHeight && grid[# xGrid - 1, yGrid + 1] == ALIVE) {
counter++;
}
// Left
if (xGrid != 0 && grid[# xGrid - 1, yGrid] == ALIVE) {
counter++;
}

// Cell survives if there are 2 or 3 adjacent ALIVE cells
if (counter == 2 || counter == 3) {
calculationGrid[# xGrid, yGrid] = ALIVE;
}
}

exit;``````
Code:
``````//checkAdjacent2(grid, x, y);

var grid = argument0;
var xGrid = argument1;
var yGrid = argument2;

var counter = 0;

// RULE: Cell dies if there are more than 3 adjacent ALIVE cells

// Check if the cell is ALIVE
if (grid[# xGrid, yGrid] == ALIVE) {

// Top-left
if (xGrid != 0 && grid[# xGrid - 1, yGrid - 1] == ALIVE) {
counter++;
}
// Top
if (yGrid != 0 && grid[# xGrid, yGrid - 1] == ALIVE) {
counter++;
}
// Top-right
if (xGrid != worldWidth && yGrid != 0 && grid[# xGrid + 1, yGrid - 1] == ALIVE) {
counter++;
}
// Right
if (xGrid != worldWidth && grid[# xGrid + 1, yGrid] == ALIVE) {
counter++;
}
// Bottom-right
if (xGrid != worldWidth && yGrid != worldHeight && grid[# xGrid + 1, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom
if (yGrid != worldHeight && grid[# xGrid, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom-left
if (xGrid != 0 && yGrid != worldHeight && grid[# xGrid - 1, yGrid + 1] == ALIVE) {
counter++;
}
// Left
if (xGrid != 0 && grid[# xGrid - 1, yGrid] == ALIVE) {
counter++;
}

// There are more than 3 adjacent ALIVE cells - current cell becomes a DEAD cell
if (counter > 3) {
}
}

exit;``````
Code:
``````//checkAdjacent3(grid, x, y);

var grid = argument0;
var xGrid = argument1;
var yGrid = argument2;

var counter = 0;

// RULE: DEAD cell with exactly 3 adjacent ALIVE cells, becomes ALIVE

// Check if the cell is ALIVE
if (grid[# xGrid, yGrid] == DEAD) {

// Top-left
if (xGrid != 0 && grid[# xGrid - 1, yGrid - 1] == ALIVE) {
counter++;
}
// Top
if (yGrid != 0 && grid[# xGrid, yGrid - 1] == ALIVE) {
counter++;
}
// Top-right
if (xGrid != worldWidth && yGrid != 0 && grid[# xGrid + 1, yGrid - 1] == ALIVE) {
counter++;
}
// Right
if (xGrid != worldWidth && grid[# xGrid + 1, yGrid] == ALIVE) {
counter++;
}
// Bottom-right
if (xGrid != worldWidth && yGrid != worldHeight && grid[# xGrid + 1, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom
if (yGrid != worldHeight && grid[# xGrid, yGrid + 1] == ALIVE) {
counter++;
}
// Bottom-left
if (xGrid != 0 && yGrid != worldHeight && grid[# xGrid - 1, yGrid + 1] == ALIVE) {
counter++;
}
// Left
if (xGrid != 0 && grid[# xGrid - 1, yGrid] == ALIVE) {
counter++;
}

// There are 3 adjacent ALIVE cells, current cells becomes an ALIVE cell
if (counter == 3) {
calculationGrid[# xGrid, yGrid] = ALIVE;
}
}

exit;``````
That's it!
Now, the Game of Life should work fine.