• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

"Nić Ariadny" (a właściwie to problem z operacjami rekurencyjnymi na dynamicznie zalokowanej tablicy dwuwymiarowej)

42 Warsaw Coding Academy
0 głosów
586 wizyt
pytanie zadane 5 maja 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)

Cześć :)

Wykonuję obecnie zadanie o takowej treści:

Napisz program, który wczyta labirynt, znajdzie w nim drogę do wyjścia i wyświetli wynik.

W tym celu program pobierze od użytkownika nazwę pliku (pamięć alokowana dynamicznie na 31 bajtów, w przypadku niepowodzenia program powinien wyświetlić komunikat Failed to allocate memory i zakończyć działanie z kodem błędu 8.). Następnie wczyta labirynt w nim zapisany, odnajdzie ścieżkę prowadzącą z punktu a do punktu b i wyświetli labirynt z zaznaczoną drogą.

W przypadku:

niemożliwości otworzenia pliku program powinien wyświetlić komunikat Couldn't open file i zakończyć działanie z kodem błędu 4,
kiedy dane w pliku są uszkodzone program powinien wyświetlić komunikat File corrupted i zakończyć działanie z kodem błędu 6,
kiedy nie uda się przydzielić pamięci na labirynt program powinien wyświetlić komunikat Failed to allocate memory i zakończyć działanie z kodem błędu 8,
kiedy nie uda się odnaleźć ścieżki program powinien wyświetlić komunikat Couldn't find path i zakończyć działanie z kodem błędu 0.
Program ma zwrócić kod błedu 0 jeżeli udało się odnaleźć ścieżkę lub tej ścieżki nie było. Brak ścieżki, z punktu widzenia programu do jej szukania, nie jest błędem.

Plik wejściowy jest uszkodzony kiedy nie jest możliwe jego jednoznaczne przeszukanie, np. nie posiada spójnej struktury wierszy i kolumn, posiada więcej niż jedno wejście/wyjście, nie posiada wejścia lub wyjścia.

Przygotuj następujące funkcje:

int load_maze(const char *filename, char ***labirynth);
int solve_maze(char **maze, int x, int y);
void free_maze(char **maze);
int load_maze(const char *filename, char ***labirynth);
Funkcja wczytuje labirynt z pliku i zapisuje do zmiennej labirynth. Funkcja może zaalokować tylko tyle pamięci, ile będzie potrzebne na przechowanie danych.

Funkcja zwraca:

1 - w przypadku przekazania błędnych danych,
2 - jeżeli nie uda się otworzyć pliku,
3 jeżeli dane w pliku są uszkodzone (poprawny plik będzie przechowywał labirynt w formacie tekstowym, każdy wiersze będzie tej samej długości),
4 w przypadku niepowodzenia alokacji pamięci,
0 w przypadku sukcesu.
Przykładowe pliki:

tylko ściany: only_maze.txt,
labirynt z wyjściem: exit.txt,
labirynt bez wyjścia: no_exit.txt.
W pliku nie ma informacji o liczbie wierszy ani kolumn. Funkcja load_maze musi sama te wartości wyznaczyć przed przystąpieniem do wczytywania danych. Ponadto znaki w pliku mają następujące znaczenie:

'#' - ściana
' ' - wolny korytarz
'a' - punkt startu, wolny korytarz
'b' - wyjście
int solve_maze(char **maze, int x, int y);
Funkcja szuka drogi w labiryncie od punktu o współrzędnych (x, y) do punktu oznaczonego literą b. W przypadku znalezienia drogi, ma ona zostać oznaczona symbolem *.

Wartość zwracana:

0 - w przypadku niepowodzenia,
1 - w przypadku sukcesu
-1 - w razie przekazania do funkcji nieprawidłowych danych.
Znak 'a' jest znakiem pomocniczym, wykorzystywanym od oznaczania startu w labiryncie przechowywanym w pliku dyskowym. Jeżeli funkcja solve_maze napotka na znak 'a' to powinna potraktować je jako pustą przestrzeń.

void free_maze(char **maze)
Funkcja zwalnia całą pamięć przydzieloną na labirynt.

Przykładowa interakcja z programem -- sukces:

Enter filename: country.txt⏎
###################⏎
#       #  *******#⏎
# ### ### #*#####*#⏎
#   #     #***#***#⏎
### #########*#*###⏎
#     #*******#*# #⏎
#######*#######*# #⏎
#b******#*******# #⏎
#########*####### #⏎
#   #*****#a****  #⏎
# # #*#########*###⏎
# # #*#*******#***#⏎
### #*#*#####*###*#⏎
#   #***#   #***#*#⏎
# ####### #####*#*#⏎
#              ***#⏎
###################⏎
⏎
Enter filename: rest.txt⏎
Couldn't find path
Pliki: rest.txt, country.txt.

Przykładowa interakcja z programem -- brak pamięci:

Limit sterty: 136 bajtów, plik nature.txt.

Enter filename: nature⏎
Failed to allocate memory⏎
Limit sterty: 326 bajtów, plik nature.txt.

Enter filename: nature⏎
#############⏎
#     #***  #⏎
# ### #*#*###⏎
#   # #b#***#⏎
### # #####*#⏎
#   #   #***#⏎
# #######*# #⏎
# #*******# #⏎
# #*### ### #⏎
# #**a#   # #⏎
# ####### # #⏎
#         # #⏎
#############⏎
⏎
Przykładowa interakcja z programem -- problem z plikiem:

Enter filename: her⏎
File corrupted
Enter filename: mind.txt⏎
Couldn't open file
Uwaga

Wszystkie operacje na tablicach powinny być wykonywane za pomocą wskaźników, a nie operatora []!

Na chwilę obecną wiem, że mam poprawnie wykonaną funkcję load_maze (przechodzą dla niej mi wszystkie testy funkcyjne). Jednak to co się dzieje w solve_maze... . Ale najpierw kod do funkcji. Oto on:

int solve_maze(char** maze, int x, int y)
{
    static long long  functionCallCount = 0;
    functionCallCount++;
    if( *(*(maze + y) + x) == 'b')
    {
       return 1;
    }
    if( *(*(maze + y) + x) != 'a')
    {
        *(*(maze + y) + x) = '.';
    }
    int ret1=0, ret2=0, ret3=0, ret4=0;
    if( *(*(maze + y + 1) + x) == ' ' || *(*(maze + y + 1) + x) == 'b' )
    {
        ret1 = solve_maze(maze,x,y+1);
        if (ret1 == 1 && *(*(maze + y) + x) != 'a' )
        {
            *(*(maze + y) + x) = '*';
        }
    }
    if( *(*(maze + y - 1) + x) == ' ' || *(*(maze + y - 1) + x) == 'b')
    {
        ret2 = solve_maze(maze,x,y-1);
        if (ret2 == 1 && *(*(maze + y) + x) != 'a')
        {
            *(*(maze + y) + x) = '*';
        }
    }
    if( *(*(maze + y) + x - 1) == ' ' || *(*(maze + y) + x - 1) == 'b' )
    {
        ret3 = solve_maze(maze,x-1,y);
        if (ret3 == 1 && *(*(maze + y) + x) != 'a')
        {
            *(*(maze + y) + x) = '*';
        }
    }
    if( *(*(maze + y) + x + 1) == ' ' || *(*(maze + y) + x + 1) == 'b' )
    {
        ret4 = solve_maze(maze,x+1,y);
        if (ret4 == 1 && *(*(maze + y) + x) != 'a')
        {
            *(*(maze + y) + x) = '*';
        }
    }
    functionCallCount--;
    if (functionCallCount == 0)
    {
        int row = 0;
        int col = 0;
        while(*(maze + row) != NULL)
        {
            while(*(*(maze + row) + col) != '\0')
            {
                if(*(*(maze + row) + col) == '.')
                {
                    *(*(maze + row) + col) = ' ';
                }
                col++;
            }
            row++;
            col=0;
        }
    }

    return (ret1 || ret2 || ret3 || ret4);
}

Dla jednego testu w przykładowym wierszu otrzymuje takie wyniki:

Wynik: PORAŻKA: Funkcja solve_maze() błędnie znalazła wyjście z labiryntu w linii 21, 
powinno być #       #    *******#         #     #, a jest #.......#....*******#.........#.....#⏎

Wynik: PORAŻKA: Funkcja solve_maze() błędnie znalazła wyjście z labiryntu w linii 19, 
powinno być #         #***#   #***#         #   #, a jest #.........#***#...#***#.........#...#⏎

No i teraz mam zonk. Wydawało mi się, że poprawnie za pomocą tych czterech if-ów udaje mi się odnajdywać prawidłową ściężkę (lub jej brak). Zakropkowanie służy do tego, aby "aktualizować" drogę, jaką się przechodzi po tablicy dwuwymiarowej od a do b. Potem dbam, aby dla pierwszego wywołania rekurencyjnego likwidować te kropki (zastosowałem taki myk, że dla pól wierszy przydzieliłem dodatkową komórkę pamięci, która jest równa NULL (czyli nie wskazuje na nic, a to pozwala mi zrobić łatwy warunek na chodzenie po tej tablic), a dla podlegających każdemu wierszowi kolumnie ostatnia wartość to znak terminatora. Tak więc czego mi tutaj jeszcze brakuje? Nie chce mówić tego słynnego zdania, ale "u mnie wszystko działa" i dla każdego z tych przykładowych plików pokazuje poprawną drogę i pozbywa się kropek.  :/

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
0 odpowiedzi 108 wizyt
0 głosów
1 odpowiedź 1,846 wizyt
pytanie zadane 4 lipca 2017 w C i C++ przez kyly Początkujący (260 p.)

93,377 zapytań

142,379 odpowiedzi

322,528 komentarzy

62,726 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...