An error occurred while loading the file. Please try again.
-
ERKEN EFE authored
Made creer_level() error message more clear in file grid.c
509e4603
/**
* @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 game 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 @c 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}; // 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; // 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; // 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; // 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;
}
current_column += 1;
buffer += 1;
}
current_row += 1;
}
// fermeture du fichier
fclose(file);
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 @c 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]);
}
printf("\n");
}
}
/**
* @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 @c 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");
// 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 = (char) getch();
}
// on referme <ncurses.h> pour désallouer la mémoire qu'elle utilisait
endwin();
}