Browse Source
Merge branch 'David' into 'main'
Merge branch 'David' into 'main'
Finished Snake See merge request pmuw_projekt/pmuw_projekt_notebinder!15remotes/origin/fdai7775-main-patch-54732
fdai8032
11 months ago
8 changed files with 458 additions and 2 deletions
-
58src/main/c/Snake/get_character.c
-
6src/main/c/Snake/get_character.h
-
201src/main/c/Snake/snake_start.c
-
22src/main/c/Snake/snake_start.h
-
5src/main/c/main.c
-
50test/Snake/test_collision.c
-
69test/Snake/test_moving_snake.c
-
49test/Snake/test_part_of_snake.c
@ -0,0 +1,58 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <sys/select.h> |
|||
#include <termios.h> |
|||
#include <time.h> |
|||
|
|||
struct termios orig_termios; |
|||
|
|||
void reset_terminal_mode(){ |
|||
tcsetattr(0, TCSANOW, &orig_termios); |
|||
} |
|||
|
|||
void set_conio_terminal_mode(){ |
|||
struct termios new_termios; |
|||
|
|||
/* take two copies - one for now, one for later */ |
|||
tcgetattr(0, &orig_termios); |
|||
memcpy(&new_termios, &orig_termios, sizeof(new_termios)); |
|||
|
|||
/* register cleanup handler, and set the new terminal mode */ |
|||
atexit(reset_terminal_mode); |
|||
cfmakeraw(&new_termios); |
|||
tcsetattr(0, TCSANOW, &new_termios); |
|||
} |
|||
|
|||
int kbhit(){ |
|||
struct timeval tv = { 0L, 0L }; |
|||
fd_set fds; |
|||
FD_ZERO(&fds); |
|||
FD_SET(0, &fds); |
|||
return select(1, &fds, NULL, NULL, &tv) > 0; |
|||
} |
|||
|
|||
int getch(){ |
|||
int r; |
|||
unsigned char c; |
|||
if ((r = read(0, &c, sizeof(c))) < 0) { |
|||
return r; |
|||
} else { |
|||
return c; |
|||
} |
|||
} |
|||
|
|||
char get_character(double limit){ |
|||
set_conio_terminal_mode(); |
|||
|
|||
clock_t t = clock(); |
|||
char c = 0; |
|||
|
|||
while ((double)(clock() - t) / CLOCKS_PER_SEC < limit){ |
|||
if(kbhit()){c = getch();} |
|||
} |
|||
|
|||
reset_terminal_mode(); |
|||
|
|||
return c; |
|||
} |
@ -0,0 +1,6 @@ |
|||
#ifndef GET_CHARACTER_H |
|||
#define GET_CHARACTER_H |
|||
|
|||
char get_character(double limit); |
|||
|
|||
#endif // GET_CHARACTER_H |
@ -0,0 +1,201 @@ |
|||
#include <stdio.h> |
|||
#include <stdbool.h> |
|||
#include <time.h> |
|||
#include <unistd.h> |
|||
#include <stdlib.h> |
|||
#include "snake_start.h" |
|||
#include "get_character.h" |
|||
#define TURN 0.5 |
|||
#define START_LENGTH 3 |
|||
#define START_DIRECTION 1 |
|||
#define START_TILE 8 * 16 + 8 |
|||
|
|||
#pragma region Funktion_heads |
|||
void main_menu(); |
|||
void game(); |
|||
void options(); |
|||
Snake initialize_snake(); |
|||
void get_next_move(double limit, Snake *snake, bool *running); |
|||
void move_snake(Snake *snake); |
|||
void draw(Snake *snake, unsigned char fruit); |
|||
int part_of_snake(Snake *snake, unsigned char tile); |
|||
bool check_if_dead(Snake *snake); |
|||
unsigned char spawn_fruit(Snake *snake); |
|||
unsigned char eating_fruit(Snake *snake); |
|||
#pragma endregion |
|||
|
|||
#pragma region Global |
|||
double TIME_TURN = 0.5; |
|||
#pragma endregion //Global |
|||
|
|||
void snake_start(){ |
|||
system("clear"); |
|||
main_menu(); |
|||
} |
|||
|
|||
void main_menu(){ |
|||
bool running = true; |
|||
while (running){ |
|||
int option = 0; |
|||
|
|||
system("clear"); |
|||
printf("Waehlen Sie eine Option:\n"); |
|||
printf("\t1.Start\n"); |
|||
printf("\t2.Options\n"); |
|||
printf("\t3.Exit\n"); |
|||
|
|||
scanf("%d", &option); |
|||
getchar(); |
|||
|
|||
system("clear"); |
|||
|
|||
switch (option){ |
|||
case 1: |
|||
game(); |
|||
break; |
|||
case 2: |
|||
options(); |
|||
break; |
|||
case 3: |
|||
running = false; |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void game(){ |
|||
Snake snake = initialize_snake(); |
|||
bool running = true; |
|||
clock_t t = clock(); |
|||
unsigned char fruit = spawn_fruit(&snake); |
|||
|
|||
while (running){ |
|||
system("clear"); |
|||
draw(&snake, fruit); |
|||
if(check_if_dead(&snake)){break;} |
|||
t = clock() - t; |
|||
get_next_move(TIME_TURN - (double)t / CLOCKS_PER_SEC, &snake, &running); |
|||
t = clock(); |
|||
move_snake(&snake); |
|||
if(part_of_snake(&snake, fruit) == 0){fruit = eating_fruit(&snake);} |
|||
} |
|||
} |
|||
|
|||
void options(){ |
|||
int difficulty = 1; |
|||
system("clear"); |
|||
printf("Please select a difficulty(1 - 10): "); |
|||
scanf("%d", &difficulty); |
|||
TIME_TURN = TURN / difficulty;//(11 - difficulty) * TURN / 10; |
|||
} |
|||
|
|||
Snake initialize_snake(){ |
|||
Snake snake; |
|||
snake.direction = START_DIRECTION; |
|||
snake.length = START_LENGTH; |
|||
for(int i = 0; i < START_LENGTH; i++){ |
|||
snake.segments[i] = START_TILE - START_DIRECTION * i; |
|||
} |
|||
return snake; |
|||
} |
|||
|
|||
void get_next_move(double limit, Snake *snake, bool *running){ |
|||
char c; |
|||
|
|||
c = get_character(limit); |
|||
|
|||
switch (c){ |
|||
case 'w': |
|||
case 'A': |
|||
snake->direction = -16; |
|||
break; |
|||
case 'a': |
|||
case 'D': |
|||
snake->direction = -1; |
|||
break; |
|||
case 's': |
|||
case 'B': |
|||
snake->direction = 16; |
|||
break; |
|||
case 'd': |
|||
case 'C': |
|||
snake->direction = 1; |
|||
break; |
|||
case 'q': |
|||
*running = false; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void move_snake(Snake *snake){ |
|||
for(int i = snake->length - 1; i > 0; i--){ |
|||
snake->segments[i] = snake->segments[i - 1]; |
|||
} |
|||
snake->segments[0] += snake->direction; |
|||
} |
|||
|
|||
void draw(Snake *snake, unsigned char fruit){ |
|||
printf("Score:%d Speed:%f\n", snake->length - START_LENGTH, TIME_TURN); |
|||
printf("+"); |
|||
for(int i = 0; i < WIDTH; i++){printf("-");} |
|||
printf("+\n"); |
|||
for(int i = 1; i <= HEIGHT; i++){ |
|||
printf("|"); |
|||
for(int j = 1; j <= WIDTH; j++){ |
|||
int index = part_of_snake(snake, i * 16 + j); |
|||
if(index == 0){printf("0");} |
|||
else if(index > 0){printf("O");} |
|||
else if(i * 16 + j == fruit){printf("X");} |
|||
else{printf(" ");} |
|||
} |
|||
printf("|\n"); |
|||
} |
|||
printf("+"); |
|||
for(int i = 0; i < WIDTH; i++){printf("-");} |
|||
printf("+\n"); |
|||
printf("(Press q to Quit)\n"); |
|||
} |
|||
|
|||
//returns index of segments which is identical to tile; -1 if not found |
|||
int part_of_snake(Snake *snake, unsigned char tile){ |
|||
for(int i = snake->length - 1; i >= 0; i--){ |
|||
if(snake->segments[i] == tile){ |
|||
return i; |
|||
} |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
bool check_if_dead(Snake *snake){ |
|||
//Self |
|||
if(part_of_snake(snake, snake->segments[0]) > 0){ |
|||
return true; |
|||
} |
|||
|
|||
//Wall |
|||
if(snake->segments[0] % 16 == 0 || (snake->segments[0] / 16) % 16 == 0){ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
unsigned char spawn_fruit(Snake *snake){ |
|||
srand(time(NULL)); |
|||
int r = 0; |
|||
while (part_of_snake(snake, r) != -1 || r % 16 == 0 || (r / 16) % 16 == 0){ |
|||
r = rand() % 256; |
|||
printf("%d\n", r); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
unsigned char eating_fruit(Snake *snake){ |
|||
snake->length++; |
|||
return spawn_fruit(snake); |
|||
} |
@ -0,0 +1,22 @@ |
|||
#ifndef SNAKE_START_H |
|||
#define SNAKE_START_H |
|||
|
|||
#define HEIGHT 15 |
|||
#define WIDTH 15 |
|||
#define AREA HEIGHT * WIDTH |
|||
|
|||
typedef struct{ |
|||
signed char direction; |
|||
char length; |
|||
unsigned char segments[AREA]; |
|||
}Snake; |
|||
|
|||
|
|||
void snake_start(); |
|||
Snake initialize_snake(); |
|||
int part_of_snake(Snake *snake, unsigned char tile); |
|||
void move_snake(Snake *snake); |
|||
bool check_if_dead(Snake *snake); |
|||
|
|||
|
|||
#endif // SNAKE_START_H |
@ -0,0 +1,50 @@ |
|||
#ifdef TEST |
|||
#include "unity.h" |
|||
#include <stdbool.h> |
|||
#include "../../src/main/c/Snake/snake_start.h" |
|||
#include "../../src/main/c/Snake/get_character.h" |
|||
|
|||
|
|||
void setUp(void){} |
|||
void tearDown(void){} |
|||
|
|||
|
|||
void test_self_collision(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {1, 5, {6 + 16 * 6, 6 + 16 * 7, 7 + 16 * 7, 7 + 16 * 6, 6 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
result = check_if_dead(&snake); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result);//head collides with body |
|||
} |
|||
|
|||
|
|||
void test_no_collision(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = initialize_snake(); |
|||
|
|||
/* act */ |
|||
result = check_if_dead(&snake); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_FALSE(result);//head collides with body |
|||
} |
|||
|
|||
|
|||
void test_wall_collision(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {-1, 4, {0 + 16 * 6, 1 + 16 * 6, 2 + 16 * 6, 3 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
result = check_if_dead(&snake); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result);//head collides with body |
|||
} |
|||
|
|||
#endif // TEST |
@ -0,0 +1,69 @@ |
|||
#ifdef TEST |
|||
#include "unity.h" |
|||
#include <stdbool.h> |
|||
#include <memory.h> |
|||
#include "../../src/main/c/Snake/snake_start.h" |
|||
#include "../../src/main/c/Snake/get_character.h" |
|||
|
|||
|
|||
void setUp(void){} |
|||
void tearDown(void){} |
|||
|
|||
|
|||
void test_moving_right(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {1, 3, {8 + 16 * 6, 7 + 16 * 6, 6 + 16 * 6}}; |
|||
Snake expected = {1, 3, {9 + 16 * 6, 8 + 16 * 6, 7 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
move_snake(&snake); |
|||
result = memcmp(&snake, &expected, sizeof(Snake)) == 0; |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result); |
|||
} |
|||
|
|||
void test_moving_down(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {16, 3, {8 + 16 * 6, 7 + 16 * 6, 6 + 16 * 6}}; |
|||
Snake expected = {16, 3, {8 + 16 * 7, 8 + 16 * 6, 7 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
move_snake(&snake); |
|||
result = memcmp(&snake, &expected, sizeof(Snake)) == 0; |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result); |
|||
} |
|||
|
|||
void test_moving_left(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {-1, 3, {8 + 16 * 6, 7 + 16 * 6, 6 + 16 * 6}}; |
|||
Snake expected = {-1, 3, {7 + 16 * 6, 8 + 16 * 6, 7 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
move_snake(&snake); |
|||
result = memcmp(&snake, &expected, sizeof(Snake)) == 0; |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result); |
|||
} |
|||
|
|||
void test_moving_up(void){ |
|||
/* arrange */ |
|||
bool result; |
|||
Snake snake = {-16, 3, {8 + 16 * 6, 7 + 16 * 6, 6 + 16 * 6}}; |
|||
Snake expected = {-16, 3, {8 + 16 * 5, 8 + 16 * 6, 7 + 16 * 6}}; |
|||
|
|||
/* act */ |
|||
move_snake(&snake); |
|||
result = memcmp(&snake, &expected, sizeof(Snake)) == 0; |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_TRUE(result); |
|||
} |
|||
|
|||
#endif // TEST |
@ -0,0 +1,49 @@ |
|||
#ifdef TEST |
|||
#include "unity.h" |
|||
#include "../../src/main/c/Snake/snake_start.h" |
|||
#include "../../src/main/c/Snake/get_character.h" |
|||
|
|||
|
|||
void setUp(void){} |
|||
void tearDown(void){} |
|||
|
|||
|
|||
void test_find_head(void){ |
|||
/* arrange */ |
|||
int result; |
|||
Snake snake = initialize_snake(); |
|||
|
|||
/* act */ |
|||
result = part_of_snake(&snake, 8 * 16 + 8); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_EQUAL_INT(0, result);//head is at 8/8 |
|||
} |
|||
|
|||
|
|||
void test_get_correct_index(void){ |
|||
/* arrange */ |
|||
int result; |
|||
Snake snake = initialize_snake(); |
|||
|
|||
/* act */ |
|||
result = part_of_snake(&snake, 8 * 16 + 6); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_EQUAL_INT(2, result);//2. part ist at 6/8 |
|||
} |
|||
|
|||
|
|||
void test_snake_not_on_tile(void){ |
|||
/* arrange */ |
|||
int result; |
|||
Snake snake = initialize_snake(); |
|||
|
|||
/* act */ |
|||
result = part_of_snake(&snake, 6 * 16 + 6); |
|||
|
|||
/* assert */ |
|||
TEST_ASSERT_EQUAL_INT(-1, result);//-1 snake is not on 6/6 |
|||
} |
|||
|
|||
#endif // TEST |
Write
Preview
Loading…
Cancel
Save
Reference in new issue