385 lines
9.2 KiB
C
385 lines
9.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <MLV/MLV_all.h>
|
|
#include "grid.h"
|
|
#include "snake.h"
|
|
|
|
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;
|
|
if (!g)
|
|
return;
|
|
for (i = 0; i < g->nbl; 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(Grid *g, int w, int h)
|
|
{
|
|
int size_width = w / g->nbc;
|
|
int size_height = h / g->nbl;
|
|
return (size_width < size_height) ? size_width : size_height;
|
|
}
|
|
|
|
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(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 < g->nbl; i++)
|
|
{
|
|
for (j = 0; j < g->nbc; j++)
|
|
{
|
|
int x = j * cell_size;
|
|
int y = i * cell_size;
|
|
|
|
switch (g->grid[i][j])
|
|
{
|
|
case WALL:
|
|
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:
|
|
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:
|
|
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:
|
|
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);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void place_snake(Grid *g, struct SnakeStruct *snake)
|
|
{
|
|
Position *current = snake->segments_list;
|
|
|
|
if (current != NULL)
|
|
{
|
|
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(struct SnakeStruct *snake, Grid *g)
|
|
{
|
|
Position *tail = snake->segments_list;
|
|
Position *head;
|
|
Element element_at_head;
|
|
|
|
while (tail->next != NULL)
|
|
{
|
|
tail = tail->next;
|
|
}
|
|
|
|
g->grid[tail->y][tail->x] = EMPTY;
|
|
|
|
crawl(snake, g);
|
|
|
|
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);
|
|
} |