views:

38

answers:

1

mBlocks is a 2-dimensional array of Block objects. Every time my application runs, it runs the InitGridNumbers function. Sometimes, it will get stuck in an infinite loop. Other times, it builds and runs without issues.

  public function InitGridNumbers():void
  {
   var tempRow:Array;
   var tempColumn:Array;
   var tempNum:int;
   for (var i:int = 0; i < mNumRows; i++)
   {
    tempRow = GetRow(i);
    for (var j:int = 0; j < mNumColumns; j++)
    {
     // if number is unassigned
     if (tempRow[j] == 0)
     {
      var cantMoveOn:Boolean = true;
      while (cantMoveOn)
      {
       tempNum = Math.random() * mNumColumns + 1;
       if (!CheckRow(i, tempNum) && !CheckColumn(j, tempNum))
        cantMoveOn = false;
      }
      mBlocks[i][j].SetNumber(tempNum);     
     }
    }
   }
  } 

  public function CheckRow(rowNum:int, checkNum:int):Boolean
  {
   var tempRow:Array = GetRow(rowNum);
   for (var i:int = 0; i < mNumColumns; i++)
   {
    if (checkNum == tempRow[i])
     return true;
   }
   return false;
  }

  public function CheckColumn(columnNum:int, checkNum:int):Boolean
  {
   var tempColumn:Array = GetColumn(columnNum);
   for (var i:int = 0; i < mNumColumns; i++)
   {
    if (checkNum == tempColumn[i])
     return true;
   }
   return false;
  }

  public function GetRow(rowNum:int):Array
  {
   var rowArray:Array = new Array(mNumRows);
   for (var i:int = 0; i < mNumRows; i++)
    rowArray[i] = mBlocks[rowNum][i].mNumber;

   return rowArray;
  }

  public function GetColumn(columnNum:int):Array
  {
   var columnArray:Array = new Array(mNumColumns);
   for (var i:int = 0; i < mNumColumns; i++)
    columnArray[i] = mBlocks[i][columnNum].mNumber;
   return columnArray;
  }
+2  A: 

To begin with, checkColumn, getColumn and getRow methods are wrong. To get a row, you should copy numColumns items and to get a column, you should copy numRows items. In other words, if there are r rows and c columns, there would be c items per each row and r items per each column.

public function checkColumn(columnNum:int, checkNum:int):Boolean
{
  var tempColumn:Array = getColumn(columnNum);
  for (var i:int = 0; i < mNumRows; i++)
  {
    if (checkNum == tempColumn[i])
      return true;
  }
  return false;
}

public function getRow(rowNum:int):Array
{
  var rowArray:Array = new Array();//needn't specify length in advance.
  for (var i:int = 0; i < mNumColumns; i++)
    rowArray[i] = mBlocks[rowNum][i].mNumber;

  return rowArray;
}
public function getColumn(columnNum:int):Array
{
  var columnArray:Array = new Array();
  for (var i:int = 0; i < mNumRows; i++)
    columnArray[i] = mBlocks[i][columnNum].mNumber;
  return columnArray;
}

while (cantMoveOn)
{
  //call Math.floor
  tempNum = Math.floor(Math.random() * mNumColumns) + 1;
  if (!checkRow(i, tempNum) && !checkColumn(j, tempNum))
    cantMoveOn = false;
}

It looks like you're checking for a number that is not present in the current row and column. It's hard to say without knowing more details, but can you think of a scenario where this would be impossible?

For example, if there are four columns and five rows, the tempNum would always be between one and four. Now if the number of rows is five and the corresponding column already has all numbers up to four, the if statement would never evaluate to true and hence you'd end up in an infinite loop

0 1 2 3
1
2
3
4

in case grid is a square, how about this:

0 1 2 3
4
0
0
Amarghosh
I see what you're saying, and you are correct, but in this specific case, it wouldn't change anything. The grid is a square, so the numRows and numColumns values are always equal.
VGambit
@VGambit see the update
Amarghosh
I can't think of a scenario where it would be impossible to allocate a number that isn't in the current row or column. As I said, it's always a square, so the first instance can't happen. Each number on the grid is initialized to 0. The function iterates through each position on the grid, and randomly chooses a number. If the number is already in the same row or column, it randomly chooses another number. When it finds a number that isn't in the row or column yet, it places it, then repeats the process for the next position, until the grid is completely filled in.
VGambit
@VGambit If you're starting with a fresh grid, I don't see how this would lead to infinite loop - try printing the grid after each call to `setNumber`. Btw, you should call `Math.floor()` on the random number * range; otherwise you'll end up storing floating numbers.
Amarghosh
I store all numbers as ints.
VGambit
@VGambit - I didn't notice that. Did you try printing?
Amarghosh
That was a great idea. I ended up with 1 3 2 4, then 3 2 1, followed by 0s. It had to put a 4 down, but it was not possible to do so. I'll fix this by adding a "reset" function that will start over the randomization process if all numbers are attempted and they all fail. One fix I just attempted was updating FlashDevelop, the Flex SDK, and the Flash Debugger. Suddenly, I can use breakpoints.
VGambit
Breakpoints have changed my life. You helped me fix one out of the two problems I've been having all day, and I just figured out why I was getting my other infinite loop problem.
VGambit