如何降低圈复杂度?

时间:2020-03-01 09:25:05

标签: java arrays refactoring minesweeper cyclomatic-complexity

感谢您阅读我的问题。 我目前正在Coursera上Java课程,并被要求在minesweeper上编写一个程序进行作业。我的代码创建了正确的结果,但是根据自动分频器,我的代码“过于复杂,圈复杂度为60”,因此大大降低了分数。我知道条件和循环太多,但是我很难将其简化。

这是我的代码。它需要3个整数命令行参数m,n和k来创建一个m×n的网格,其中k个地雷位于随机位置。我使用“ 5”标记地雷,而不是“ ”,因为图块中可以得到的最高数字是4(因为图块具有4个边)。如果两个地雷并排放置,则可能会将额外的值添加到其标记“ 5”。因此,当我打印出它们时,使所有> = 5的值都变成“ ”。每个值都用两个空格分隔。

public class Minesweeper {
  public static void main(String[] args) {
    int m = Integer.parseInt(args[0]);
    int n = Integer.parseInt(args[1]);
    int k = Integer.parseInt(args[2]);
    int[][] mine = new int[m][n];
    //put the mines
    for(int z = 0; z < k; z++) {
      int randomX = (int) (Math.random() * m);
      int randomY = (int) (Math.random() * n);
      mine[randomX][randomY] = 5; 
    }

    for(int y = 0; y < n; y++) {
      for(int x = 0; x < m; x++) {
        //first row of the grid
        if(y == 0) {
          //upper left corner
          if(x == 0) {
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            }
          }
          //upper right corner
          else if(x == m - 1) {
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            } 
          }
          //mid of first row
          else {
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            } 
          }
        }
        //mid rows
        else if(y > 0 && y < n - 1) {
          //left side
          if(x == 0) {
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
          }
          //right side
          else if(x == m - 1) {
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
          }
          //mid
          else {
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y + 1] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
          } 
        }
        //bottom row
        else if(y == n - 1) {
          //bottom left corner
          if(x == 0) {
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
          }
          //bottom right corner
          else if(x == m - 1) {
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
          }
          //middle of the bottom row
          else {
            if(mine[x + 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x - 1][y] >= 5) {
              mine[x][y] += 1;
            }
            if(mine[x][y - 1] >= 5) {
              mine[x][y] += 1;
            }
          }
        }
      }
    }
  //print out the grid
    for(int y = 0; y < n; y++) {
      for(int x = 0; x < m; x++) {
        //println at the right edge of the grid
        if(x == m - 1) {
          if(mine[x][y] >= 5) {
            System.out.println("*");
          }
          else {
            System.out.println(mine[x][y]);
          }
        }
        //other tiles, no need to switch lines
        else {
          if(mine[x][y] >= 5) {
            System.out.print("*  ");
          }
          else {
            System.out.print(mine[x][y] + "  ");
          }
        }
      } 
    }
  }
}

感谢您的宝贵时间,我非常感谢您提出任何建议。

2 个答案:

答案 0 :(得分:0)

如果您在循环中进行左/右/上/下测试以节省大量代码,则可以降低复杂性:

for (int tryX = -1; tryX <= 1; tryX++) {
  for (int tryY = -1; tryY <= 1; tryY++) {
    if(mine[x + tryX][y + tryY] >= 5) {
      mine[x][y] += 1;
    }
  }
}

由于这占用了大量代码行,因此将降低复杂度。 您应该使用IDE将代码提取到方法中(对于IntelliJ,请参见here)。 好的提取点是循环。

我看到两个很好的提取点:

  1. initArrayWithRandomMines()
  2. calculateNeighborMines()

答案 1 :(得分:0)

我不会共享重构的代码,但会给您一些想法和示例,您应该这样做。我认为这对您的学习会更有用。

您应该找到相同的条件,并将其从多个分支中提取到一个。我建议您从内部条件开始,然后再到外部。

让我们以具有y == 0条件的分支为例:

if(x == 0) {
  if(mine[x + 1][y] >= 5) {
     mine[x][y] += 1;
  }
  if(mine[x][y + 1] >= 5) {
    mine[x][y] += 1;
  }
}
//upper right corner
else if(x == m - 1) {
  if(mine[x - 1][y] >= 5) {
     mine[x][y] += 1;
  }
  if(mine[x][y + 1] >= 5) {
     mine[x][y] += 1;
  } 
//mid of first row
else {
  if(mine[x - 1][y] >= 5) {
    mine[x][y] += 1;
  }
  if(mine[x + 1][y] >= 5) {
    mine[x][y] += 1;
  }
  if(mine[x][y + 1] >= 5) {
    mine[x][y] += 1;
  } 
}

您可以看到您在mine[x + 1][y] >= 5x == 0分支中选中了else。您可以将两个条件合而为一,它看起来像x < m-1,现在代码看起来像:

if(x < m-1 && mine[x + 1][y] >= 5) {
  mine[x][y] += 1;
}

if(x == 0) {
  if(mine[x][y + 1] >= 5) {
    mine[x][y] += 1;
  }
}
//upper right corner
else if(x == m - 1) {
  if(mine[x - 1][y] >= 5) {
     mine[x][y] += 1;
  }
  if(mine[x][y + 1] >= 5) {
     mine[x][y] += 1;
  } 
//mid of first row
else {
  if(mine[x - 1][y] >= 5) {
    mine[x][y] += 1;
  }
  if(mine[x][y + 1] >= 5) {
    mine[x][y] += 1;
  } 
}

继续每个if语句,条件是在何处使用x。当您完成x时,请对y进行相同的操作。从几个分支中提取公共部分。

以及有关打印结果的部分。请考虑您应该做什么。您应该根据*打印mine[x][y]mine[x][y]==5,而取决于System.out.println()打印空格或换行(x == m - 1)。现在考虑如何实现它。