用模数环绕网格

时间:2015-09-18 17:09:11

标签: c++ algorithm modulo cellular-automata

我正在尝试编写一个程序,在20x60单元格的网格上实现Conway的生命游戏。网格应环绕,使左侧连接到右侧,顶部连接到底部。

因此,任何位置为(0, col)的单元格都会在(maxRow, col)处有一个邻居。位置为(row, 0)的任何单元格都会在(row, maxCol)处有一个邻居。

以下函数用于计算相邻单元格的数量。它适用于不在边缘的坐标,但不适用于那些坐标。例如,如果(0, 10)处有点,(0, 11)(0, 12)(0, 10)被传递到函数中,它将返回一个高数字作为邻居计数而不是{ {1}}。我知道mod运算符1会有所帮助,但我不明白如何使用它。

%

1 个答案:

答案 0 :(得分:1)

在提供解决方案之前,让我先做一些观察。

  • 添加一些网格值并稍后减去其他网格值不是一个好主意。您应该首先计算正确的网格坐标。

  • 当您编写count += grid[i][j];时,您正在使用可能无效的数组索引。例如,当i = row - 1为零时,row会产生i -1的值。

  • 您的代码暗示maxrow是行数,因为您正在编写maxrow-1,但名称maxrow表示最大行索引。这令人困惑。调用行数numRows会更好,然后最大的行索引是numRows - 1。同样,最好将maxcol替换为numCols

现在到了问题的核心。值row - 1可以等于-1row + 1可以等于numRows。这两个都是无效的行索引。同样,col - 1col + 1可能会导致无效的列索引-1numCols。解决问题的一种方法是测试这些特定值并用环绕索引替换它们:

int count = 0;
for (int i = row - 1; i <= row + 1; i++) {
  int R = i;
  if (R == -1) {
    R = numRows - 1;
  } else if (R == numRows) {
    R = 0;
  }
  for (int j = col - 1; j <= col + 1; j++) {
    if (i == row && j == col) {
      continue;  // Skip grid[row][col].
    }
    int C = j;
    if (C == -1) {
      C = numCols - 1;
    } else if (C == numCols) {
      C = 0;
    }
    count += grid[R][C];
  }
}

这是一种解决问题的高性能方法,因为测试和分配比模数更快的操作,但它也是很多代码。我们可以在模运算符的帮助下编写更简洁的代码。

我们想写i % numRows,但是当i为-1时,C ++会将其计算为-1。这是因为模数运算对于负值是模糊的而C++ has chosen an interpretation不能保证非负结果。

要解决此问题,我们在使用模numRows之前将i添加到numRows。这可以确保我们始终采用正数的模数。现在我们可以计算grid[row][col]的八个邻居中的活细胞数量,如下所示。

int count = 0;
for (int i = row - 1; i <= row + 1; i++) {
  for (int j = col - 1; j <= col + 1; j++) {
    if (i == row && j == col) { 
      continue;  // Skip grid[row][col].
    }
    count += grid[(i + numRows) % numRows][(j + numCols) % numCols];
  }
}