Итерационный вариант упражнения Ханойская башня


Я только что закончил итерационный вариант Ханойская башня.

Это как алгоритм работы:

enter image description here

Я пытаюсь найти способ, чтобы удалить goto инструкция. Какие-либо советы?

/**
 * definition of all function: 
 * 
 *  print : just print the state of the array
 *  populate: just fill the array with 0
 *  mov_pl: move the pile from to 
 *  CHK_POS_FROM : check from where come the disk
 *  CHK_POS_TO: check where the disk will go
 *  CHK_STK: check the status of the pile
 **/


    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>

    // Number if pile
    #define DM_STCK 3

    // Number of disk 
    #define DM_CLMN 10


    void print(int STCK[][DM_STCK], int DM_S);  
    void MOV_PL(int STCK[][DM_STCK], int FROM, int TO, size_t DM_S); 
    int CHK_POS_FROM(int STCK[][DM_STCK], int N_PL, size_t DM_S);
    int CHK_POS_TO(int STCK[][DM_STCK], int N_PL, size_t DM_S);
    int CHK_STK(int STCK[][DM_STCK], int N_PL, size_t DM_S);
    void populate(int STCK[][DM_STCK], int DM_S);

    int main(int argc, char *argv[]){

    // name of each pule

        int PL_1 = 0;
        int PL_2 = 1;
        int PL_3 = 2;

    // check if the disk are odd or even

        if(DM_CLMN % 2 == 0){
            PL_2 = 2;
            PL_3 = 1;
        }


        int stack[DM_CLMN][DM_STCK];

        populate(stack, DM_CLMN);

        long long mosse = (long long)pow(2,DM_CLMN) - 1;

        int RS_1 = 0;
        int RS_2 = 0;

        puts("### START ###");

        print(stack, DM_STCK);

        for(int cnt = 0; cnt < mosse; cnt++){

            RS_1 = 0;
            RS_2 = 0;

            printf("MOSSA NUMERO: %d\n", 1 + cnt);

            if(cnt % 3 == 0){

                    RS_1 = CHK_STK(stack, PL_1, DM_CLMN);
                    RS_2 = CHK_STK(stack, PL_3, DM_CLMN);

                    if(RS_1 > RS_2){
                        if(RS_2 == 0){
                        MOV_PL(stack, PL_1, PL_3, DM_CLMN);
                        print(stack, DM_STCK);

                        //printf("A --> B");
                        } else {
                            ODINO_0:
                            MOV_PL(stack, PL_3, PL_1, DM_CLMN);
                            print(stack, DM_STCK);
                            continue;
                        //printf("B --> A");
                        }
                    } if(RS_1 < RS_2) {
                        if(RS_1 == 0){
    //                      Odino perdonami per questa istruzione
                            goto ODINO_0;
                        }
                        MOV_PL(stack, PL_1, PL_3, DM_CLMN);
                        print(stack, DM_STCK);

                    }

                }

            if(cnt % 3 == 1){

                    RS_1 = CHK_STK(stack, PL_1, DM_CLMN);
                    RS_2 = CHK_STK(stack, PL_2, DM_CLMN);

                    if(RS_1 > RS_2){
                        if(RS_2 == 0){
                        MOV_PL(stack, PL_1, PL_2, DM_CLMN);
                        print(stack, DM_STCK);

                        //printf("A --> B");
                        } else {
    //                  Che odino sia con me
                        ODINO_1:
                        MOV_PL(stack, PL_2, PL_1, DM_CLMN);
                        print(stack, DM_STCK);

                        continue;
                        //printf("B --> A");
                        }
                    } else {
                        if(RS_1 == 0){
    //                      Odino perdonami per questa istruzione
                            goto ODINO_1;
                        }
                        MOV_PL(stack, PL_1, PL_2, DM_CLMN);
                        print(stack, DM_STCK);

                    }
            }

            if(cnt % 3 == 2){

                RS_1 = CHK_STK(stack, PL_2, DM_CLMN);
                RS_2 = CHK_STK(stack, PL_3, DM_CLMN);

                    if(RS_1 > RS_2){
                        if(RS_2 == 0){
                        MOV_PL(stack, PL_2, PL_3, DM_CLMN);
                        print(stack, DM_STCK);

                        //printf("A --> B");
                        } else {
                        ODINO_2:
                        MOV_PL(stack, PL_3, PL_2, DM_CLMN);
                        print(stack, DM_STCK);

                        continue;
                        //printf("B --> A");
                        }
                    } else {
                        if(RS_1 == 0){
    //                      Odino perdonami per questa istruzione
                            goto ODINO_2;
                        }
                        MOV_PL(stack, PL_2, PL_3, DM_CLMN);
                        print(stack, DM_STCK);

                    }
            }

        }

        puts("### END ###");        


        return 0;
    }

    void populate(int STCK[][DM_STCK], int DM_S){

        for(int colonna = 0; colonna < DM_S; colonna++){
            for(int riga = 0; riga < DM_STCK; riga++){
                STCK[colonna][riga] = 0;
            }
        }

        for(int cnt_1 = 0; cnt_1 < DM_S; cnt_1++){
            STCK[cnt_1][0] = cnt_1 + 1;
        }

    }

    // Stampa le 3 torri

    void print(int STCK[][DM_STCK], int DM_S){
        for(int colonne = 0; colonne < DM_CLMN; colonne++){
            for(int righe = 0; righe < DM_STCK; righe++){

                if(STCK[colonne][righe] == 0){
                    printf("|   |");
                }else{
                    printf("| %d |", STCK[colonne][righe]);
                }
            }
            puts("\n");
        }

        puts("\n");
    }

    // Controlla in che direzione muovere il paletto se -> o <-
    // check wich direction to move the pile if left or right

    void MOV_PL(int STCK[][DM_STCK], int FROM, int TO, size_t DM_S){

        int POS_1 = CHK_POS_FROM(STCK, FROM, DM_S);
        int POS_2 = CHK_POS_TO(STCK, TO,DM_S);

        int TMP = STCK[POS_2][TO];
        STCK[POS_2][TO] = STCK[POS_1][FROM];
        STCK[POS_1][FROM] = TMP;

    }

    // Estrae la posizione del numero da posizione
    // Look at the disk position in the array

    int CHK_POS_FROM(int STCK[][DM_STCK], int N_PL, size_t DM_S){

        int POS = DM_S - 1;

        for(int cnt_1 = 0; cnt_1 < DM_S; cnt_1++){
            if(STCK[cnt_1][N_PL] != 0){
               POS = cnt_1;
               break;
          }
        }


        return POS;

    }

    /* 
         Estrae la posizione di dove posizione il numero da posizione e 
        controlla che non sia uno zero, se non è uno zero allora è pos - 1 altrimenti 
        solo pos

        Extract the position, so we can tell in wich position is and check if 
        it's  0, if it's not a 0 pos = pos - 1 otherwise is just pos
    */


    int CHK_POS_TO(int STCK[][DM_STCK], int N_PL, size_t DM_S){

        int POS = DM_S - 1;

        for(int cnt_1 = 0; cnt_1 < DM_S; cnt_1++){
            if(STCK[cnt_1][N_PL] != 0){
               POS = cnt_1 - 1;
               break;
          }
        }


        return POS;

    }

    /*

        Estra il primo anello dallo stack e lo confronta con l'anello del l'altro stack
        per decidere in quale verso spostare l'anello.

        Extract the first disk from the stack and compares with the other disk
        from the pile, to decide in wich way to move the disk left or right

    */ 

    int CHK_STK(int STCK[][DM_STCK], int N_PL, size_t DM_S){

        int FLG = 0;

        for(int cnt = 0; cnt < DM_S; cnt++){
            if(STCK[cnt][N_PL] != 0){
               FLG = STCK[cnt][N_PL];
            break;
          }
        }

     return FLG;

    }


193
2
задан 3 марта 2018 в 07:03 Источник Поделиться
Комментарии
2 ответа

для облегчения читаемости и понимания:


  1. последовательно отступ кода. отступ после каждой открывающей скобки '{'. отступы перед каждой закрывающей фигурной скобкой '}'. Предлагаю каждый уровень отступа будет 4 места.

  2. используйте осмысленные имена переменных и параметров. Имена следует указать content или usage (или лучше, оба)

  3. отдельные блоки кода ( for if else while do...while switch case default ) по одной пустой строке.

  4. отдельные функции по 2 или 3 пустые строки (будьте последовательны)

  5. лучше всего, чтобы не ввести случайно пустую строку

  6. это лучше, чтобы не вводить случайного отступов

  7. следите за аксиому: только один оператор на строке и (в большинстве) одной переменной в заявлении.

  8. Лечить закрывающей скобки '}' как отдельное заявление.

  9. в отношении: int main(int argc, char *argv[]) поскольку ни параметр используется, предлагают использовать: int main( void )

  10. в отношении: void print(int STCK[][DM_STCK], int DM_S) С инт DM_S не используется, либо исключить этот параметр или первая строка в теле функции должно быть: (void)DM_S;

  11. это плохая практика программирования, чтобы включить заголовочные файлы эти содержимое не используется. И. Е. предлагаю убрать Утверждение: #include <stdlib.h>

  12. настоятельно рекомендуем удалить ярлыка: ODINO_0 и заменив 'перейти' к ODINO_0 с трех строк кода после метки. Аналогичные соображения имеют место для ODINO_1 и ODINO_2

  13. так DM_S передается как size_tлюбые другие переменные, используемые С он также должен быть объявлен как size_tне int

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

  15. для облегчения читаемости и понимания: вставить (разумное) пространство: внутри скобок, в квадратных скобках, после запятых, после точек с запятой, около операторов

3
ответ дан 5 марта 2018 в 11:03 Источник Поделиться

Код:

if(RS_1 > RS_2) {
if(RS_2 == 0) {
// do A
} else {
ODINO_0:
// do B
}
} if(RS_1 < RS_2) {
if(RS_1 == 0) {
goto ODINO_0;
}
// do C
}

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

if(RS_2 == 0) {
// do A
} else if(RS_1 > RS_2 || RS_1 == 0) {
// do B
} else if(RS_1 < RS_2) {
// do C
}

в предположении, что эти две величины никогда не бывает отрицательным. Если они могут быть отрицательными, есть некоторые дополнительные тесты необходимы.

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

По поводу имен: пожалуйста, используйте длинные имена переменных и функций. 3-письмо заглавных букв имен выглядеть код Fortran 66. Трудно читать ваш код, потому что имена переменных не имеют смысла, и нет комментариев, объясняющих их применение. Хорошие имена переменных делает код легко читается (и нет необходимости в комментариях, если они достаточно хороши). Плюс, современные IDE сделать завершения имен, вы даже не придется вводить полные имена. :Д

2
ответ дан 4 марта 2018 в 12:03 Источник Поделиться