Recursive Flood Fill Part II: Making a "Flood It" Game

Make the board the same color by flooding it from the top-left.

Make the board the same color by flooding it from the top-left.

This tutorial expands upon the concepts taught in my previous Recursive Flood Fill Algorithm in GameMaker: Studio post. Today, I will walk you through creating a Flood It game using the recursive flood fill algorithm.

The win condition is to make the entire board the same color by means of changing the color of the top-left cell. The accompanying .gif showcases the completion of the game. To increase replayability, this simple mechanic can be coupled with varying board sizes, additional colors, and a best-score counter.

To keep this lesson digestible, our version of the game will get minimal GUI. Changing the flood color is done by pressing keyboard keys, the number of turns used is printed in the GameMaker: Studio console, and a random board is generated each play. 

Flood It Mechanics

1) If each cell of the board is not the same color, continue. Otherwise, game complete.
2) Press R, Y, G, or B to set the flood color.
3) If the top-left cell's color is not the flood color, continue.
4) Execute the flood fill algorithm from the top-left cell.

Initializing

The following code should go in the Create Event of an object. This declares all necessary variables and generates our grid. When comparing this initialization code to Part I's initialization code, the key differences are: setting a random seed, modifying grid dimensions, and creating a turn counter.

random_set_seed(randomize()); // randomness

arr = ds_grid_create(16, 16); // init 16x16 grid
cell_width = 20; // width of each grid cell
cell_height = 20; // height of each grid cell
xpos = 32; // x-coordinate of the top-left cell in the room
ypos = 32; // y-coordinate of the top-left cell in the room

// init the colors used in the game
red = c_red;
yellow = c_yellow;
green = c_lime;
blue = c_blue;

flood_color = red; // color to flood the grid (from top-left cell)

turns = 0; // how many color swaps it takes to flood the grid

// cycle through all the cells in the grid and make them any of the four colors
for (var i = 0; i < ds_grid_width(arr); i++) {
    for (var j = 0; j < ds_grid_height(arr); j++) {
        ds_grid_set(arr, i, j, choose(red, yellow, green, blue));
    }
}

Flooding

The following code should go in the Step Event of the same object. This event does not appear in Part I and is used to change the flood color based on keyboard inputs. The floodfill script call has moved to this event from the Draw Event, as it is triggered upon pressing the keys. The turn counter also increases by one each time a different color is selected.

var pressed = false; // no key has been pressed

// determine which key was pressed
switch (keyboard_key) {
    case (ord("R")): // if R, set the flood color to red
        flood_color = red;
        pressed = true; // indicate that a key has been pressed
        break;
    case (ord("Y")): // if Y, set the flood color to yellow
        flood_color = yellow;
        pressed = true;
        break;
    case (ord("G")): // if G, set the flood color to green
        flood_color = green;
        pressed = true;
        break;
    case (ord("B")): // if B, set the flood color to blue
        flood_color = blue;
        pressed = true;
        break;
}

// if a key has been pressed
if (pressed) {
    if (ds_grid_get(arr, 0, 0) != flood_color) { // ensure the color of the top-left cell is not already the flood color
        turns+=1; // increment turn counter
        floodfill(0, 0, flood_color, ds_grid_get(arr, 0, 0)); // call the algorithm, starting in the top-left (0, 0) grid cell
    }
}

Drawing

The following code should go in the Draw Event of the same object. When comparing this drawing code to Part I's drawing code, the key differences are: the addition of a check to determine whether each grid cell is the same color (win condition) and the removal of cell mouse-clicking to call the floodfill script (moved, in part, to the Step Event).

var success = true; // whether the grid is one solid color, default to true*

// cycle through all the cells in the grid
for (var i = 0; i < ds_grid_width(arr); i++) {
    for (var j = 0; j < ds_grid_height(arr); j++) {
        // temp variables for top-left and bottom-right coordinates of each cell
        var x1, y1, x2, y2;
        x1 = xpos + (i * cell_width);
        y1 = ypos + (j * cell_height);
        x2 = x1 + cell_width;
        y2 = y1 + cell_height;

        var col = ds_grid_get(arr, i, j); // get the color of the cell

        // *multiple cell colors in the grid, we cannot win this turn
        if (col != flood_color) {
            success = false;
        }

        // draw rectangle at the given coordinates based on the color of the cell
        draw_set_color(col);
        draw_rectangle(x1, y1, x2, y2, false);
    }
}

// if all grid cells are the same color, print the number of turns and restart the game
if (success) {
    show_debug_message(turns);
    room_restart();
}

The Flood Fill Script

The following code should go in a script called floodfill. This code has gone unmodified since Part I.

///floodfill(i, j, new_color, prev_color);
var i, j, new_color, prev_color;

i = argument0; // cell col
j = argument1; // cell row
new_color = argument2; // new, replacement color the cell should be
prev_color = argument3; // the color of the region to be changed

// if the coordinates are not within the grid and if the color of the cell has changed, return
if (i < 0 || i >= ds_grid_width(arr) || j < 0 || j >= ds_grid_height(arr)) || (ds_grid_get(arr, i, j) != prev_color) {
    return 0;
}

// change the color of the cell to the new color
ds_grid_set(arr, i, j, new_color);

// adjacent cell recursion
floodfill(i - 1, j, new_color, prev_color); // cell to the left
floodfill(i + 1, j, new_color, prev_color); // cell to the right
floodfill(i, j - 1, new_color, prev_color); // cell above
floodfill(i, j + 1, new_color, prev_color); // cell below

Wrapping Up

If you managed to successfully create the game, congratulations! If something is not working, either go back and ensure you followed all the steps and put the code in the correct events, or download the source project here. If you want an additional challenge, try adding more colors in a larger grid. Further, try your hand at adding clickable buttons that set the flood color rather than pressing keyboard keys. As always, if you have any questions, comments, or critiques feel free to leave them below.

GameMaker-related posts mailing list