Search code examples
arraysactionscript-3multidimensional-arrayair

as3 2d array with random numbers that does not produce 3 of a kind in rows or columns


The title pretty much sums up my goal. Im working on a candy crush clone in my spare time. The table is 7 rows and 8 columns so basicly a 2d array. I want to fill up the 2d array with random numbers of 1-8 in a way to avoid getting 3,4,5 of a kinds in rows and columns. This is necessery in order to make the starting table avoid instantly triggering points for the player.

So far the code that handle the 2d array looks like this: (tweaked it so it doesnt look so lame)

    private function getRandomSequence(min:int=1, max:int=8):Vector.<uint>{
        var values:Vector.<uint>=new Vector.<uint>;
        for (var i:int = min; i <= max; i++) values.push(i);
        var result:Vector.<uint>=new Vector.<uint>;
        while (values.length > 0) result = result.concat(values.splice(Math.floor(Math.random() * values.length), 1));
        return result;
    }


    private function getRandomArr():Vector.<Vector.<uint>>{
        var j:uint=0;
        var i:uint=0;
        var multiArray:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(7, true);
        for(j = 0; j < 7; j++) multiArray[j] = getRandomSequence(1,8);

        for(i = 0; j < 5; j++){
            for(j = 0; j < 8; j++){
                if(multiArray[i][j] == multiArray[i+1][j] == multiArray[i+2][j]){
                    //3 of a kind detected
                    while(multiArray[i][j] == multiArray[i+1][j]) multiArray[i][j] = main.mein.rng(1,8);
                }
            }
        }
        return multiArray;
    }

The problem is that the first function that gives you a random sequence avoid getting 3 of a kind yes but it also avoid 2 of a kinds aswell. Further tests required to make a function that provide relaible random number sequence with a length of 8 that allow 2 of a kinds but not allow 3 of a kinds or more.


Solution

  • There are numerous ways this can be done but for simplicities sake I'd recommend doing it - as I call it - the 'naive' way, which is pretty simple:

    1. Initialize your array with random integers between 1-8
    2. Iterate over the array and see if you find at least 3 occurences of the same number horizontally
    3. If there are 3 occurences, replace the third occurence inside the array with a new random integer between 1-8, making sure it's not the same number as the previous 2 occurences
    4. Iterate over the array and see if you find at least 3 occurences of the same number vertically
    5. If there are 3 occurences, replace the third occurence inside the array with a new random integer between 1-8, making sure it's not the same number as the previous 2 occurences
    6. If you had to replace a number at step 3 or step 5 go back to step 2 - if not you're done

    So basically you have to write a recursive function which calls itself as long as there are three occurences of a number either horizontally or vertically.

    Below is a Javascript example which showcases the idea. Just hit the 'Run code snippet' button and take a look at the results panel which shows the array before and after the clean up.

    function checkGrid(arr) {
      var previousNumberr = -1;
      var counter = 0;
      var currentNumber = 0;
      var tempNumber = 0;
      var failed = false;
      for (var a = 0; a < arr.length; a++) {
        previousNumber = -1;
        counter = 0;
        for (var b = 0; b < arr[0].length; b++) {
          currentNumber = arr[a][b];
          if (currentNumber != previousNumber) {
            previousNumber = currentNumber;
            counter = 0;
          } else {
            counter++;
            if (counter == 2) {
              do {
                tempNumber = Math.ceil(Math.random() * maxNum)
              }
              while (tempNumber == currentNumber);
              arr[a][b] = tempNumber;
              failed = true;
            }
          }
        }
      }
    
      for (var c = 0; c < arr[0].length; c++) {
        previousNumber = -1;
        counter = 0;
        for (var d = 0; d < arr.length; d++) {
          currentNumber = arr[d][c];
          if (currentNumber != previousNumber) {
            previousNumber = currentNumber;
            counter = 0;
          } else {
            counter++;
            if (counter == 2) {
              do {
                tempNumber = Math.ceil(Math.random() * maxNum)
              }
              while (tempNumber == currentNumber);
              arr[d][c] = tempNumber;
              failed = true;
            }
          }
        }
      }
    
      if (failed) {
        checkGrid(arr);
      }
    }
    
    var rows = 7;
    var columns = 8;
    var maxNum = 8;
    
    var grid = new Array(
      new Array(2, 6, 8, 4, 8, 5, 8),
      new Array(4, 6, 7, 2, 4, 6, 4),
      new Array(1, 6, 2, 4, 4, 2, 7),
      new Array(5, 1, 1, 1, 8, 6, 3),
      new Array(5, 8, 1, 5, 4, 5, 6),
      new Array(1, 1, 1, 5, 7, 7, 7),
      new Array(6, 3, 3, 1, 2, 1, 3),
      new Array(2, 2, 7, 1, 8, 2, 7)
    );
    for (var a = 0; a < columns; a++) {
      console.log(grid[a].toString());
    }
    console.log("");
    console.log("cleaning");
    console.log("");
    checkGrid(grid);
    for (var b = 0; b < columns; b++) {
      console.log(grid[b].toString());
    }