(生命游戏)如何循环遍历矩阵的外层而不检查它的外部,同时检查邻居?

时间:2018-01-09 12:07:34

标签: c matrix logic indexoutofboundsexception conways-game-of-life

矩阵中的每个点代表一个生存或死亡的细胞。我必须计算每个细胞有多少个ALIVE邻居。我有一个功能,但它检查边界之外的单元格。我不知道如何在不执行大量if-else语句的情况下同时检查邻居并跟踪边缘。

void Neighbours(int rows, 
                int cols, cell world[rows][cols], 
                int neighbors[rows][cols]) {

//Loop through each cell in the matrix. 
for(int rCell = 0; rCell < rows; rCell++){
  for(int cCell = 0; cCell < cols; cCell++) {
    //Reset neighbor count for each cell.
    neighbors[rCell][cCell] = 0;
    //Check cell status in cell's vicinity of each cell. 
    for(int surroundR = -1; surroundR <= 1; surroundR++){
      for(int surroundC = -1; surroundC <= 1; surroundC ++) {
        //CONDITIONS
        //1. If the cell is alive,
        //2. if the cell is not itself,
        //3. if it does exist within the boundaries of the matrix.
        if(field[rCell - surroundR][cCell - surroundC].status == ALIVE) {
          if(!(surroundR  == 0 && surroundC  == 0) && (rCell-surroundR < rows) && (cCell-surroundC < cols) && (cCell-surroundC  >= 0) && (rCell-surroundR  >= 0)) {
            neighbors[rCell][cCell] += 1;
          }
        }
      }
    }
  } 
}
}

4 个答案:

答案 0 :(得分:3)

处理此问题最简单的方法是添加两个虚拟行和列:矩阵上方的一行,矩阵下方的一行,矩阵左侧的一列以及矩阵右侧的一列。您将它们一次性设置为DEAD,并仅在原始矩阵中的单元格上运行循环。

答案 1 :(得分:2)

总是在进行此类检查时 - 在索引到数组之前检查索引是否在您要索引的数组的大小范围内。在索引到数组之前,您必须先执行此操作。之前由于访问数组索引超出限制,您有未定义的行为。

if( (rCell - surroundR) <= rows-1 && (cCell - surroundC)<= cols-1 && (rCell - surroundR)>=0 && (cCell - surroundC)>=0 ) {
   /* then do rest of work */

}

答案 2 :(得分:2)

您可以通过使用仅包含 dead 元素的每一行包含一行的数组来轻松销售一些内存以节省时间,并且仅在内部进行处理。算法变得更简单,错误风险更小,但必须更改整个代码以添加2行和2行:

void Neighbours(int rows, 
                int cols, cell world[rows][cols], 
                int neighbors[rows][cols]) {

//Loop through each cell in the matrix. 
for(int rCell = 1; rCell < rows-1; rCell++){   // limit to the interior
  for(int cCell = 1; cCell < cols-1; cCell++) {
     // remaining part of the loops is unchanged

答案 3 :(得分:2)

一种方法是在阵列的边缘用行和列的死单元填充数组。

另一种方法是编写单独的代码片段:

  • 一个循环处理数组的内部单元格(省略边缘行和列),检查所有邻居。

  • 一个循环处理顶行,仅检查顶行单元格的实际邻居。只处理行内部的单元格,省略角落。

  • 同样,底行有一个循环,左栏有一个循环,右栏有一个循环。

  • 分别检查四个角。

虽然这是更多代码,但它执行的检查次数少于检查每个单元格的一个循环。请注意,可以组合顶行和底行的循环(因为它们共享列坐标),并且可以组合左边缘和右边缘的循环。

可以进一步减少计算负荷。例如,主阵列中每个3 * 1条带中的活细胞计数可以被缓存(在辅助阵列中或简单地在精心制作的循环中的变量中)以便重复使用。主阵列内部的每个这样的条带在计算各个单元周围的3 * 3方块时使用了三次,因此缓存它们的计数可以消除一些重复的工作。

(关于填充:要使用正确的C代码,您需要两列,一个在左侧,一个在右侧。但是,如果您的C实现支持访问子阵列元素超出范围,只要被寻址的元素在完整的数组,或者手动将两个维度映射到一维数组,然后一个填充列就足够了,因为它既可以在数组左边缘的左边,也可以在右边缘的右边。)< / p>