diff --git a/grid.c b/grid.c index f3142da27a15ecac11cc11c3b8235b7976d602c6..42c10314f7b1c31c9470196b9d78b8f7e05573fd 100644 --- a/grid.c +++ b/grid.c @@ -1,76 +1,145 @@ -#include <stdlib.h> +/** + * @file grid.c + * @author Efe ERKEN (efe.erken@etu.unistra.fr) + * @brief Fichier source contenant les fonctions pour traiter les niveaux du jeu sokoban + * @version 0.1 + * @date 2022-11-10 + * + * @copyright Copyright (c) 2022 + * + */ + #include <stdio.h> +#include <stdlib.h> #include <ncurses.h> #include "grid.h" #include "player.h" +/** + * @brief Fonction qui alloue la grille du jeu + * + * @param [in] row Le nombre de lignes du niveau de jeu + * @param [in] column Le nombre de colonnes du niveau de jeu + * @return grid* + * + * @pre - + * @post - + * + * Cette fonction prend en paramètre deux arguments tels que le nombre de lignes + * et le nombre de colonnes du niveau de jeu. Elle alloue dynamiquement la structure @c grid + * en fonction de cette taille et renvoie un pointeur sur cette structure. + */ grid *creer_level(int row, int column) { + // on alloue la structure elle-même dynamiquement grid *G = (grid *)malloc(sizeof(grid)); + // on vérifie si l'allocation s'est bien passée if (G == NULL) { fprintf(stderr, "Error G structure alloc failed"); exit(-1); } + // on alloue la première dimension du tableau dynamique à deux dimensions dans la structure G->game_grid = (enum CaseType **)(malloc(row * (sizeof(enum CaseType *)))); + // on vérifie si l'allocation s'est bien passée if (G->game_grid == NULL) { fprintf(stderr, "Error game_grid row alloc failed"); exit(-1); } + // on alloue la deuxième dimension du tableau dynamique for (int i = 0; i < row; i++) { G->game_grid[i] = (enum CaseType *)(malloc(column * (sizeof(enum CaseType)))); + // on vérifie si l'allocation s'est bien passée if (G->game_grid[i] == NULL) { fprintf(stderr, "Error game_grid column alloc failed"); exit(-1); } } + // on initialise les valeurs de taille du niveau G->row_number = row; G->column_number = column; return G; } +/** + * @brief Fonction pour désallouer la structure du jeu + * + * @param [in] G Pointeur sur une structure @c grid + * + * @pre @a G doit être non NULL et pointer sur la structure allouée + * @post @a G contient toujours l'adresse qu'il avait + * + * Cette fonction prend en paramètre un pointeur sur une structure @c grid + * et désalloue cette structure. Pour cela dans un premier temps, elle + * désalloue le tableau dynamique à deux dimensions @a game_grid et finalement + * elle désalloue la structure elle-même. + */ void free_level(grid *G) { + // on désalloue la deuxième dimension du tableau dynamique dans la structure for (int i = 0; i < G->row_number; i++) { free(G->game_grid[i]); } + // on désalloue la première dimension du tableau dynamique free(G->game_grid); + // on désalloue la structure free(G); } +/** + * @brief Fonction qui charge le niveau de jeu depuis un fichier dans la structure @c grid + * + * @param [in] file_path La localisation du fichier à lire + * @return grid* + * + * @pre - + * @post - + * + * Cette fonction lit ligne par ligne le fichier donné en paramètre pour charger + * les informations sur le niveau dans la structure @c grid qu'elle alloue elle-même. + * À part les informations sur par exemple la taille du niveau, elle charge chaque + * case du niveau dans le tableau dynamique à deux dimension de la structure. + * Elle recopie le niveau dans une structure et renvoi un pointeur dessus. + */ grid *init_level(const char *file_path) { // ouverture du fichier en mode lecture FILE *file = fopen(file_path, "r"); + // vérification si le fichier est bien ouvert if (!file) { fprintf(stderr, "Error %s not found", file_path); exit(-1); } - char line[100] = {0}; + char line[100] = {0}; // buffer pour lire une ligne dans le fichier int number_column = 0; // nombre de colonne - int number_row = 0; /// nombre de ligne - int number_goals = 0; + int number_row = 0; // nombre de ligne + int number_goals = 0; // nombre d'objectifs // on lit la première ligne du fichier fgets(line, 100, file); + // on récupère les informations sur le niveau depuis la première ligne sscanf(line, "%d %d %d", &number_column, &number_row, &number_goals); + // on alloue la structure pour stocker le niveau grid *level = creer_level(number_row, number_column); - int current_row = 0; + int current_row = 0; // la ligne où on se trouve actuellement en lisant le niveau // int current_goal = 0; // On lit le fichier ligne par ligne jusqu'à la fin du fichier while (fgets(line, 100, file) != NULL) { char *buffer = line; - int current_column = 0; + int current_column = 0; // la colonne où on se trouve actuellement en lisant le niveau + // tant qu'on arrive pas à une ligne vide ou à la fin d'une ligne, on continue à lire la ligne while (*buffer && *buffer != '\n') { + // on charge chaque case dans la structure level->game_grid[current_row][current_column] = *buffer; + // on initialise la position du joueur dans la structure quand on la retrouve if (*buffer == '@') { level->player.x = current_column; level->player.y = current_row; @@ -86,7 +155,19 @@ grid *init_level(const char *file_path) return level; } +/** + * @brief Fonction qui affiche le niveau chargé dans le terminal + * + * @param [in] G Pointeur sur la structure qui stocke le niveau + * + * @pre @a G doit être non NULL et pointer sur la structure allouée + * @post Affichage des caractères + * + * Cette fonction parcourt le tableau dans la structure qui stocke les cases du niveau + * et les affiche chacun. Elle utilise la fonction @c printf() de @c <stdio.h> + */ void display(grid *G) { + // on parcourt chaque ligne et colonne du tableau pour afficher le niveau for (int row = 0; row < G->row_number; row++) { for (int column = 0; column < G->column_number; column++) { printf("%c", G->game_grid[row][column]); @@ -95,24 +176,41 @@ void display(grid *G) { } } -char display_ncurses(grid *G) { +/** + * @brief Fonction qui affiche le niveau chargé dans le terminal avec @c ncurses + * + * @param [in] G Pointeur sur la structure qui stocke le niveau + * + * @pre @a G doit être non NULL et pointer sur la structure allouée + * @post Affichage des caractères, appuyez sur 'q' pour quitter + * + * Cette fonction affiche le niveau du jeu comme la fonction @c display() mais au + * contraire elle utilise la bibliothèque @c <ncurses.h> pour ne pas polluer le terminal + * avec beaucoup d'affichages inutiles et aussi pour présenter une interface plus agréable + * et professionnel pour le jeu. + */ +void display_ncurses(grid *G) { + // on initialise <ncurses.h> initscr(); + // on efface le buffer d'avant clear(); noecho(); cbreak(); printw("Appuyez sur \"q\" pour quitter\n"); - printw("Appuyez sur \"h, j, k, l\" pour vous déplacer\n\n"); + // on parcourt chaque ligne et colonne du tableau pour charger dans le buffer for (int row = 0; row < G->row_number; row++) { for (int column = 0; column < G->column_number; column++) { printw("%c", G->game_grid[row][column]); } printw("\n"); } + // on affiche le buffer, donc le niveau entier refresh(); + // on attend jusqu'à ce que l'utilisateur appuie sur la touche 'q' pour quitter char quitCar = '\0'; - while (quitCar != 'q' && quitCar != 'h' && quitCar != 'j' && quitCar != 'k' && quitCar != 'l') { + while (quitCar != 'q') { quitCar = (char) getch(); } + // on referme <ncurses.h> pour désallouer la mémoire qu'elle utilisait endwin(); - return quitCar; } diff --git a/grid.h b/grid.h index 4a1f03c6afd77db926eeebe614bd6e9e1fcd4d02..e912cdd127fbc61d5df1bde8601ca0c555676781 100644 --- a/grid.h +++ b/grid.h @@ -35,6 +35,6 @@ void free_level(grid *G); void display(grid *G); -char display_ncurses(grid *G); +void display_ncurses(grid *G); #endif