221 lines
4.5 KiB
C
221 lines
4.5 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include <MLV/MLV_all.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include "grid.h"
|
|
#include "snake.h"
|
|
|
|
#define DIFFICULTY 6
|
|
|
|
void print_help()
|
|
{
|
|
printf("Usage: snake2025 [OPTIONS]\n");
|
|
printf("Options:\n");
|
|
printf(" -h, --help Display this help message\n");
|
|
printf(" -i, --input FILE Load initial grid configuration from FILE\n");
|
|
printf("\n");
|
|
printf("This is a simple snake game. Use the arrow keys to control the snake.\n");
|
|
printf("Press ESC to exit the game.\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
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;
|
|
int width = 640, height = 480;
|
|
MLV_Keyboard_button touche = MLV_KEYBOARD_NONE;
|
|
int initial_size = 0;
|
|
|
|
Grid *g;
|
|
|
|
static struct option long_options[] = {
|
|
{"help", no_argument, 0, 'h'},
|
|
{"input", required_argument, 0, 'i'},
|
|
{0, 0, 0, 0}};
|
|
|
|
Snake *snake = new_snake();
|
|
add_segment(snake, 1, 5);
|
|
add_segment(snake, 1, 4);
|
|
add_segment(snake, 1, 3);
|
|
add_segment(snake, 1, 2);
|
|
add_segment(snake, 1, 1);
|
|
add_segment(snake, 1, 0);
|
|
snake->dir = BOTTOM;
|
|
|
|
initial_size += snake->size;
|
|
|
|
while ((opt = getopt_long(argc, argv, "hi:", long_options, &option_index)) != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'h':
|
|
print_help();
|
|
return 0;
|
|
case 'i':
|
|
input_file = optarg;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use -h or --help for usage information.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
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);
|
|
|
|
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)
|
|
{
|
|
result = move_snake(snake, g);
|
|
|
|
if (result == WALL || result == SNAKE)
|
|
{
|
|
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;
|
|
}
|
|
else if (result == FRUIT)
|
|
{
|
|
Position *tail = snake->segments_list;
|
|
Position *prev = NULL;
|
|
while (tail->next != NULL)
|
|
{
|
|
prev = tail;
|
|
tail = tail->next;
|
|
}
|
|
int dx = tail->x - (prev ? prev->x : tail->x);
|
|
int dy = tail->y - (prev ? prev->y : tail->y);
|
|
add_segment(snake, tail->x + dx, tail->y + dy);
|
|
place_snake(g, snake);
|
|
if (snake->size == initial_size + nb_fruit)
|
|
{
|
|
MLV_draw_text(
|
|
width / 2 - 75, height / 2,
|
|
"You Win! All fruits collected.",
|
|
MLV_COLOR_GREEN);
|
|
MLV_actualise_window();
|
|
MLV_wait_seconds(3);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
draw_grid(g);
|
|
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();
|
|
}
|
|
|
|
MLV_free_window();
|
|
free_grid(g);
|
|
free_snake(snake);
|
|
return 0;
|
|
} |