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. :/