This commit is contained in:
Oleksandr Vyshniakov 2025-05-01 22:45:15 +02:00
parent 7ea4fe4500
commit eb14c451e1
11 changed files with 403 additions and 1 deletions

View File

@ -1,6 +1,6 @@
CC = gcc CC = gcc
CFLAGS = -Wall -Wextra -std=c99 CFLAGS = -Wall -Wextra -std=c99
dIRS = a1 du1 du2 du3 du4 du5 dIRS = a1 du1 du2 du3 du4 du5 a3
all: all:
@for %%d in ($(dIRS)) do \ @for %%d in ($(dIRS)) do \
$(CC) $(CFLAGS) %%d\program.c -o %%d\program.exe $(CC) $(CFLAGS) %%d\program.c -o %%d\program.exe

19
a3/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC = gcc
CFLAGS = -Wall -Wextra -std=c99
OBJS = main.o snake.o world.o
snake: $(OBJS)
$(CC) $(CFLAGS) -o snake $(OBJS)
main.o: main.c snake.h world.h
$(CC) $(CFLAGS) -c main.c
snake.o: snake.c snake.h
$(CC) $(CFLAGS) -c snake.c
world.o: world.c world.h snake.h
$(CC) $(CFLAGS) -c world.c
clean:
del *.o *.exe

42
a3/main.c Normal file
View File

@ -0,0 +1,42 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "snake.h"
#include "world.h"
int main(void) {
struct state game_state;
setup_world(&game_state, 20, 10);
draw_world(&game_state);
while (1) {
char command = read_input();
change_direction(&game_state, command);
int outcome = step_state(&game_state);
draw_world(&game_state);
if (outcome != END_CONTINUE) {
break;
}
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
free_snake(game_state.snake);
printf("\n--- KONIEC HRY ---\n");
return 0;
}

BIN
a3/main.o Normal file

Binary file not shown.

110
a3/snake.c Normal file
View File

@ -0,0 +1,110 @@
#include <stdio.h>
#include "snake.h"
#include <stdlib.h>
struct snake* add_snake (struct snake* snake, int x, int y) {
struct snake* head = NULL;
head = malloc(sizeof(struct snake));
if (!head) {
return snake;
}
head->x = x;
head->y = y;
head->next = NULL;
if (snake !=NULL) {
head->next = snake;
}
return head;
}
struct snake* remove_snake(struct snake* snake) {
if (snake == NULL) {
return NULL;
}
if (snake->next == NULL) {
free(snake);
return NULL;
}
struct snake* temp = snake;
while (temp->next->next != NULL) {
temp = temp->next;
}
free(temp->next);
temp->next = NULL;
return snake;
}
void free_snake(struct snake* sn) {
struct snake* walker = sn;
struct snake* next_part = NULL;
while (walker !=NULL) {
next_part = walker->next;
free(walker);
walker = next_part;
}
}
int is_snake(struct snake* snake, int x, int y) {
struct snake* current = snake;
while (current !=NULL) {
if ((current->x==x) && (current->y==y)) {
return 1;
}
current = current->next;
}
return 0;
}
int step_state(struct state* state) {
int x = state->snake->x + state->sx;
int y = state->snake->y + state->sy;
if (x < 0) return END_WALL;
if (x >= state->width) return END_WALL;
if (y < 0) return END_WALL;
if (y >= state->height) return END_WALL;
if (is_snake(state->snake, x, y)) {
return END_SNAKE;
}
int food_found = -1;
for (int idx = 0; idx < FOOD_COUNT; idx++) {
if (state->foodx[idx] == x && state->foody[idx] == y) {
food_found = idx;
break;
}
}
if (food_found != -1) {
state->foodx[food_found] = -1;
state->foody[food_found] = -1;
state->snake = add_snake(state->snake, x, y);
int remaining = 0;
for (int k = 0; k < FOOD_COUNT; ++k) {
remaining += (state->foodx[k] >= 0 && state->foody[k] >= 0);
}
if (remaining == 0) {
return END_FOOD;
}
return END_CONTINUE;
}
state->snake = add_snake(state->snake, x, y);
state->snake = remove_snake(state->snake);
return END_CONTINUE;
}

BIN
a3/snake.exe Normal file

Binary file not shown.

111
a3/snake.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef snake_h_INCLUDED
#define snake_h_INCLUDED
// Number of food items on the plane
#define FOOD_COUNT 5
/**
* One part of the snake;
*
* The snake is a linked list;
*/
struct snake {
// x position of the snake part
int x;
// y position of the snake part
int y;
// Pointer to the next snake part.
// The last part of the snake has NULL pointer to the next part.
struct snake* next;
};
// End game reason constants, return value of step_state
enum endgame {
// Continue the game
END_CONTINUE = 0,
// Snake hit a wall
END_WALL,
// Snake hit itself
END_SNAKE,
// No food left
END_FOOD,
// Other reason to end
END_USER
};
/**
* State of the game.
*
* The state consists of the snake, its speed and food on the plane.
*
* The snake is a linked list of snake parts.
*
* Speed vector is a vector added to the last head position to create a new head.
*
* Food are points on the plane. Food with negative coordinates means food is already eaten.
*/
struct state {
// Snake as a linked list
struct snake* snake;
// X of the food positions
int foodx[FOOD_COUNT];
// Y of the food positions
int foody[FOOD_COUNT];
int sx;
int sy;
int width;
int height;
};
/**
* Add a new snake part with given position. The new snake part becomes the new head.
*
* @param head of the snake.
* @param x coordinate of the new head;
* @param y coordinate of the new head.
* @return new head of the snake.
*/
struct snake* add_snake(struct snake* snake, int x, int y);
/**
* Remove the last snake part.
* The last snake part should always have NULL next pointer.
*
* @param head of the snake.
* @return new head of the snake.
*/
struct snake* remove_snake(struct snake* snake);
/**
* Finds out if given coordinates are part of the snake.
* @param snake
* @param x coordinate to search in snake
* @param y coordinate to search in snake
* @return True, if there is a snake part with coordinates x,y. False otherwise
*/
int is_snake(struct snake* snake, int x, int y);
/**
* Remove and free each snake part;
* @param head of the snake.
*/
void free_snake(struct snake* sn);
/**
* Change game state.
*
* The function should calculate new position of the snake head
* from the current position and speed vector.
* Then it should modify snake parts or food coordinates according to the rules:
*
* - If the new position is on the snake, end the game, return END_SNAKE.
* - If the new position is on the food, mark food as eaten
* (set its coordinates to -1) and add new snake part on the position of the food. If there is no food left, return END_FOOD. Else return END_CONTINUE.
* - If the new position is on the plane, add new snake part on the new position and remove the last part of the snake, return END_CONTINUE.
*
* @param current state of the game
* @return reason to end the game according to enum endgame.
*/
int step_state(struct state* state);
#endif // snake_h_INCLUDED

BIN
a3/snake.o Normal file

Binary file not shown.

109
a3/world.c Normal file
View File

@ -0,0 +1,109 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "world.h"
#include "snake.h"
static void place_food(struct state* s) {
int placed = 0;
while (placed < FOOD_COUNT) {
int fx = rand() % s->width;
int fy = rand() % s->height;
if (!is_snake(s->snake, fx, fy)) {
s->foodx[placed] = fx;
s->foody[placed] = fy;
placed++;
}
}
}
void setup_world(struct state* s, int w, int h) {
if (!s) return;
srand((unsigned int)time(NULL));
s->width = w;
s->height = h;
s->sx = 1;
s->sy = 0;
s->snake = NULL;
int start_x = w / 2;
int start_y = h / 2;
s->snake = add_snake(s->snake, start_x, start_y);
place_food(s);
}
void draw_world(const struct state* s) {
if (!s) return;
system("clear"); // или "cls" на Windows
for (int row = 0; row < s->height; row++) {
for (int col = 0; col < s->width; col++) {
int drawn = 0;
if (is_snake(s->snake, col, row)) {
putchar('O');
drawn = 1;
} else {
for (int i = 0; i < FOOD_COUNT; ++i) {
if (s->foodx[i] == col && s->foody[i] == row) {
putchar('*');
drawn = 1;
break;
}
}
}
if (!drawn) {
putchar('.');
}
}
putchar('\n');
}
}
char read_input(void) {
char key = 0;
printf("Zadaj smer (WASD): ");
scanf(" %c", &key);
return key;
}
void change_direction(struct state* s, char key) {
if (!s) return;
switch (key) {
case 'w':
case 'W':
s->sx = 0;
s->sy = -1;
break;
case 's':
case 'S':
s->sx = 0;
s->sy = 1;
break;
case 'a':
case 'A':
s->sx = -1;
s->sy = 0;
break;
case 'd':
case 'D':
s->sx = 1;
s->sy = 0;
break;
default:
// ничего не делаем при некорректном вводе
break;
}
}

11
a3/world.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef WORLD_MODULE_H
#define WORLD_MODULE_H
#include "snake.h"
void setup_world(struct state* s, int w, int h);
void draw_world(const struct state* s);
char read_input(void);
void change_direction(struct state* s, char key);
#endif

BIN
a3/world.o Normal file

Binary file not shown.