#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #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; 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) { 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]); } free(buf); fclose(stream); if (input_file) { nb_fruit = count_fruits(input_file, g); } else { exit(EXIT_FAILURE); } 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) { MLV_draw_text( width / 2 - 75, height / 2, "Game Over! You hit something.", MLV_COLOR_RED); MLV_actualise_window(); MLV_wait_seconds(3); break; } else if (result == FRUIT) { nb_fruit--; if (nb_fruit == 0) { 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); return 0; }