减少计算邻居的复杂性康威的生命游戏

问题描述

我必须实施康威的生命游戏。一切正常,并且给定的测试正在通过。我唯一的问题是这种方法在我的文件上运行 PMD 规则时会出现复杂性错误。我知道很多 if 语句是造成这种情况的原因,但是在尝试将它们压缩成更小的组时,我不小心破坏了我的代码

内容如下:

The method 'getNeighbourCount(int,int)' has a cyclomatic complexity of 21.

The method 'getNeighbourCount(int,int)' has an NPath complexity of 20736,current threshold is 200

优化此方法的最佳选择是什么?

public Integer getNeighbourCount(int x,int y) {
        // x = column (20),y = row (15)

        int countNeigbours = 0;
        if (x != 0 && y != 0 && isAlive(x - 1,y - 1)) {
            countNeigbours++;
        }

        if (x != 0 && isAlive(x - 1,y)) {
            countNeigbours++;
        }

        if (x != 0 && y != rows - 1 && isAlive(x - 1,y + 1)) {
            countNeigbours++;
        }
        if (y != 0 && isAlive(x,y - 1)) {
            countNeigbours++;
        }
        // check self
        if (y != rows - 1 && isAlive(x,y + 1)) {
            countNeigbours++;
        }

        if (x != columns - 1 && y != 0 && isAlive(x + 1,y - 1)) {
            countNeigbours++;
        }

        if (x != columns - 1 && isAlive(x + 1,y)) {
            countNeigbours++;
        }

        if (x != columns - 1 && y != rows - 1 && isAlive(x + 1,y + 1)) {
            countNeigbours++;
        }

        return countNeigbours;
}

isAlive 返回布尔值,如果单元格被采用(真)或不采用(假)。

解决方法

从当前位置循环“delta x”和“delta y”:

for (int dx : new int[]{-1,1}) {
  if (x + dx < 0 || x + dx >= columns) continue;

  for (int dy : new int[]{-1,1}) {
    if (y + dy < 0 || y + dy >= rows) continue;
    if (dx == 0 && dy == 0) continue;

    if (isAlive(x + dx,y + dy)) countNeighbours++;
  }
}

(当然,您不必使用数组和增强的 for 循环:您可以只执行 for (int dx = -1; dx <= 1; ++dx) 或其他任何您喜欢的操作)

,

我不知道这是否会提供加速,但是您可以尝试使用第二个数组来保存总和,并在设置或清除单个单元格时增加或减少这些值。这用检查替换了许多“isAlive”检查,以判断一个单元是否应该被打开或关闭,并将单元邻接计算减少到那些被切换的单元,这应该比对整个数组重复计算要少得多.也就是说,对于大部分为空的网格,只有一小部分单元格需要重新计算,比整个网格少得多。

此外,您可以尝试使用整行 isActiveminActivemaxActive 值。这将进一步减少循环量,但会增加每次迭代的复杂性和成本。活动单元的稀疏性将决定是否通过减少迭代次数来平衡额外成本。