Как уменьшить сложность цикломатику c? - PullRequest
3 голосов
/ 01 марта 2020

Спасибо, что прочитали мой вопрос. В настоящее время я учусь на Coursera Java, и меня попросили написать программу для тральщика для этого задания. Мой код дает правильный результат, но моя оценка была значительно вычтена, потому что мой код «чрезмерно сложен, с цикломатикой c сложность 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 голосов
/ 01 марта 2020

Я не буду делиться переработанным кодом, но дам вам некоторые идеи и примеры, которые вы должны сделать. Я думаю, что это будет более полезно для вашего обучения.

Вы должны найти то же условие и извлечь их из нескольких веток в одну. Я рекомендую вам начинать с внутренних условий и после того, как вы вышли на улицу.

Давайте рассмотрим ветку с условием 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] >= 5, когда x == 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 в условии. когда вы закончите sh с x, выполните те же действия с условиями с y. Извлеките общие части из нескольких ветвей.

И о части, где вы печатаете результат. Пожалуйста, подумайте, что вы должны сделать. Вы должны напечатать * или mine[x][y] зависит от mine[x][y]==5, а пробелы или new_line (System.out.println()) зависят от x == m - 1. Теперь подумайте, как это реализовать.

0 голосов
/ 01 марта 2020

Вы можете уменьшить сложность, выполнив тестирование влево / вправо / вверх / вниз в al oop, чтобы сохранить много строк кода:

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). Хорошие точки извлечения - это циклы.

Я вижу две хорошие точки извлечения:

  1. initArrayWithRandomMines ()
  2. вычисленияNeighborMines ()
...