3 Commits
tp4 ... tp5

Author SHA1 Message Date
b23fd11f2f Fixed missing check 2025-05-20 14:26:32 +02:00
48c0bd0f96 Improving count fruit function 2025-05-19 16:15:53 +02:00
7b0f8f28e0 Rendu TP5 2025-05-19 16:06:59 +02:00
8 changed files with 222 additions and 266 deletions

View File

@@ -1,6 +1,6 @@
# Jeu Snake 2025
[![en](https://img.shields.io/badge/lang-en-red.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp2/README.md)
[![fr](https://img.shields.io/badge/lang-fr-green.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp2/README-fr.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp5/README.md)
[![fr](https://img.shields.io/badge/lang-fr-green.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp5/README-fr.md)
Ce projet est un jeu snake basé sur une grille utilisant la bibliothèque graphique MLV. La grille représente un plateau de jeu avec des murs, des espaces vides, des fruits et un serpent. Le programme affiche la grille dans une fenêtre graphique et attend une interaction de l'utilisateur.

View File

@@ -1,6 +1,6 @@
# Snake 2025 Game
[![en](https://img.shields.io/badge/lang-en-red.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp2/README.md)
[![fr](https://img.shields.io/badge/lang-fr-green.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp2/README-fr.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp5/README.md)
[![fr](https://img.shields.io/badge/lang-fr-green.svg)](https://git.esiee.fr/frequela/snake2025/-/blob/tp5/README-fr.md)
This project is a simple grid-based snake game using the MLV graphics library. The grid represents a game board with walls, empty spaces, fruits, and a snake. The program displays the grid in a graphical window and waits for user interaction.

301
game.c
View File

@@ -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 <MLV/MLV_all.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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,64 @@ int main(int argc, char *argv[])
}
}
if (input_file)
if (input_file == NULL)
{
nb_fruit = read_grid_from_file(input_file, grid);
input_file = "levels/default";
}
else
stream = fopen(input_file, "r");
if (!stream)
{
int i, j;
for (i = 0; i < NBL; i++)
{
for (j = 0; j < NBC; j++)
{
grid[i][j] = EMPTY;
}
}
nb_fruit = count_fruits(grid);
fprintf(stderr, "Error: unable to open file\n");
exit(EXIT_FAILURE);
}
place_snake(grid, &snake);
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]);
}
rewind(stream);
nb_fruit = count_fruits(stream, g);
if (nb_fruit == 0)
{
fprintf(stderr, "Error: no fruits in the grid\n");
free(buf);
fclose(stream);
exit(EXIT_FAILURE);
}
if (nb_fruit == -1)
{
fprintf(stderr, "Error: unable to count fruits\n");
free(buf);
fclose(stream);
exit(EXIT_FAILURE);
}
free(buf);
fclose(stream);
place_snake(g, &snake);
MLV_create_window("SNAKE", "3R-IN1B", width, height);
MLV_change_frame_rate(24);
@@ -300,14 +142,18 @@ 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)
{
MLV_draw_text(
width / 2 - 75, height / 2,
"Game Over! You hit something.",
MLV_COLOR_RED);
if (result == WALL)
{
MLV_draw_text(width / 2 - 75, height / 2, "Game Over! You hit a wall.", MLV_COLOR_RED);
}
else if (result == SNAKE)
{
MLV_draw_text(width / 2 - 75, height / 2, "Game Over! You hit yourself.", MLV_COLOR_RED);
}
MLV_actualise_window();
MLV_wait_seconds(3);
break;
@@ -328,7 +174,7 @@ int main(int argc, char *argv[])
}
}
draw_grid(grid);
draw_grid(g);
MLV_actualise_window();
switch (touche)
@@ -358,5 +204,6 @@ int main(int argc, char *argv[])
}
MLV_free_window();
free_grid(g);
return 0;
}

128
grid.c
View File

@@ -1,41 +1,84 @@
#include <stdio.h>
#include <stdlib.h>
#include <MLV/MLV_all.h>
#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,78 @@ 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(FILE *stream, Grid *g)
{
int i, j, nb_fruit = 0;
for (i = 0; i < g->nbl; i++)
{
if (!fgets(g->grid[i], g->nbc + 2, stream))
{
fprintf(stderr, "Error: Stream does not contain enough lines\n");
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++;
}
}
}
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';
}

29
grid.h
View File

@@ -1,10 +1,18 @@
#ifndef GRID_H
#define GRID_H
#include "snake.h"
#include <stdio.h>
#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(FILE *stream, Grid *g);
void copy(const char *src, char *dst);
#endif /* GRID_H */

View File

@@ -19,4 +19,4 @@ w w
f f
f
w w
w w

10
snake.c
View File

@@ -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;
}

10
snake.h
View File

@@ -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 */