Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
2c045ae715
|
|||
|
fd49d9a147
|
|||
|
c4d0ba3f1c
|
|||
|
9a754e94be
|
|||
|
9c053fe61c
|
|||
|
c8a4a40618
|
|||
|
4798ec85a3
|
|||
|
d694422e66
|
|||
|
f36b376137
|
|||
|
48c0bd0f96
|
|||
|
7b0f8f28e0
|
36
README-fr.md
36
README-fr.md
@@ -1,6 +1,6 @@
|
||||
# Jeu Snake 2025
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp4/README.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp4/README-fr.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp6/README.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp6/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.
|
||||
|
||||
@@ -10,6 +10,9 @@ Ce projet est un jeu snake basé sur une grille utilisant la bibliothèque graph
|
||||
- Utilise la bibliothèque graphique MLV pour le rendu graphique.
|
||||
- Assure que les blocs en dehors de la grille sont affichés en noir.
|
||||
- Permet à l'utilisateur de quitter le programme en appuyant sur la touche ESC.
|
||||
- Implémente un serpent dynamique utilisant une liste chaînée pour ses segments.
|
||||
- Gère le mouvement du serpent en mettant à jour la position de la tête et en déplaçant tous les segments en conséquence.
|
||||
- Permet au serpent de grandir lorsqu'il mange des fruits.
|
||||
|
||||
## Représentation de la Grille
|
||||
|
||||
@@ -19,6 +22,16 @@ Ce projet est un jeu snake basé sur une grille utilisant la bibliothèque graph
|
||||
- `'f'` pour les fruits.
|
||||
- `'s'` pour le serpent.
|
||||
|
||||
## Représentation du Serpent
|
||||
|
||||
- Le serpent est implémenté comme une liste chaînée de segments (`Position`), où :
|
||||
- Chaque segment a des coordonnées `x` et `y`.
|
||||
- Le pointeur `next` relie le segment suivant dans le serpent.
|
||||
- Le mouvement du serpent est géré en :
|
||||
- Ajoutant une nouvelle tête en fonction de la direction actuelle.
|
||||
- Déplaçant tous les segments pour suivre la tête.
|
||||
- Supprimant la queue sauf si le serpent mange un fruit.
|
||||
|
||||
## Dépendances
|
||||
|
||||
- GCC (GNU Compiler Collection)
|
||||
@@ -52,7 +65,24 @@ Cela compilera les fichiers sources et créera un exécutable nommé `game` dans
|
||||
./game
|
||||
```
|
||||
|
||||
2. Une fenêtre s'ouvrira affichant la grille. Les blocs en dehors de la grille apparaîtront en noir. Appuyez sur la touche ESC pour fermer la fenêtre.
|
||||
2. Une fenêtre s'ouvrira affichant la grille. Les blocs en dehors de la grille apparaîtront en noir. Utilisez les flèches directionnelles pour contrôler le serpent. Appuyez sur la touche ESC pour fermer la fenêtre.
|
||||
|
||||
## Logique du Jeu
|
||||
|
||||
- **Mouvement du Serpent** :
|
||||
- Le serpent se déplace dans la direction actuelle, en mettant à jour la position de sa tête et en déplaçant tous les segments.
|
||||
- Si le serpent mange un fruit, il grandit en ajoutant un nouveau segment sans supprimer la queue.
|
||||
- Si le serpent entre en collision avec un mur ou lui-même, le jeu se termine.
|
||||
|
||||
- **Mise à Jour de la Grille** :
|
||||
- La grille est mise à jour pour refléter la nouvelle position du serpent après chaque mouvement.
|
||||
- Les fruits sont supprimés de la grille lorsqu'ils sont mangés par le serpent.
|
||||
|
||||
- **Condition de Victoire** :
|
||||
- Le joueur gagne lorsque tous les fruits sur la grille sont collectés.
|
||||
|
||||
- **Condition de Défaite** :
|
||||
- Le jeu se termine si le serpent entre en collision avec un mur ou lui-même.
|
||||
|
||||
## Nettoyage
|
||||
|
||||
|
||||
36
README.md
36
README.md
@@ -1,6 +1,6 @@
|
||||
# Snake 2025 Game
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp4/README.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp4/README-fr.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp6/README.md)
|
||||
[](https://git.esiee.fr/frequela/snake2025/-/blob/tp6/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.
|
||||
|
||||
@@ -10,6 +10,9 @@ This project is a simple grid-based snake game using the MLV graphics library. T
|
||||
- Uses the MLV graphics library for graphical rendering.
|
||||
- Ensures that blocks outside the grid are displayed as black.
|
||||
- Allows the user to quit the program by pressing the ESC key.
|
||||
- Implements a dynamic snake using a linked list for its segments.
|
||||
- Handles snake movement by updating the head position and shifting all segments accordingly.
|
||||
- Supports snake growth when eating fruits.
|
||||
|
||||
## Grid Representation
|
||||
|
||||
@@ -19,6 +22,16 @@ This project is a simple grid-based snake game using the MLV graphics library. T
|
||||
- `'f'` for fruits.
|
||||
- `'s'` for the snake.
|
||||
|
||||
## Snake Representation
|
||||
|
||||
- The snake is implemented as a linked list of segments (`Position` structures), where:
|
||||
- Each segment has `x` and `y` coordinates.
|
||||
- The `next` pointer links to the next segment in the snake.
|
||||
- The snake's movement is handled by:
|
||||
- Adding a new head based on the current direction.
|
||||
- Shifting all segments to follow the head.
|
||||
- Removing the tail unless the snake eats a fruit.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- GCC (GNU Compiler Collection)
|
||||
@@ -52,7 +65,24 @@ This will compile the source files and create an executable named `game` in the
|
||||
./game
|
||||
```
|
||||
|
||||
2. A window will open displaying the grid. Blocks outside the grid will appear black. Press the ESC key to close the window.
|
||||
2. A window will open displaying the grid. Blocks outside the grid will appear black. Use the arrow keys to control the snake. Press the ESC key to close the window.
|
||||
|
||||
## Game Logic
|
||||
|
||||
- **Snake Movement**:
|
||||
- The snake moves in the current direction, updating its head position and shifting all segments.
|
||||
- If the snake eats a fruit, it grows by adding a new segment without removing the tail.
|
||||
- If the snake collides with a wall or itself, the game ends.
|
||||
|
||||
- **Grid Updates**:
|
||||
- The grid is updated to reflect the snake's new position after each move.
|
||||
- Fruits are removed from the grid when eaten by the snake.
|
||||
|
||||
- **Winning Condition**:
|
||||
- The player wins when all fruits on the grid are collected.
|
||||
|
||||
- **Losing Condition**:
|
||||
- The game ends if the snake collides with a wall or itself.
|
||||
|
||||
## Cleaning Up
|
||||
|
||||
|
||||
BIN
assets/boost.png
Normal file
BIN
assets/boost.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
BIN
assets/fruit.png
Normal file
BIN
assets/fruit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 311 KiB |
BIN
assets/grass.png
Normal file
BIN
assets/grass.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 683 KiB |
BIN
assets/wall.png
Normal file
BIN
assets/wall.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
521
game.c
521
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 <MLV/MLV_all.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -162,7 +7,7 @@
|
||||
#include "grid.h"
|
||||
#include "snake.h"
|
||||
|
||||
#define DIFFICULTY 6
|
||||
#define BASE_SPEED 6
|
||||
|
||||
void print_help()
|
||||
{
|
||||
@@ -175,79 +20,35 @@ 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, total_fruits = 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;
|
||||
int initial_size = 0;
|
||||
int current_level = 1;
|
||||
int global_score = 0;
|
||||
int previous_score = 0;
|
||||
int speed = BASE_SPEED;
|
||||
int boosts = 0;
|
||||
int boost_spawn_timer = 0;
|
||||
int boost_spawn_interval = 0;
|
||||
int boost_duration = 0;
|
||||
const int boost_duration_frames = 5 * 24;
|
||||
|
||||
Grid *g;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"input", required_argument, 0, 'i'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
Snake snake;
|
||||
snake.pos[0].x = 1;
|
||||
snake.pos[0].y = 3;
|
||||
snake.pos[1].x = 1;
|
||||
snake.pos[1].y = 2;
|
||||
snake.pos[2].x = 1;
|
||||
snake.pos[2].y = 1;
|
||||
snake.pos[3].x = 1;
|
||||
snake.pos[3].y = 0;
|
||||
snake.dir = RIGHT;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hi:", long_options, &option_index)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
@@ -264,103 +65,233 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (input_file)
|
||||
while (1)
|
||||
{
|
||||
nb_fruit = read_grid_from_file(input_file, grid);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < NBL; i++)
|
||||
Snake *snake = new_snake();
|
||||
|
||||
previous_score = global_score;
|
||||
|
||||
if (input_file == NULL)
|
||||
{
|
||||
for (j = 0; j < NBC; j++)
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
char level_file[256];
|
||||
snprintf(level_file, sizeof(level_file), "levels/level%d", current_level);
|
||||
input_file = level_file;
|
||||
}
|
||||
nb_fruit = count_fruits(grid);
|
||||
}
|
||||
|
||||
place_snake(grid, &snake);
|
||||
|
||||
MLV_create_window("SNAKE", "3R-IN1B", width, height);
|
||||
MLV_change_frame_rate(24);
|
||||
|
||||
while (
|
||||
MLV_get_event(
|
||||
&touche, NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL) == MLV_NONE ||
|
||||
touche != MLV_KEYBOARD_ESCAPE)
|
||||
{
|
||||
Element result;
|
||||
MLV_clear_window(MLV_COLOR_BLACK);
|
||||
|
||||
loop_count = (loop_count + 1) % DIFFICULTY;
|
||||
if (loop_count == 0)
|
||||
stream = fopen(input_file, "r");
|
||||
if (!stream)
|
||||
{
|
||||
result = move_snake(&snake, grid);
|
||||
fprintf(stderr, "Error: unable to open file for level %d\n", current_level);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (result == WALL || result == SNAKE)
|
||||
nbl = count_nb_lines(stream);
|
||||
rewind(stream);
|
||||
nbc = getline(&buf, &size_buf, stream);
|
||||
if (nbc == -1)
|
||||
{
|
||||
fprintf(stderr, "Error: malformed file\n");
|
||||
free(buf);
|
||||
fclose(stream);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
fprintf(stderr, "Error: inconsistent line length\n");
|
||||
free(buf);
|
||||
free_grid(g);
|
||||
fclose(stream);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (result == FRUIT)
|
||||
copy(buf, g->grid[i]);
|
||||
}
|
||||
|
||||
rewind(stream);
|
||||
nb_fruit = count_fruits(stream, g);
|
||||
total_fruits = nb_fruit;
|
||||
if (nb_fruit == 0)
|
||||
{
|
||||
fprintf(stderr, "Error: no fruits in the grid\n");
|
||||
free(buf);
|
||||
free_grid(g);
|
||||
fclose(stream);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (nb_fruit == -1)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to count fruits\n");
|
||||
free(buf);
|
||||
free_grid(g);
|
||||
fclose(stream);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
fclose(stream);
|
||||
|
||||
read_snake_from_grid(g, snake);
|
||||
initial_size = snake->size;
|
||||
|
||||
MLV_create_window("SNAKE", "3R-IN1B", width, height);
|
||||
MLV_change_frame_rate(24);
|
||||
|
||||
while (
|
||||
MLV_get_event(
|
||||
&touche, NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL) == MLV_NONE ||
|
||||
touche != MLV_KEYBOARD_ESCAPE)
|
||||
{
|
||||
Element result;
|
||||
char stats[256];
|
||||
MLV_clear_window(MLV_COLOR_BLACK);
|
||||
|
||||
loop_count = (loop_count + 1) % speed;
|
||||
if (loop_count == 0)
|
||||
{
|
||||
nb_fruit--;
|
||||
if (nb_fruit == 0)
|
||||
if (boost_spawn_timer >= boost_spawn_interval)
|
||||
{
|
||||
MLV_draw_text(
|
||||
width / 2 - 75, height / 2,
|
||||
"You Win! All fruits collected.",
|
||||
MLV_COLOR_GREEN);
|
||||
int x, y;
|
||||
do
|
||||
{
|
||||
x = rand() % g->nbc;
|
||||
y = rand() % g->nbl;
|
||||
} while (g->grid[y][x] != EMPTY);
|
||||
|
||||
g->grid[y][x] = BOOST;
|
||||
boost_spawn_timer = 0;
|
||||
boost_spawn_interval = 50 + rand() % BASE_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost_spawn_timer++;
|
||||
}
|
||||
|
||||
result = move_snake(snake, g);
|
||||
|
||||
if (result == WALL || result == SNAKE)
|
||||
{
|
||||
if (result == WALL)
|
||||
{
|
||||
MLV_draw_text(width / 2 - 80, height / 2, "Game Over! You hit a wall.", MLV_COLOR_RED);
|
||||
}
|
||||
else if (result == SNAKE)
|
||||
{
|
||||
MLV_draw_text(width / 2 - 80, height / 2, "Game Over! You hit yourself.", MLV_COLOR_RED);
|
||||
}
|
||||
MLV_actualise_window();
|
||||
MLV_wait_seconds(3);
|
||||
|
||||
global_score = previous_score;
|
||||
boosts = 0;
|
||||
boost_duration = 0;
|
||||
speed = BASE_SPEED;
|
||||
break;
|
||||
}
|
||||
else if (result == BOOST)
|
||||
{
|
||||
boosts++;
|
||||
boost_duration = boost_duration_frames;
|
||||
speed = BASE_SPEED - boosts;
|
||||
speed = (BASE_SPEED - boosts) > 1 ? (BASE_SPEED - boosts) : 1;
|
||||
printf("Boost collected! Speed increased. Boost duration: %d frames\n", boost_duration);
|
||||
}
|
||||
else if (result == FRUIT)
|
||||
{
|
||||
Position *tail = snake->segments_list;
|
||||
Position *prev = NULL;
|
||||
int dx, dy;
|
||||
while (tail->next != NULL)
|
||||
{
|
||||
prev = tail;
|
||||
tail = tail->next;
|
||||
}
|
||||
dx = tail->x - (prev ? prev->x : tail->x);
|
||||
dy = tail->y - (prev ? prev->y : tail->y);
|
||||
add_segment(snake, tail->x + dx, tail->y + dy);
|
||||
place_snake(g, snake);
|
||||
nb_fruit--;
|
||||
global_score++;
|
||||
if (snake->size == initial_size + total_fruits)
|
||||
{
|
||||
MLV_draw_text(
|
||||
width / 2 - 200, height / 2,
|
||||
"You Win! All fruits collected. Proceeding to the next level.",
|
||||
MLV_COLOR_GREEN);
|
||||
MLV_actualise_window();
|
||||
MLV_wait_seconds(3);
|
||||
current_level++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (boost_duration > 0)
|
||||
{
|
||||
boost_duration--;
|
||||
if (boost_duration == 0)
|
||||
{
|
||||
boosts--;
|
||||
speed = (BASE_SPEED - boosts) > 1 ? (BASE_SPEED - boosts) : 1;
|
||||
printf("Boost expired. Speed reset. Active boosts: %d\n", boosts);
|
||||
}
|
||||
}
|
||||
|
||||
draw_grid(g);
|
||||
|
||||
snprintf(stats, sizeof(stats),
|
||||
"Level: %d | Fruits Left: %d/%d | Score: %d | Snake Size: %d | Boosts: %d",
|
||||
current_level, nb_fruit, total_fruits, global_score, snake->size, boosts);
|
||||
MLV_draw_text(10, height - 20, stats, MLV_COLOR_WHITE);
|
||||
|
||||
MLV_actualise_window();
|
||||
|
||||
switch (touche)
|
||||
{
|
||||
case MLV_KEYBOARD_DOWN:
|
||||
if (snake->dir != TOP)
|
||||
snake->dir = BOTTOM;
|
||||
break;
|
||||
case MLV_KEYBOARD_UP:
|
||||
if (snake->dir != BOTTOM)
|
||||
snake->dir = TOP;
|
||||
break;
|
||||
case MLV_KEYBOARD_LEFT:
|
||||
if (snake->dir != RIGHT)
|
||||
snake->dir = LEFT;
|
||||
break;
|
||||
case MLV_KEYBOARD_RIGHT:
|
||||
if (snake->dir != LEFT)
|
||||
snake->dir = RIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
touche = MLV_KEYBOARD_NONE;
|
||||
MLV_delay_according_to_frame_rate();
|
||||
}
|
||||
|
||||
draw_grid(grid);
|
||||
MLV_actualise_window();
|
||||
MLV_free_window();
|
||||
free_grid(g);
|
||||
free_snake(snake);
|
||||
input_file = NULL;
|
||||
|
||||
switch (touche)
|
||||
if (touche == MLV_KEYBOARD_ESCAPE)
|
||||
{
|
||||
case MLV_KEYBOARD_DOWN:
|
||||
if (snake.dir != TOP)
|
||||
snake.dir = BOTTOM;
|
||||
break;
|
||||
case MLV_KEYBOARD_UP:
|
||||
if (snake.dir != BOTTOM)
|
||||
snake.dir = TOP;
|
||||
break;
|
||||
case MLV_KEYBOARD_LEFT:
|
||||
if (snake.dir != RIGHT)
|
||||
snake.dir = LEFT;
|
||||
break;
|
||||
case MLV_KEYBOARD_RIGHT:
|
||||
if (snake.dir != LEFT)
|
||||
snake.dir = RIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
touche = MLV_KEYBOARD_NONE;
|
||||
MLV_delay_according_to_frame_rate();
|
||||
}
|
||||
|
||||
MLV_free_window();
|
||||
return 0;
|
||||
}
|
||||
356
grid.c
356
grid.c
@@ -1,53 +1,177 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.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 + 2, 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(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_Image *image_wall, *image_fruit, *image_snake, *image_snake_head, *image_boost, *image_empty;
|
||||
image_wall = MLV_load_image("./assets/wall.png");
|
||||
image_fruit = MLV_load_image("./assets/fruit.png");
|
||||
image_snake = MLV_load_image("./assets/snake.png");
|
||||
image_snake_head = MLV_load_image("./assets/snake_head.png");
|
||||
image_boost = MLV_load_image("./assets/boost.png");
|
||||
image_empty = MLV_load_image("./assets/grass.png");
|
||||
if (image_wall != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_wall, cell_size, cell_size);
|
||||
}
|
||||
if (image_fruit != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_fruit, cell_size, cell_size);
|
||||
}
|
||||
if (image_snake != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_snake, cell_size, cell_size);
|
||||
}
|
||||
if (image_snake_head != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_snake_head, cell_size, cell_size);
|
||||
}
|
||||
if (image_boost != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_boost, cell_size, cell_size);
|
||||
}
|
||||
if (image_empty != NULL)
|
||||
{
|
||||
MLV_resize_image_with_proportions(image_empty, cell_size, cell_size);
|
||||
}
|
||||
|
||||
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);
|
||||
if (image_wall == NULL)
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_BROWN);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_image(image_wall, x, y);
|
||||
}
|
||||
break;
|
||||
case EMPTY:
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_WHITE);
|
||||
if (image_empty != NULL)
|
||||
{
|
||||
MLV_draw_image(image_empty, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_WHITE);
|
||||
}
|
||||
|
||||
break;
|
||||
case FRUIT:
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_RED);
|
||||
if (image_fruit == NULL)
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_image(image_fruit, x, y);
|
||||
}
|
||||
break;
|
||||
case SNAKE:
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_GREEN);
|
||||
if (image_snake == NULL)
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_image(image_snake, x, y);
|
||||
}
|
||||
break;
|
||||
case SNAKEHEAD:
|
||||
if (image_snake == NULL)
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_image(image_snake_head, x, y);
|
||||
}
|
||||
break;
|
||||
case BOOST:
|
||||
if (image_boost == NULL)
|
||||
{
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_YELLOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLV_draw_image(image_boost, x, y);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MLV_draw_filled_rectangle(x, y, cell_size, cell_size, MLV_COLOR_BLACK);
|
||||
@@ -57,29 +181,205 @@ 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++)
|
||||
Position *current = snake->segments_list;
|
||||
|
||||
if (current != NULL)
|
||||
{
|
||||
Coord part = snake->pos[i];
|
||||
grid[part.y][part.x] = 's';
|
||||
g->grid[current->y][current->x] = SNAKEHEAD;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
g->grid[current->y][current->x] = SNAKE;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
Element move_snake(Snake *snake, char grid[NBL][NBC + 1]) {
|
||||
Coord tail = snake->pos[SNAKE_SIZE - 1];
|
||||
Coord head;
|
||||
Element move_snake(struct SnakeStruct *snake, Grid *g)
|
||||
{
|
||||
Position *tail = snake->segments_list;
|
||||
Position *head;
|
||||
Element element_at_head;
|
||||
|
||||
grid[tail.y][tail.x] = EMPTY;
|
||||
while (tail->next != NULL)
|
||||
{
|
||||
tail = tail->next;
|
||||
}
|
||||
|
||||
crawl(snake);
|
||||
g->grid[tail->y][tail->x] = EMPTY;
|
||||
|
||||
head = snake->pos[0];
|
||||
element_at_head = grid[head.y][head.x];
|
||||
crawl(snake, g);
|
||||
|
||||
grid[head.y][head.x] = SNAKE;
|
||||
head = snake->segments_list;
|
||||
element_at_head = g->grid[head->y][head->x];
|
||||
|
||||
g->grid[head->y][head->x] = SNAKEHEAD;
|
||||
|
||||
if (head->next != NULL)
|
||||
{
|
||||
g->grid[head->next->y][head->next->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';
|
||||
}
|
||||
|
||||
static bool are_adjacent(Position *a, Position *b)
|
||||
{
|
||||
return (a->x == b->x && abs(a->y - b->y) == 1) ||
|
||||
(a->y == b->y && abs(a->x - b->x) == 1);
|
||||
}
|
||||
|
||||
int is_snake_connected(struct SnakeStruct *snake)
|
||||
{
|
||||
Position *current = snake->segments_list;
|
||||
while (current && current->next)
|
||||
{
|
||||
if (!are_adjacent(current, current->next))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void read_snake_from_grid(Grid *g, struct SnakeStruct *snake)
|
||||
{
|
||||
Position *positions = malloc(g->nbl * g->nbc * sizeof(Position));
|
||||
int positions_count = 0;
|
||||
Position *head = NULL;
|
||||
Position *current;
|
||||
int i;
|
||||
int *used = NULL;
|
||||
|
||||
for (i = 0; i < g->nbl; i++)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < g->nbc; j++)
|
||||
{
|
||||
if (g->grid[i][j] == SNAKE || g->grid[i][j] == SNAKEHEAD)
|
||||
{
|
||||
positions[positions_count].x = j;
|
||||
positions[positions_count].y = i;
|
||||
positions[positions_count].next = NULL;
|
||||
|
||||
if (g->grid[i][j] == SNAKEHEAD)
|
||||
{
|
||||
head = &positions[positions_count];
|
||||
}
|
||||
|
||||
positions_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (head == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: Snake head (S) not found in the grid.\n");
|
||||
free(positions);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
used = malloc(positions_count * sizeof(int));
|
||||
if (!used) {
|
||||
fprintf(stderr, "Error: Could not allocate memory for used array.\n");
|
||||
free(positions);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (i = 0; i < positions_count; i++)
|
||||
{
|
||||
used[i] = 0;
|
||||
}
|
||||
|
||||
add_segment(snake, head->x, head->y);
|
||||
used[head - positions] = 1;
|
||||
|
||||
current = head;
|
||||
while (1)
|
||||
{
|
||||
int found = 0;
|
||||
int j;
|
||||
for (j = 0; j < positions_count; j++)
|
||||
{
|
||||
if (!used[j] && are_adjacent(current, &positions[j]))
|
||||
{
|
||||
add_segment(snake, positions[j].x, positions[j].y);
|
||||
used[j] = 1;
|
||||
current = &positions[j];
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < positions_count; i++)
|
||||
{
|
||||
if (!used[i])
|
||||
{
|
||||
fprintf(stderr, "Error: Snake is not fully connected in the grid.\n");
|
||||
free(positions);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
snake->dir = determine_initial_direction(g, snake->segments_list);
|
||||
|
||||
free(positions);
|
||||
free(used);
|
||||
}
|
||||
35
grid.h
35
grid.h
@@ -1,23 +1,40 @@
|
||||
#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
|
||||
{
|
||||
WALL = 'w',
|
||||
EMPTY = ' ',
|
||||
FRUIT = 'f',
|
||||
SNAKE = 's'
|
||||
SNAKE = 's',
|
||||
SNAKEHEAD = 'S',
|
||||
BOOST = 'b'
|
||||
} 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(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);
|
||||
int is_snake_connected(struct SnakeStruct *snake);
|
||||
void read_snake_from_grid(Grid *g, struct SnakeStruct *snake);
|
||||
|
||||
#endif /* GRID_H */
|
||||
@@ -1,7 +1,7 @@
|
||||
w w
|
||||
|
||||
f
|
||||
|
||||
ssssS
|
||||
f f
|
||||
|
||||
|
||||
@@ -19,4 +19,4 @@ w w
|
||||
f f
|
||||
|
||||
f
|
||||
w w
|
||||
w w
|
||||
25
levels/level2
Normal file
25
levels/level2
Normal file
@@ -0,0 +1,25 @@
|
||||
w w
|
||||
|
||||
f
|
||||
|
||||
f f
|
||||
|
||||
|
||||
f
|
||||
|
||||
|
||||
wwwwwwwwww
|
||||
Sssssw w w
|
||||
w f w
|
||||
wwwwww w
|
||||
w
|
||||
w
|
||||
f w
|
||||
w
|
||||
f f w
|
||||
w
|
||||
f w
|
||||
w w
|
||||
w
|
||||
w
|
||||
w
|
||||
22
levels/level3
Normal file
22
levels/level3
Normal file
@@ -0,0 +1,22 @@
|
||||
w w
|
||||
|
||||
w
|
||||
ssssS w
|
||||
w f
|
||||
w
|
||||
w
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
w
|
||||
w f
|
||||
f w
|
||||
wwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwww
|
||||
f
|
||||
w w
|
||||
22
levels/level4
Normal file
22
levels/level4
Normal file
@@ -0,0 +1,22 @@
|
||||
w w
|
||||
w
|
||||
f w
|
||||
ssssS w
|
||||
|
||||
|
||||
wwwwwwwwww
|
||||
f
|
||||
|
||||
|
||||
w
|
||||
w
|
||||
w
|
||||
www w
|
||||
f w f
|
||||
w
|
||||
w
|
||||
|
||||
f
|
||||
wwwwwww
|
||||
f
|
||||
w w
|
||||
137
snake.c
137
snake.c
@@ -1,30 +1,147 @@
|
||||
#include <stdlib.h>
|
||||
#include "grid.h"
|
||||
#include "snake.h"
|
||||
|
||||
void crawl(Snake *snake)
|
||||
Snake *new_snake(void)
|
||||
{
|
||||
int i;
|
||||
Coord new_head = snake->pos[0];
|
||||
Snake *snake = (Snake *)malloc(sizeof(Snake));
|
||||
if (snake == NULL)
|
||||
{
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
snake->size = 0;
|
||||
snake->segments_list = NULL;
|
||||
snake->dir = RIGHT;
|
||||
|
||||
return snake;
|
||||
}
|
||||
|
||||
void add_segment(Snake *snake, int x, int y)
|
||||
{
|
||||
Position *new_segment = (Position *)malloc(sizeof(Position));
|
||||
if (new_segment == NULL)
|
||||
{
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
new_segment->x = x;
|
||||
new_segment->y = y;
|
||||
new_segment->next = NULL;
|
||||
|
||||
if (snake->segments_list == NULL)
|
||||
{
|
||||
snake->segments_list = new_segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
Position *current = snake->segments_list;
|
||||
while (current->next != NULL)
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
current->next = new_segment;
|
||||
}
|
||||
|
||||
snake->size++;
|
||||
}
|
||||
|
||||
void free_snake(Snake *snake)
|
||||
{
|
||||
Position *current = snake->segments_list;
|
||||
while (current != NULL)
|
||||
{
|
||||
Position *next = current->next;
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
free(snake);
|
||||
}
|
||||
|
||||
void debug_snake(Snake *snake)
|
||||
{
|
||||
Position *current = snake->segments_list;
|
||||
printf("Snake segments:\n");
|
||||
while (current != NULL)
|
||||
{
|
||||
printf(" (%d, %d)\n", current->x, current->y);
|
||||
current = current->next;
|
||||
}
|
||||
printf("Snake size: %d\n", snake->size);
|
||||
}
|
||||
|
||||
void crawl(Snake *snake, struct GridStruct *g)
|
||||
{
|
||||
Position *new_head = (Position *)malloc(sizeof(Position));
|
||||
Position *current;
|
||||
if (new_head == NULL)
|
||||
{
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
new_head->x = snake->segments_list->x;
|
||||
new_head->y = snake->segments_list->y;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = SNAKE_SIZE - 1; i > 0; i--)
|
||||
new_head->next = snake->segments_list;
|
||||
snake->segments_list = new_head;
|
||||
|
||||
current = snake->segments_list;
|
||||
while (current->next != NULL && current->next->next != NULL)
|
||||
{
|
||||
snake->pos[i] = snake->pos[i - 1];
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
snake->pos[0] = new_head;
|
||||
free(current->next);
|
||||
current->next = NULL;
|
||||
}
|
||||
|
||||
Direction determine_initial_direction(struct GridStruct *g, Position *head)
|
||||
{
|
||||
int x = head->x;
|
||||
int y = head->y;
|
||||
|
||||
printf("Determining initial direction from position (%d, %d)\n", x, y);
|
||||
|
||||
if (x + 1 < g->nbc && g->grid[y][x + 1] != WALL && g->grid[y][x + 1] != SNAKE)
|
||||
{
|
||||
printf("Direction: RIGHT\n");
|
||||
return RIGHT;
|
||||
}
|
||||
if (y + 1 < g->nbl && g->grid[y + 1][x] != WALL && g->grid[y + 1][x] != SNAKE)
|
||||
{
|
||||
printf("Direction: BOTTOM\n");
|
||||
return BOTTOM;
|
||||
}
|
||||
if (x - 1 >= 0 && g->grid[y][x - 1] != WALL && g->grid[y][x - 1] != SNAKE)
|
||||
{
|
||||
printf("Direction: LEFT\n");
|
||||
return LEFT;
|
||||
}
|
||||
if (y - 1 >= 0 && g->grid[y - 1][x] != WALL && g->grid[y - 1][x] != SNAKE)
|
||||
{
|
||||
printf("Direction: TOP\n");
|
||||
return TOP;
|
||||
}
|
||||
|
||||
printf("Default direction: BOTTOM\n");
|
||||
return BOTTOM;
|
||||
}
|
||||
23
snake.h
23
snake.h
@@ -1,13 +1,14 @@
|
||||
#ifndef SNAKE_H
|
||||
#define SNAKE_H
|
||||
|
||||
#define SNAKE_SIZE 4
|
||||
struct GridStruct;
|
||||
|
||||
typedef struct
|
||||
typedef struct Position
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} Coord;
|
||||
struct Position *next;
|
||||
} Position;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -17,12 +18,20 @@ typedef enum
|
||||
RIGHT
|
||||
} Direction;
|
||||
|
||||
typedef struct
|
||||
struct SnakeStruct
|
||||
{
|
||||
Coord pos[SNAKE_SIZE];
|
||||
Position *segments_list;
|
||||
int size;
|
||||
Direction dir;
|
||||
} Snake;
|
||||
};
|
||||
|
||||
void crawl(Snake *snake);
|
||||
typedef struct SnakeStruct Snake;
|
||||
|
||||
Snake *new_snake(void);
|
||||
void add_segment(Snake *snake, int x, int y);
|
||||
void free_snake(Snake *snake);
|
||||
void debug_snake(Snake *snake);
|
||||
void crawl(Snake *snake, struct GridStruct *g);
|
||||
Direction determine_initial_direction(struct GridStruct *g, Position *head);
|
||||
|
||||
#endif /* SNAKE_H */
|
||||
Reference in New Issue
Block a user