Search code examples
javascriptarraysfunction2d-games

Return N unique random numbers in JS array


I am going to do small game like Google Mineshweeper on JS. And I need to write function, that gets amount of numbers N and returns N unique random numbers in array. It's easy to do array with repeating, but I can't understand, how to create array without it. I use this code to initialize game field:

const game = {
    init: function(fieldWidth, fieldHeight, fieldBombs) {
        let field = [];
        let bombsPos = [];
        for (let i = 0; i < fieldWidth * fieldHeight; i++) {
            field[i] = {
                isBomb: false,
                nearbyBombs: 0,
            }
        }

        for (let i = 0; i < fieldBombs; i++) {
            // It's possible to repeat numbers!!!
            bombsPos[i] = Math.floor(Math.random() * (fieldWidth * fieldHeight)); 
            field[bombsPos[i]].isBomb = true;
        }
        return field;
    },
    reset: function() {
        // Other code
    }, 
}
console.log(game.init(2, 2, 2));

So, can you help me to solve this problem? Thanks in advance.


Solution

  • Use a while loop instead, while the bombsPos array length is smaller than the fieldBombs number:

    while (bombsPos.length < fieldBombs) {
        const index = Math.floor(Math.random() * (fieldWidth * fieldHeight));
        if (!field[index].isBomb) {
            field[index].isBomb = true;
            bombsPos.push(index);
        }
    }
    

    const game = {
        init: function(fieldWidth, fieldHeight, fieldBombs) {
            let field = [];
            let bombsPos = [];
            for (let i = 0; i < fieldWidth * fieldHeight; i++) {
                field[i] = {
                    isBomb: false,
                    nearbyBombs: 0,
                }
            }
            while (bombsPos.length < fieldBombs) {
                const index = Math.floor(Math.random() * (fieldWidth * fieldHeight));
                if (!field[index].isBomb) {
                    field[index].isBomb = true;
                    bombsPos.push(index);
                }
            }
            return field;
        },
        reset: function() {
            // Other code
        }, 
    }
    console.log(game.init(2, 2, 2));

    But it looks like you aren't using the bombsPos array. Is that deliberate, or a mis-copy from your actual code? If you really aren't using it elsewhere, then use a Set of the indicies found so far instead.

    const game = {
        init: function(fieldWidth, fieldHeight, fieldBombs) {
            const field = [];
            const bombIndicies = new Set();
            for (let i = 0; i < fieldWidth * fieldHeight; i++) {
                field[i] = {
                    isBomb: false,
                    nearbyBombs: 0,
                }
            }
            while (bombIndicies.size < fieldBombs) {
                const index = Math.floor(Math.random() * (fieldWidth * fieldHeight));
                if (!field[index].isBomb) {
                    field[index].isBomb = true;
                    bombIndicies.add(index);
                }
            }
            return field;
        },
        reset: function() {
            // Other code
        }, 
    }
    console.log(game.init(2, 2, 2));