tags:

views:

111

answers:

3

I have an array (of 9 elements, say) which I must treat as a (3 by 3) square. For the sake of simplifying the question, this is a one-based array (ie, indexing starts at 1 instead of 0).

My goal is to determine valid adjacent squares relative to a starting point.

In other words, how it's stored in memory: 1 2 3 4 5 6 7 8 9

How I'm treating it:
7 8 9
4 5 6
1 2 3

I already know how to move up and down and test for going out of bounds (1 >= current_index <= 9)

edit: I know the above test is overly general but it's simple and works.

//row_size = 3, row_step is -1, 0 or 1 depending on if we're going left,
//staying put or going right respectively.
current_index += (row_size * row_step); 

How do I test for an out of bounds condition when going left or right? Conceptually I know it involves determining if 3 (for example) is on the same row as 4 (or if 10 is even within the same square as 9, as an alternate example, given that multiple squares are in the same array back to back), but I can't figure out how to determine that. I imagine there's a modulo in there somewhere, but where?

Thanks very much,
Geoff

Addendum:
Here's the resulting code, altered for use with a zero-based array (I cleaned up the offset code present in the project) which walks adjacent squares.

bool IsSameSquare(int index0, int index1, int square_size) {
  //Assert for square_size != 0 here
  return (!((index0 < 0) || (index1 < 0))
      && ((index0 < square_size) && (index1 < square_size)))
      && (index0 / square_size == index1 / square_size);
}
bool IsSameRow(int index0, int index1, int row_size) {
  //Assert for row_size != 0 here
  return IsSameSquare(index0, index1, row_size * row_size)
  && (index0 / row_size == index1 / row_size);
}
bool IsSameColumn(int index0, int index1, int row_size) {
  //Assert for row_size != 0 here
  return IsSameSquare(index0, index1, row_size * row_size)
      && (index0 % row_size == index1 % row_size);
}

//for all possible adjacent positions
for (int row_step = -1; row_step < 2; ++row_step) {
  //move up, down or stay put.
  int row_adjusted_position = original_position + (row_size * row_step);
  if (!IsSameSquare(original_position, row_adjusted_position, square_size)) {
    continue;
  }
  for (int column_step = -1; column_step < 2; ++column_step) {
    if ((row_step == 0) & (column_step == 0)) { continue; }
    //hold on to the position that has had its' row position adjusted.
    int new_position = row_adjusted_position;

    if (column_step != 0) {
      //move left or right
      int column_adjusted_position = new_position + column_step;
      //if we've gone out of bounds again for the column.
      if (IsSameRow(column_adjusted_position, new_position, row_size)) {
        new_position = column_adjusted_position;
      } else {
        continue;                          
      }
    } //if (column_step != 0)
    //if we get here we know it's safe, do something with new_position
    //...
  } //for each column_step
} //for each row_step
A: 

You should be using a multidimensional array for this.

If your array class doesn't support multidimensional stuff, you should write up a quick wrapper that does.

Anon.
Using a multidimensional array is not an option, but thanks for your reply nonetheless.
Geoff
Why is it not an option? You can write a lightweight wrapper, and still access the underlying linear array if you have something that needs to access it.
Anon.
If you're after performance with something moving around the array or checking neighbors, 2D is not an option. Looking at grid[pos+offset] is much faster than grid[pos_x+offset_x][pos_y+offset_y].
phkahler
It doesn't solve the right problem. Thanks again though.
Geoff
I'm not talking about nested arrays. I'm talking about C-style multidimensional arrays - `array[x, y]`. Which are just syntactic sugar over a (single) normal array anyway. So why isn't it an option?
Anon.
I agree that using a multi-dimensional array class is nice when it's appropriate (provided the wrapper code gets optimized away), but it just isn't in my case. See my comment under Mark Byers' answer to understand why. Thanks again for your fervent interest!
Geoff
Your comment there doesn't really explain anything. In fact, it seems unrelated to what's being discussed in these comments here. Now I'm actually curious as to what you could possibly be doing with these that makes a multidimensional array wrapper infeasible.
Anon.
I answered exactly that question in said comment, might I suggest rereading it? :)
Geoff
+1  A: 

This is easier if you used 0-based indexing. These rules work if you subtract 1 from all your indexes:

  • Two indexes are in the same square if (a/9) == (b/9) and a >= 0 and b >= 0.
  • Two indexes are in the same row if they are in the same square and (a/3) == (b/3).
  • Two indexes are in the same column if they are in the same square and (a%3) == (b%3).
Mark Byers
I was using a one-based array as a simplification, but in reality it is indeed a zero-based array. Cell zero represents a separate source node which is excluded from the square cell walking. Thanks for your reply, I'll see what I can do with this. :)
Geoff
I just want to point out this relies on integer division, not a problem. And darn you for beating me to the punch!
kramthegram
Hmm. Is there a way of avoiding integer division? kramthegram's point hadn't occurred to me righ away until testing it.Apparently -1/3 and 0/3 are somehow equal (I know the details of why, they just hadn't occurred to me).
Geoff
@Geoff: OK, I hadn't considered negative indexes. I've updated my answer to take account of that too.
Mark Byers
I added the boundaries necessary to check for past-the-end indices and it works like a charm! thanks a million!
Geoff
A: 

There are several way to do this, I'm choosing a weird one just for fun. Use modulus.

Ase your rows are size 3 just use modulus of 3 and two simple rules.

If currPos mod 3 = 0 and (currPos+move) mod 3 = 1 then invalid
If currPos mod 3 = 1 and (currPos+move) mod 3 = 0 then invalid

this check for you jumping two a new row, you could also do one rule like this

if (currPos mod 3)-((currPos+move) mod 3)> 1 then invalid

Cheers

kramthegram