2013-08-26 3 views
1

В настоящее время я пытаюсь проверить ячейки сетки для данных во всех ячейках вокруг нее. Вверх, влево, вниз, вправо и во всех диагоналях. Как я могу использовать бросок исключений, поэтому мне не нужно отдельно кодировать стороны и углы?Проверка сетки, исключение из запредельных исключений

Это в настоящее время то, что у меня есть. isIsAlive() просто проверяет, активна ли ячейка. Соседи для ячейки включают в себя все активные клетки.

public void calcNeighbors() throws ArrayIndexOutOfBoundsException{ 

    int x =0; 

    int y =0; 
    int neighbors = 0; 



    while(x < 9){ 
     while(y < 9){ 

      if(generation[x+1][y+1].isIsAlive()){ 
       neighbors++; 

      } 
      if(generation[x+1][y].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x+1][y-1].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x][y-1].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x-1][y-1].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x-1][y].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x-1][y+1].isIsAlive()){ 
       neighbors++; 
      } 
       if(generation[x][y+1].isIsAlive()){ 
       neighbors++; 
      } 
      y++; 
     } 
     x++; 
     neighbors = 0; 
    } 
} 
+3

Ответ: не надо. Не используйте исключения для исключительного потока управления. –

+0

Это аналогичный поток кода через вопрос ожидания: http: // stackoverflow.com/questions/16320014/java-optimization-nitpick-is-it-faster-to-cast-something-and-let-it-throw-excep/16320082 # 16320082 В дополнение к обычным проблемам чтения я сделал несколько тестов относительно эффективность. Это делает для мрачного чтения. «Слишком долго не читал» исключения были в 20 раз медленнее, чем экземпляр (который сам по себе довольно медленный) –

+0

Об общих советах; использование «9» - магическое число; **Плохо**. Что делать, если размер массива изменяется, используйте array.length. вы можете получить второе измерение с помощью массива [0] .length. –

ответ

3

Вы не должны бросать свое собственное исключение, если гипотетический сосед окажется вне пределов. Java все равно будет бросать ArrayIndexOutOfBoundsException.

Перед доступом к массиву вам необходимо проверить свои границы; не обращайтесь к массиву, если ваш x или y выходит за пределы допустимого диапазона.

+0

+1 И что важно, при проверке «вне диапазона» не используйте магические числа в коде (например, '9'), используйте фактическую длину массива. (* Даже если * в очень большой сетке N/NE/E/SE/S/SW/W/NW, может быть только девять - подождите, не так ли? 8 - соседи.) –

+0

Так что я могу 't, скажем ... пусть ошибка произойдет, бросьте ее, а затем пусть ничего не сделает? Кроме того, это сетка 10x10. Вот почему массив длинный 9. – Xenorosth

+0

@Xenorosth: Вы * можете *, вы просто * не должны *. Исключения для * исключительных * условий, а выброс их не является бесплатным. –

4

Ваш список блоков if является уродливым (должен быть тупым) и опасным. Вместо этого используйте вложенные для циклов, но вычисляем верхнюю и нижнюю границы циклов for, учитывающих края.

for (int x = 0; x < MAX_X; x++) { 
    for (int y = 0; y < MAX_Y; y++) { 

    int minRow = Math.max(0, x - 1); 
    int maxRow = Math.min(MAX_X - 1, x + 1); 
    int minCol = Math.max(0, y - 1); 
    int maxCol = Math.min(MAX_Y - 1, y + 1); 

    for (int row = minRow; row <= maxRow; row++) { 
     for (int col = minCol; col <= maxCol; col++) { 
     if (row != x || col != y) { 
      if(generation[row][col].isIsAlive()){ 
      neighbors[x, y]++; 
      } 
     } 
     } 
    } 
    } 
} 
+0

@TJCrowder: основная проблема заключается в том, что он не позволяет Java сделать тяжелый подъем для него, поскольку все, что ему нужно использовать, является самой простой логикой для проверки того, что он не выходит за пределы. В моем примере выше я называю ** внутренним ** двумя циклами, которые я обсуждаю, а не внешними для/while циклов. –

+0

Да, но эти петли не были там, когда я прокомментировал. Повторите редактирование: разве это не так много? –

+0

@ T.J.Crowder: нет, я так не думаю. Я сам использовал этот код с моей игрой в жизни и с моей программой minesweeper. –

1

Не рекомендуется использовать исключения для этой цели. Но если вы настаиваете, вы можете сделать это следующим образом. Во-первых, определить метод

public boolean isAlive(int x,int y) { 
    try { 
     return this.generation[x][y].isIsAlive() ; 
    } catch(IndexOutOfBoundsException ex) { 
     return false ; // Or whatever you want to be the default 
    } 
} 

И затем использовать isAlive(x+1,y+1) вместо generation[x+1][y+1].isIsAlive() и так далее.

Кроме того, создается впечатление, что вы ошибочно объявляете локальную переменную int neighbors = 0;. Я говорю это, потому что вы продолжаете устанавливать его в 0 в конце, но вы его нигде не храните. Лично я хотел бы определить поле neighbors в какой бы это базовый класс generation и:

for(int x= 0 ; x < generation.length ; x++) { 
    for(int y= 0 ; y < generation[x].length ; y++) { 
     generation[x][y].neighbors= 0 ; 
     for(int dx= -1 ; dx <= 1 ; dx++) { 
      for(int dy= -1 ; dy <= 1 ; dy++) { 
       if(! (dx == 0 && dy == 0) && isAlive(x+dx,y+dx)) { 
        generation[x][y].neighbors++; 
       } 
     } 
    } 
} 

Меня беспокоит так много if с 3 являются: 1. Это очень легко сделать ошибку. 2. Для добавления любого другого кода во все if s потребуется много времени (и подвержено ошибкам). 3. Логику легче понять. Хотя вы также можете добавить комментарий, объясняющий, что вы собираетесь проверять соседей, и что соседи - это все 8 ячеек, где строка или столбец равна +1 или -1 текущей ячейке.

Кроме того, теперь, когда мы сократили число if с, мы могли бы также встраивать функцию выше и написать следующее:

for(int x= 0 ; x < generation.length ; x++) { 
    for(int y= 0 ; y < generation[x].length ; y++) { 
     generation[x][y].neighbors= 0 ; 
     for(int dx= -1 ; dx <= 1 ; dx++) { 
      for(int dy= -1 ; dy <= 1 ; dy++) { 
       try { 
        if(! (dx == 0 && dy == 0) && isAlive(x+dx,y+dx)) { 
         generation[x][y].neighbors++; 
        } 
       } catch(IndexOutOfBoundsException ex) { 
        // Do whatever you want in this case 
       } 
      } 
     } 
    } 
} 

Теперь без злоупотребляющих исключений (который на сегодняшний день является наиболее рекомендуется), я бы сказал, что добавить функцию

public boolean isValidNeighbor(int i,int j) { 
    return 0 <= i && i < generation.length && 0 <= j && j < generation[i].length ; 
} 

И ваш код становится:

for(int x= 0 ; x < generation.length ; x++) { 
    for(int y= 0 ; y < generation[x].length ; y++) { 
     generation[x][y].neighbors= 0 ; 
     for(int dx= -1 ; dx <= 1 ; dx++) { 
      for(int dy= -1 ; dy <= 1 ; dy++) { 
       if(! (dx == 0 && dy == 0) && isValidNeighbor(x+dx,y+dx) && isAlive(x+dx,y+dx)) { 
        generation[x][y].neighbors++; 
       } 
      } 
     } 
    } 
} 

Многое, намного лучше. И, даже если не главная причина, меньше кода и сложности, чем с исключениями !!!

Смежные вопросы