Как сжать много if-операторов во что-то меньшее и более читаемое? - PullRequest
0 голосов
/ 10 июня 2019

Я работаю над кодом для игры в жизнь. И одна из функций должна «развить» текущий набор ячеек. Это означает, что у меня должны быть некоторые условия, и если выражение if удовлетворяет условию, то ячейка становится ячейкой DEAD или ALIVE.

Однако есть только несколько следующих ячеек, которые инициализируются, поэтому мне пришлось бы установить для остальных ячеек значение DEAD, на которые условия не влияют.

Поскольку есть четыре условия, я хотел бы сжать свои операторы if до минимально возможного количества.

Условия:

  • Ячейка с 0 или 1 живыми соседями умирает в следующем поколении.
  • Ячейка с 2 или 3 живыми соседями живет в следующем поколении.
  • Ячейка с 4 или более живыми соседями умирает в следующем поколении.
  • Пустая ячейка, в которой ровно 3 живых соседа, становится живой ячейка следующего поколения.

Я попытался вписать как можно больше условий в один оператор if и оператор else в if, то есть, если ни одна из ячеек не удовлетворяет условиям, для него автоматически будет установлено значение DEAD. Так, что все клетки в field[i][j].next либо мертвы, либо живы.

Хотелось бы отметить, что массив field[i][j].current уже инициализирован с ячейками DEAD и ALIVE.

  void evolve(const int rows,const int cols,cell field[rows][cols], int 
    NeighbourCounter[i][j]){

       CellNeighbour(rows, cols,field,NeighbourCounter);

       for(int i = 0;i<rows;i++){
         for(int j =0;j<cols;j++){
           if(field[i][j].current == ALIVE  && NeighbourCounter[i][j] < 2){
              field[i][j].next == DEAD;
           }
           if(field[i][j].current == ALIVE && NeighbourCounter[i][j] == ||NeighbourCounter[i][j] == 2){
               field[i][j].next = ALIVE;
           } 
           if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4){
                field[i][j].next = DEAD;
           }
           if(field[i][j].current == DEAD && NeighbourCounter[i][j] == 3){
                field[i][j].next = ALIVE;
           }
         }
     else{
            field[i][j].next = DEAD;
     }
    }

NeighbourCounter - это массив, который вычисляет, сколько ALIVE-соседей имеет каждая ячейка.

Ожидаемый вывод должен состоять в том, что field[rows][cols] должен быть обновлен, а обновленная версия сохранена в `` field [lines] [cols] .next`.

Ответы [ 4 ]

3 голосов
/ 10 июня 2019

Как сжать много if-операторов во что-то меньшее и большее читаемый

Вы используете неверное форматирование кода. Например, неясно, с каким оператором if следует следующий оператор else.

 else{
        field[i][j].next = DEAD;
 }

Плохое форматирование кода обычно является источником многих ошибок (включая логические ошибки).:)

Все эти операторы if

      if(field[i][j].current == ALIVE  && NeighbourCounter[i][j]<2){
           field[i][j].next == DEAD;
        }
         if(field[i][j].current == ALIVE && NeighbourCounter[i][j] ==3 
||NeighbourCounter[i][j] ==2 ){
          field[i][j].next = ALIVE;
        }
         if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4 
){
           field[i][j].next = DEAD;
         }
//...

можно переписать как

if ( field[i][j].current == ALIVE )
{
    if ( NeighbourCounter[i][j] < 2 )
    {
        field[i][j].next == DEAD;
    }
    else if ( NeighbourCounter[i][j] < 4 )
    {
        field[i][j].next = ALIVE; 
    }
    else 
    {
        field[i][j].next = DEAD;     
    }
}
else if ( field[i][j].current == DEAD )
{
    if ( NeighbourCounter[i][j] == 3 )
    {
        field[i][j].next = ALIVE;
    }    
}
// ... 

Это делает код более читабельным.

В качестве альтернативного подхода вы можете использовать оператор switch, например, такой:

switch ( field[i][j].current )
{
    case ALIVE:
    {
        // ...
    }

    case DEAD:
    {
        // ...
    }

    default:
    {
        // ...
    }
}
1 голос
/ 10 июня 2019

Одним из мощных методов кодирования функций является справочные таблицы .Количество соседей ограничено диапазоном 0 ... 9, а количество состояний - 2, поэтому вы можете использовать справочную таблицу размером 20:

bool NewStateLUT[2][10] = {
    {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // new states for dead cells
    {0, 0, 1, 1, 0, 0, 0, 0, 0, 0}  // new states for alive cells
};

Код, который использует эту таблицу:

whatever.next = NewStateLUT[whatever.current][NeighbourCounter];

В этом коде предполагается, что DEAD равно 0, а ALIVE равно 1. Возможно, потребуется изменить синтаксис, если DEAD и ALIVE являются перечислителями.


Поскольку LUT содержит только 0 и 1, вместо массива легко использовать растровое изображение:

uint32_t NewStateBitmap = 0b0000000100'0000001100;
whatever.next = (NewStateBitmap >> (whatever.current * 10 + NeighbourCounter)) & 1;
1 голос
/ 10 июня 2019

Вероятно, проще и понятнее просто switch по значению числа соседей, например:

for (int i = 0;  i < rows;  ++i) {
    for (int j = 0;  j < cols;  ++j) {
        switch (NeighbourCounter[i][j]) {
        case 0:
        case 1:
            /* cell dies without enough support */
            field[i][j].next = DEAD; /* I assume you meant =, not == */
            break;
        case 2:
            /* two neighbours can support a live cell */
            field[i][j].next = field[i][j].current;
            break;
        case 3:
            /* three neighbours can resurrect a dead one */
            field[i][j].next = ALIVE;
            break;
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
            /* more than three is a crowd */
            field[i][j].next = DEAD;
            break;
        default:
            fprintf(stderr, "Invalid value %d from NeighbourCounter\n",
                    NeighbourCounter[i][j]);
        }
    }
}

Вы увидите, что case 2 является единственным, в котором необходимо значение current; все остальные зависят только от количества соседей.

0 голосов
/ 10 июня 2019

Ячейка жива в следующем поколении, если она имеет 3 соседей или если она жива и имеет двух соседей.

Это, возможно, немного еретично, но мне интересно, являются ли константы живыми иМЕРТВЫ не мешают.Другим способом было бы переименовать поле current, скажем, now_alive и рядом с next_alive, а затем сохранить в них 0 или 1.

Тогда вычисление следующего живого можно записать

C->next_alive = (N == 3) || (C->now_alive+N) == 3;

где C указывает на ячейку, а N - на число ее соседей.

...