Edwin Flores
Edwin Flores

Reputation: 23

How to check all neighbors of a character in a string vector

Game of conway. Trying to access all neighbors of a each "cell" that i read in from a file.

If a cell is alive, it stays alive for the next generation if it has exactly two or three neighbors.

If a cell is dead, then it becomes alive for the next generation if it has exactly three neighbors.

E has exactly 8 neighbors in both situations. Im having issues with the top line of the next generation:

.........                 F......DE
...ABC...                 I......GH
...DEF...                 .........
...GHI...                 .........
.........                 C......AB

file is read into currentgen, a string vector nextgen is a copy of currentgen, that I change as needed

//find neighbors
    for (size_t i=0; i < currentgen.size(); i++){
                for(size_t j = 0; j < currentgen[0].length(); j++){ 
                //neighbor count
                int neighborcount = 0;
                //south neighbor
                if(currentgen[(i+1) % currentgen.size()][j] == 'O'){
                    neighborcount++;
                }
                //north
                if(currentgen[(i-1) % currentgen.size()][j] == 'O'){
                    neighborcount++;
                }
                
                //left
                if(currentgen[i][(j-1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                
                //right
                if(currentgen[i][(j+1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                
                //south right
                if(currentgen[(i+1) % currentgen.size()]
                [(j+1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                
                //south left
                if(currentgen[(i+1) % currentgen.size()]
                [(j-1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                
                //north right
                if(currentgen[(i-1) % currentgen.size()]
                [(j+1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                //north left
                if(currentgen[(i-1) % currentgen.size()]
                [(j-1) % currentgen[i].length()] == 'O'){
                    neighborcount++;
                }
                
                //if cell is alive
                if(currentgen[i][j] == 'O'){
                    nextgen[i][j] = '.';
                    if(neighborcount == 2){
                    nextgen[i][j]= 'O';
                    }
                    if(neighborcount == 3){
                    nextgen[i][j]= 'O';
                    }
                    
                
                }
                
                //if cell is dead
                if(currentgen[i][j] == '.'){
                    if(neighborcount == 3){
                    nextgen[i][j]= 'O';
                
                    }
                }

Upvotes: 1

Views: 284

Answers (3)

Yamahari
Yamahari

Reputation: 2038

Something like this:

#include <iostream>
#include <utility>

int main() {
  char field[5][5]{
      '.', '.', '.', '.', '.',
      '.', '.', 'O', '.', '.',
      '.', 'O', '.', 'O', '.',
      '.', '.', 'O', '.', '.',
      '.', '.', '.', '.', '.'
  };

  int posX = 2, posY = 2, count = 0;
  for (int y = -1; y <= 1; ++y)
    for (int x = -1; x <= 1; ++x) {
      const char symbol = field[(posY + y + 5) % 5][(posX + x + 5) % 5];
      count += static_cast<int>((y != 0 || x != 0) && symbol == 'O');
    }
  std::cout << count << '\n';
}

or

const char symbol = field[(posY + y + HEIGHT) & (HEIGHT - 1)][(posX + x + WIDTH) & (WIDTH - 1)];

if your field size is a power of 2 in x/y direction

Upvotes: 0

Yurii A
Yurii A

Reputation: 379

Here is a small piece of advice on how to avoid hard-coding the coordinates (south, north, left, right, etc.). You can use 2 arrays, namely dx and dy, which indicates the delta of x and y coordinates.

For example, start with a north neighbour and go clockwise (see the picture attached):

dx and dy description

int dx[] = {0, 1, 1, 1, 0, -1, -1, -1};
int dy[] = {-1, -1, 0, 1, 1, 1, 0, -1};

Now, in order to cycle through the neighbours of a cell (x, y), just add the corresponding dx and dy entries.

As pointed out by @cigien, you should not compute a remainder operator for negative values. The easiest thing to do is to add n and take modulo n, where n is a size of the field. It will save you from having negative value before modulo operation while preserving the same result, since n % n = 0.

Here is how you can cycle through the neighbours of (x, y):

int x;
int y;

// fill x and y

for(int d = 0; d < 8; ++d)
{
    int nx = x + dx[d];
    int ny = y + dy[d];

    nx = (nx + n) % n;
    ny = (ny + n) % n;

    // horray!
}

Upvotes: 0

cigien
cigien

Reputation: 60238

The issue with your code is that you're relying on % having the usual meaning of remainder. However, in c++, doing % on negative values will give you a remainder towards 0.

So the following expression is:

-1 % 5 // -1 not 4

To do the remainder correctly, you can add the value you're using as the modulus, and then you're guaranteed to have a positive number, and the calculation will work:

(-1 + 5) % 5  // 4 yay!!

Also, all those if conditions to check the neighbors is very verbose. You could simplify that to:

for (size_t i=0; i < currentgen.size(); i++) {
  for(size_t j = 0; j < currentgen[0].length(); j++) { 
    //neighbor count
    int neighborcount = 0;
    for (int i_offset : {-1, 0, 1})
      for (int j_offset : {-1, 0, 1}) 
        if (i && j && currentgen[(i + i_offset + currentgen.size()) 
                                 % currentgen.size()]
                                [(j + j_offset + currentgen[i].size()) 
                                 % currentgen[i].size()] == 'O')
          neighborcount++;
 
    //if cell is alive
    // ... etc

Upvotes: 1

Related Questions