• 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)

Object Storage Arubacloud
0 głosów
342 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 92 wizyt
0 głosów
1 odpowiedź 1,555 wizyt
pytanie zadane 4 lipca 2017 w C i C++ przez kyly Początkujący (260 p.)

92,551 zapytań

141,399 odpowiedzi

319,531 komentarzy

61,938 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...