refresh
This commit is contained in:
parent
7ea4fe4500
commit
eb14c451e1
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c99
|
||||
dIRS = a1 du1 du2 du3 du4 du5
|
||||
dIRS = a1 du1 du2 du3 du4 du5 a3
|
||||
all:
|
||||
@for %%d in ($(dIRS)) do \
|
||||
$(CC) $(CFLAGS) %%d\program.c -o %%d\program.exe
|
||||
|
19
a3/Makefile
Normal file
19
a3/Makefile
Normal 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
42
a3/main.c
Normal 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;
|
||||
}
|
110
a3/snake.c
Normal file
110
a3/snake.c
Normal 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
BIN
a3/snake.exe
Normal file
Binary file not shown.
111
a3/snake.h
Normal file
111
a3/snake.h
Normal 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
BIN
a3/snake.o
Normal file
Binary file not shown.
109
a3/world.c
Normal file
109
a3/world.c
Normal 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
11
a3/world.h
Normal 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
BIN
a3/world.o
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user