diff --git a/game.c b/game.c index 04e3d78..a4d843d 100644 --- a/game.c +++ b/game.c @@ -1,159 +1,4 @@ -/** - * - * Ce programme montre comment il est possible de dessiner les figures - * géométriques suivantes : - * - * cercle - * disque ( cercle plein ) - * ellipse - * ellipse pleine - * rectangle - * rectangle plein - * ligne - * point - * Courbe de Bézier - * polygone - * polygone plein - * - * Pour cela le programme utilise les fonctions suivantes : - * - *------------------------------------------------------------------------------ - * MLV_draw_circle: Dessine un cercle à une position et un rayon spécifiés en - * paramètres. - * - * void MLV_draw_circle( - * int x, Coordonnée en X du centre du cercle - * int y, Coordonnée en Y du centre du cercle - * int radius, Rayon du cercle - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_filled_circle : Dessine un disque plein dont le centre et le rayon - * sont passés en parametres. - * - * void MLV_draw_filled_circle( - * int x, Coordonnée en X du centre du cercle - * int y, Coordonnée en Y du centre du cercle - * int radius, Rayon du cercle - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_ellipse : Dessine une ellipse dont la position, les rayons et la - * couleur sont passés en paramètres. - * - * MLV_draw_ellipse( - * int x, Coordonnée en X du centre de l'ellipse - * int y, Coordonnée en Y du centre de l'ellipse - * int radius_x, Rayon en X de l'ellipse - * int radius_y, Rayon en Y de l'ellipse - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_filled_ellipse : Dessine une ellipse pleine dont la position, les - * rayons et la couleur sont passés en paramètres. - * - * void MLV_draw_filled_ellipse( - * int x, Coordonnee en X du centre de l'ellipse - * int y, Coordonnee en Y du centre de l'ellipse - * int radius_x, Rayon en X de l'ellipse - * int radius_y, Rayon en Y de l'ellipse - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_rectangle : Dessine un rectangle dont la taille, la couleur et la - * position du sommet Nord-Ouest sont données en - * paramètres. - * - * void MLV_draw_rectangle( - * int x, Coordonnée en X du sommet Nord-Ouest du rectangle - * int y, Coordonnée en Y du sommet Nord-Ouest du rectangle - * int width, Largeur du rectangle - * int height, Hauteur du rectangle - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_filled_rectangle : Dessine un rectangle dont la taille, la couleur - * et la position du sommet Nord-Ouest sont données - * en paramètres. - * void MLV_draw_filled_rectangle( - * int x, Coordonnée en X du sommet Nord-Ouest du rectangle - * int y, Coordonnée en Y du sommet Nord-Ouest du rectangle - * int width, Largeur du rectangle - * int height, Hauteur du rectangle - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_line : Dessine une ligne dont les coordonnées des deux extrémités - * sont passées en paramètres. - * void MLV_draw_line( - * int x1, Coordonnée en X de la première extrémité de la ligne - * int y1, Coordonnée en Y de la première extrémité de la ligne - * int x2, Coordonnée en X de la deuxième extrémité de la ligne - * int y2, Coordonnée en Y de la deuxième extrémité de la ligne - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_point : Dessine un point dont les coordonées sont passées - * en paramètres. - * - * void MLV_draw_point( - * int x, Coordonnée en X du point - * int y, Coordonnée en Y du point - * MLV_Color color Couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_bezier_curve: Dessine une courbe de Bézier à partir d'une liste de - * sommets. - * - * void MLV_draw_bezier_curve( - * const int* vx, La liste des coordonnées en X des différents - * sommets de la courbe. - * const int* vy, La liste des coordonnées en Y des différents - * sommets de la courbe. - * int npoints, Le nombre de sommets de la courbe de Bézier. - * MLV_Color color La couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_polygon: Dessine un polygone à partir d'une liste de sommets. - * - * void MLV_draw_polygon( - * const int* vx, La liste des coordonnées en X des différents - * sommets du polygone. - * const int* vy, La liste des coordonnées en Y des différents - * sommets du polygone. - * int npoints, Le nombre de sommets du polygone. - * MLV_Color color La couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * MLV_draw_polygon: Dessine un polygone plein à partir d'une liste de sommets. - * - * void MLV_draw_filled_polygon( - * const int* vx, La liste des coordonnées en X des différents - * sommets du polygone. - * const int* vy, La liste des coordonnées en Y des différents - * sommets du polygone. - * int npoints, Le nombre de sommets du polygone. - * MLV_Color color La couleur du tracé - * ); - * - * ----------------------------------------------------------------------------- - * - * Il existe d'autres fonctions de dessin. Vous les trouverez en consultant - * le fichier MLV_shape.h ou en tapant dans le terminal la commande : - * - * man MLV_shape.h - */ - +#define _POSIX_C_SOURCE 200809L #include #include #include @@ -175,62 +20,19 @@ void print_help() printf("Press ESC to exit the game.\n"); } -int read_grid_from_file(const char *filename, char grid[NBL][NBC + 1]) -{ - int i, j, nb_fruit = 0; - FILE *file = fopen(filename, "r"); - if (!file) - { - fprintf(stderr, "Error: Could not open file %s\n", filename); - exit(EXIT_FAILURE); - } - - for (i = 0; i < NBL; i++) - { - if (!fgets(grid[i], NBC + 2, file)) - { - fprintf(stderr, "Error: File %s does not contain enough lines\n", filename); - fclose(file); - exit(EXIT_FAILURE); - } - grid[i][strcspn(grid[i], "\n")] = '\0'; - - for (j = 0; j < NBC; j++) - { - if (grid[i][j] == FRUIT) - { - nb_fruit++; - } - } - } - - fclose(file); - return nb_fruit; -} - -int count_fruits(char grid[NBL][NBC + 1]) -{ - int i, j, nb_fruit = 0; - for (i = 0; i < NBL; i++) - { - for (j = 0; j < NBC; j++) - { - if (grid[i][j] == FRUIT) - { - nb_fruit++; - } - } - } - return nb_fruit; -} - int main(int argc, char *argv[]) { - int opt, option_index = 0, loop_count = 0, nb_fruit = 0; + FILE *stream; + char *buf = NULL; + size_t size_buf = 0; + int nbl, nbc, i; + int opt, option_index = 0; + int loop_count = 0, nb_fruit = 0; char *input_file = NULL; - MLV_Keyboard_button touche = MLV_KEYBOARD_NONE; int width = 640, height = 480; - char grid[NBL][NBC + 1] = {0}; + MLV_Keyboard_button touche = MLV_KEYBOARD_NONE; + + Grid *g; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, @@ -264,24 +66,56 @@ int main(int argc, char *argv[]) } } + if (input_file == NULL) + { + input_file = "levels/default"; + } + stream = fopen(input_file, "r"); + if (!stream) + { + fprintf(stderr, "Error: unable to open file\n"); + exit(EXIT_FAILURE); + } + + nbl = count_nb_lines(stream); + rewind(stream); + nbc = getline(&buf, &size_buf, stream); + if (nbc == -1) + { + fprintf(stderr, "Error: malformed file\n"); + exit(EXIT_FAILURE); + } + nbc--; + + g = allocate_grid(nbl, nbc); + + copy(buf, g->grid[0]); + for (i = 1; i < nbl; i++) + { + int size_tmp = getline(&buf, &size_buf, stream); + if (size_tmp != nbc + 1) + { + fprintf(stderr, "Error: inconsistent line length\n"); + free(buf); + fclose(stream); + exit(EXIT_FAILURE); + } + copy(buf, g->grid[i]); + } + + free(buf); + fclose(stream); + if (input_file) { - nb_fruit = read_grid_from_file(input_file, grid); + nb_fruit = count_fruits(input_file, g); } else { - int i, j; - for (i = 0; i < NBL; i++) - { - for (j = 0; j < NBC; j++) - { - grid[i][j] = EMPTY; - } - } - nb_fruit = count_fruits(grid); + exit(EXIT_FAILURE); } - place_snake(grid, &snake); + place_snake(g, &snake); MLV_create_window("SNAKE", "3R-IN1B", width, height); MLV_change_frame_rate(24); @@ -300,7 +134,7 @@ int main(int argc, char *argv[]) loop_count = (loop_count + 1) % DIFFICULTY; if (loop_count == 0) { - result = move_snake(&snake, grid); + result = move_snake(&snake, g); if (result == WALL || result == SNAKE) { @@ -328,7 +162,7 @@ int main(int argc, char *argv[]) } } - draw_grid(grid); + draw_grid(g); MLV_actualise_window(); switch (touche) @@ -358,5 +192,6 @@ int main(int argc, char *argv[]) } MLV_free_window(); + free_grid(g); return 0; } \ No newline at end of file diff --git a/grid.c b/grid.c index 953e5a1..e1463f1 100644 --- a/grid.c +++ b/grid.c @@ -1,41 +1,84 @@ #include +#include #include #include "grid.h" #include "snake.h" -void debug(char grid[NBL][NBC + 1]) +Grid *allocate_grid(int n, int m) +{ + Grid *g = malloc(sizeof(Grid)); + int i; + if (!g) + { + fprintf(stderr, "Error: could not allocate Grid.\n"); + exit(EXIT_FAILURE); + } + g->nbl = n; + g->nbc = m; + g->grid = malloc(n * sizeof(char *)); + if (!g->grid) + { + fprintf(stderr, "Error: could not allocate g->grid.\n"); + exit(EXIT_FAILURE); + } + for (i = 0; i < n; i++) + { + g->grid[i] = calloc(m + 1, sizeof(char)); + if (!g->grid[i]) + { + fprintf(stderr, "Error: could not allocate row.\n"); + exit(EXIT_FAILURE); + } + } + return g; +} + +void free_grid(Grid *g) { int i; - for (i = 0; i < NBL; i++) + if (!g) + return; + for (i = 0; i < g->nbl; i++) { - printf("%s\n", grid[i]); + free(g->grid[i]); + } + free(g->grid); + free(g); +} + +void debug(Grid *g) +{ + int i; + for (i = 0; i < g->nbl; i++) + { + printf("%s\n", g->grid[i]); } } -int compute_size(int w, int h) +int compute_size(Grid *g, int w, int h) { - int size_width = w / NBC; - int size_height = h / NBL; + int size_width = w / g->nbc; + int size_height = h / g->nbl; return (size_width < size_height) ? size_width : size_height; } -void draw_grid(char grid[NBL][NBC + 1]) +void draw_grid(Grid *g) { int i, j; int window_width = MLV_get_window_width(); int window_height = MLV_get_window_height(); - int cell_size = compute_size(window_width, window_height); + int cell_size = compute_size(g, window_width, window_height); MLV_draw_filled_rectangle(0, 0, window_width, window_height, MLV_COLOR_BLACK); - for (i = 0; i < NBL; i++) + for (i = 0; i < g->nbl; i++) { - for (j = 0; j < NBC; j++) + for (j = 0; j < g->nbc; j++) { int x = j * cell_size; int y = i * cell_size; - switch (grid[i][j]) + switch (g->grid[i][j]) { case WALL: MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_BROWN); @@ -57,29 +100,86 @@ void draw_grid(char grid[NBL][NBC + 1]) } } -void place_snake(char grid[NBL][NBC + 1], Snake *snake) +void place_snake(Grid *g, struct SnakeStruct *snake) { int i; for (i = 0; i < SNAKE_SIZE; i++) { Coord part = snake->pos[i]; - grid[part.y][part.x] = 's'; + g->grid[part.y][part.x] = 's'; } } -Element move_snake(Snake *snake, char grid[NBL][NBC + 1]) { +Element move_snake(struct SnakeStruct *snake, Grid *g) +{ Coord tail = snake->pos[SNAKE_SIZE - 1]; Coord head; Element element_at_head; - grid[tail.y][tail.x] = EMPTY; + g->grid[tail.y][tail.x] = EMPTY; - crawl(snake); + crawl(snake, g); head = snake->pos[0]; - element_at_head = grid[head.y][head.x]; + element_at_head = g->grid[head.y][head.x]; - grid[head.y][head.x] = SNAKE; + g->grid[head.y][head.x] = SNAKE; return element_at_head; +} + +int count_nb_lines(FILE *stream) +{ + int count = 0; + char buffer[256]; + while (fgets(buffer, sizeof(buffer), stream)) + { + count++; + } + rewind(stream); + return count; +} + +int count_fruits(const char *filename, Grid *g) +{ + int i, j, nb_fruit = 0; + FILE *file = fopen(filename, "r"); + if (!file) + { + fprintf(stderr, "Error: Could not open file %s\n", filename); + exit(EXIT_FAILURE); + } + + for (i = 0; i < g->nbl; i++) + { + if (!fgets(g->grid[i], g->nbc + 2, file)) + { + fprintf(stderr, "Error: File %s does not contain enough lines\n", filename); + fclose(file); + exit(EXIT_FAILURE); + } + g->grid[i][strcspn(g->grid[i], "\n")] = '\0'; + + for (j = 0; j < g->nbc; j++) + { + if (g->grid[i][j] == FRUIT) + { + nb_fruit++; + } + } + } + + fclose(file); + return nb_fruit; +} + +void copy(const char *src, char *dst) +{ + int i = 0; + while (src[i] != '\0' && src[i] != '\n') + { + dst[i] = src[i]; + i++; + } + dst[i] = '\0'; } \ No newline at end of file diff --git a/grid.h b/grid.h index 8ac366c..8f4b07e 100644 --- a/grid.h +++ b/grid.h @@ -1,10 +1,18 @@ #ifndef GRID_H #define GRID_H -#include "snake.h" +#include -#define NBL 22 -#define NBC 36 +struct SnakeStruct; + +struct GridStruct +{ + char **grid; + int nbl; + int nbc; +}; + +typedef struct GridStruct Grid; typedef enum { @@ -14,10 +22,15 @@ typedef enum SNAKE = 's' } Element; -void debug(char grid[NBL][NBC + 1]); -int compute_size(int w, int h); -void draw_grid(char grid[NBL][NBC + 1]); -void place_snake(char grid[NBL][NBC + 1], Snake *snake); -Element move_snake(Snake* snake, char grid[NBL][NBC+1]); +Grid* allocate_grid(int n, int m); +void free_grid(Grid *g); +void debug(Grid *g); +int compute_size(Grid *g, int w, int h); +void draw_grid(Grid *g); +void place_snake(Grid *g, struct SnakeStruct *snake); +Element move_snake(struct SnakeStruct *snake, Grid *g); +int count_nb_lines(FILE *stream); +int count_fruits(const char *filename, Grid *g); +void copy(const char *src, char *dst); #endif /* GRID_H */ \ No newline at end of file diff --git a/grids/1 b/levels/default similarity index 95% rename from grids/1 rename to levels/default index 1fdbdf2..7991750 100644 --- a/grids/1 +++ b/levels/default @@ -19,4 +19,4 @@ w w f f f -w w \ No newline at end of file +w w diff --git a/snake.c b/snake.c index c05d180..30bc618 100644 --- a/snake.c +++ b/snake.c @@ -1,23 +1,23 @@ #include "grid.h" #include "snake.h" -void crawl(Snake *snake) +void crawl(Snake *snake, Grid *g) { int i; Coord new_head = snake->pos[0]; switch (snake->dir) { case LEFT: - new_head.x = (new_head.x - 1 + NBC) % NBC; + new_head.x = (new_head.x - 1 + g->nbc) % g->nbc; break; case RIGHT: - new_head.x = (new_head.x + 1) % NBC; + new_head.x = (new_head.x + 1) % g->nbc; break; case TOP: - new_head.y = (new_head.y - 1 + NBL) % NBL; + new_head.y = (new_head.y - 1 + g->nbl) % g->nbl; break; case BOTTOM: - new_head.y = (new_head.y + 1) % NBL; + new_head.y = (new_head.y + 1) % g->nbl; break; } diff --git a/snake.h b/snake.h index af6cf62..4a41d83 100644 --- a/snake.h +++ b/snake.h @@ -1,6 +1,8 @@ #ifndef SNAKE_H #define SNAKE_H +struct GridStruct; + #define SNAKE_SIZE 4 typedef struct @@ -17,12 +19,14 @@ typedef enum RIGHT } Direction; -typedef struct +struct SnakeStruct { Coord pos[SNAKE_SIZE]; Direction dir; -} Snake; +}; -void crawl(Snake *snake); +typedef struct SnakeStruct Snake; + +void crawl(Snake *snake, struct GridStruct *g); #endif /* SNAKE_H */ \ No newline at end of file