Ad

Why Is This Coodinate-returning Function Sometimes Returning A Coordinate Outside Its Supposed Restrictions?

- 1 answer

As an exercise I'm building a clone of the classic Nibbles/Snake game.

The game area consists of a two-dimensional array (rows and columns), and the player snake consists of another two-dimensional array containing coordinates for each cell in the game area that the snake is currently occupying.

I then have a function to create the apples that the snake is supposed to eat. This function returns a simple array containing an x- and a y-coordinate specifying the game area cell to put the apple. This cell should of course never be one of the cells that the player snake is occupying at the moment when the apple is created.

However, the function I've constructed sometimes creates an apple in a cell that the player snake IS currently occupying.

Can anyone spot the bug?

This is the relevant code:

const rows = 20;
const cols = 26;

const cells = createCells(rows, cols);
let player = [[1,1], [1,2], [1,3], [1,4]];
let apple = createApple(cells, player);

function createCells(rows, cols) {
    let cells = new Array(rows);
    for (let r = 0; r < cells.length; r++) {
        cells[r] = new Array(cols);
    }
    return cells;
}

function createApple(cells, player) {
    let positions = new Array();
    for (let r = 0; r < cells.length; r++) {
        for (let c = 0; c < cells[r].length; c++) {
            for (let p = 0; p < player.length; p++) {
                if (!(player[p][0] === r && player[p][1] === c)) {
                    positions.push([r, c]);
                }
            }
        }
    }
    let random = Math.floor(Math.random() * positions.length - 1);
    let apple = positions[random];
    return apple;
}
Ad

Answer

The bug is in this part of the code:

        for (let p = 0; p < player.length; p++) {
            if (!(player[p][0] === r && player[p][1] === c)) {
                positions.push([r, c]);
            }
        }

Even for the cells that are occupied by the snake, you are pushing them (player.length - 1) times. So, for the initial setup where player.length is 4, you are pushing every unoccupied cell 4 times, and every occupied cell 3 times. Do you see the bug now?

What you should change in the code? For a given cell (r,c), you must check it with ALL the cells of the player, and push it to positions only and only if there is no match with any of them. Take some time, and try to code it yourself without seeing further below.

        bool free=true;
        for (let p = 0; p < player.length; p++) {
            if (player[p][0] === r && player[p][1] === c) {
                free = false;
                break;
            }
        }
        if (free) {
            positions.push([r, c]);
        }
Ad
source: stackoverflow.com
Ad