0

Unhandled Exception: System.IndexOutOfRangeException: Index was outside of the bounds of the array (at the first if statements)

    static int arrayRows = 20;
    static int arrayCols = 20;

    public void printBoard()
    {
        int neighbours;
        for (y = 0; y < arrayCols; y++)
            for (x = 0; x < arrayRows; x++)
            {
                neighbours = 0;
                // Count number of neighbours surrounding live cell
                if (parentGen[x-1, y-1] == 1) // top left 
                    neighbours++;
                if (parentGen[x-1, y] == 1)  // left
                    neighbours++;
                if (parentGen[x-1, y+1] == 1) // bottom left
                    neighbours++;
                if (parentGen[x, y-1] == 1)  // middle top
                    neighbours++;
                if (parentGen[x, y+1] == 1)  // middle bottom
                    neighbours++;
                if (parentGen[x+1, y-1] == 1) // top right
                    neighbours++;
                if (parentGen[x+1, y] == 1)  // right
                    neighbours++;
                if (parentGen[x+1, y+1] == 1) // bottom right
                    neighbours++;
            }
    }

The only thing I can think of is that my program is checking coordinates of < 0? How do I go about fixing this?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
tom
  • 801
  • 1
  • 7
  • 4

5 Answers5

9

Your first coordinates are parentGen[-1, -1], this will always throw the exception.

You need to check if the cell you're on has any neighbors to the left, right, top, or bottom. For example, x = 0 has no neighbors to the left and y = 20 has no neighbors to the bottom. You may wish to break this out to other functions, such as HasNeighborsLeft(int x), etc.

edit: sample code

if(x > 0 && y > 0 && parentGen[x - 1, y - 1] == 1)
{
    neighbors++;
}

You can factor this out to it's own functions though, and you can wrap this kind of logic around all of the checks that involve x - 1 for example.

marr75
  • 5,666
  • 1
  • 27
  • 41
  • Setting x to 1, fixes the problem, but I know that this isn't good coding practice? – tom Sep 13 '10 at 15:25
  • It's not bad practice, it's bad logic. You won't check all the conditions you want if you do this. – Steve Townsend Sep 13 '10 at 15:27
  • Setting x to 1 only stops the exception from being thrown, doesn't actually solve the problem because now you're not checking the neighbors of cell (0, 0), what you really need to do is not check certain neighboring sections that do not exist, for example, cells left of the x = 0 column and cells below the y = 20 row. – marr75 Sep 13 '10 at 15:27
1

You need boundary condition checks on both x and y at top and bottom of their range. You cannot legally index the entire array using +1 and -1 offsets. Break up your check into boundary condition cases where x == 0, x == arrayRows-1 (by not checking the invalid relative offsets here), and then check cases where x+1 and x-1 are always valid in an else. Similarly with y.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
0

You're array goes from 0->21. As well, you're testing values at [-1, -1] and [22, 22]You can fix it by chainging your for statement(s) to

for (int x = 1; x <= arrayCols - 1; x++)
    for (int y = 1; y <= arrayRows - 1; y++)

In addition, problems with loops are almost always caused by a small number of cases that you can always check for:

  1. Your for statement a) starts at a lower bound than the array, or b) finishes at a higher one a) for (int x = -1; b) for (int x = 0; x <= array.Length

  2. Your code in the loop accesses values outside of your indexer range for (int x = 0... array[x-1, ...

  3. Your collection isn't initialized

In this case, your problem 2.

Steven Evers
  • 16,649
  • 19
  • 79
  • 126
0

The problem is that you are looking at the previous and next values (-1 and +1) which will obviously go outside the array bounds at either ends of the array.

There are a few options solving this:

  • Create a bigger array with a dummy 'border' around the edge which you don't use for your board but allows you to use code very similar to that which you have now (with your -1 and +1 previous and next cell logic). (Imagine a chess board that is 10x10 where you are not allowed to play in the outermost squares).
  • Scatter loads of 'if' statements to check if you're at the first or last item in the array and thus avoid making any array accesses that are invalid.
  • Create a function to retrieve an item at a particular cell and put conditional logic in this function for dealing with the array bounds.

Personally I would go with the last option, build yourself a function which gets the state of the specified cell, checks that the indices are valid and returns a default value if they are not. For example:

private const int EMPTY_CELL = 0;
private const int INVALID_CELL = EMPTY_CELL; // for now the same, but gives scope to handle separately

private int GetCellState(int row, int column)
{
    if (row < 0) return INVALID_CELL;
    if (column < 0) return INVALID_CELL;
    if (row >= arrayRows) return INVALID_CELL;
    if (column >= arrayColumns) return INVALID_CELL;

    return parentGen[row, column];
}

It is then simply a matter of swapping your direct accesses to parentGen with calls to the function.

Paul Ruane
  • 37,459
  • 12
  • 63
  • 82
0

you could start by creating a sequence of only the valid indices and then iterate the combinations of those:

static int arrayRows = 20;
static int arrayCols = 20;

public void printBoard()
{
    var sequences = from row in Enumerable.Range(0, arrayRows)
                    from column in Enumerable.Range(0, arrayCols)
                    select new
                    {
                        Rows = (from xs in new[] { row - 1, row, row + 1 }
                                where xs >= 0 && xs < 20
                                select xs),
                        Columns = (from ys in new[] { column - 1, column, column + 1 }
                                   where ys >= 0 && ys < 20
                                   select ys)
                    };
    //now that we have a sequence with all the needed (valid) indices 
    //iterate through the combinations of those
    var neighbours = (from seq in sequences
                      from row in seq.Rows
                      from column in seq.Columns
                      where row != column && parentGen[row, column] == 1
                      select 1).Count();

}
Rune FS
  • 21,497
  • 7
  • 62
  • 96