diff --git a/src/main/c/Snake/get_character.c b/src/main/c/Snake/get_character.c new file mode 100644 index 0000000..9c180ef --- /dev/null +++ b/src/main/c/Snake/get_character.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/src/main/c/Snake/get_character.h b/src/main/c/Snake/get_character.h new file mode 100644 index 0000000..a955266 --- /dev/null +++ b/src/main/c/Snake/get_character.h @@ -0,0 +1,6 @@ +#ifndef GET_CHARACTER_H +#define GET_CHARACTER_H + +char get_character(double limit); + +#endif // GET_CHARACTER_H \ No newline at end of file diff --git a/src/main/c/Snake/snake_start.c b/src/main/c/Snake/snake_start.c new file mode 100644 index 0000000..f6b7996 --- /dev/null +++ b/src/main/c/Snake/snake_start.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#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); +} \ No newline at end of file diff --git a/src/main/c/Snake/snake_start.h b/src/main/c/Snake/snake_start.h new file mode 100644 index 0000000..1634146 --- /dev/null +++ b/src/main/c/Snake/snake_start.h @@ -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 \ No newline at end of file diff --git a/src/main/c/main.c b/src/main/c/main.c index eaf0b17..922c8d4 100644 --- a/src/main/c/main.c +++ b/src/main/c/main.c @@ -3,6 +3,7 @@ #include #include "Template/game100.h" +#include "Snake/snake_start.h" int main(){ bool running = true; @@ -15,7 +16,7 @@ int main(){ printf("Waehlen Sie eine Option:\n"); printf("\t1.Spiel1 starten\n"); printf("\t2.Spiel2 starten\n"); - printf("\t3.Spiel3 starten\n"); + printf("\t3.Snake starten\n"); printf("\t4.Spiel4 starten\n"); printf("\t100.Template starten\n"); printf("\t6.Exit\n"); @@ -31,7 +32,7 @@ int main(){ //start_game2(); break; case 3: - //start_game3(); + snake_start(); break; case 4: //start_game4(); diff --git a/test/Snake/test_collision.c b/test/Snake/test_collision.c new file mode 100644 index 0000000..e5d5a63 --- /dev/null +++ b/test/Snake/test_collision.c @@ -0,0 +1,50 @@ +#ifdef TEST +#include "unity.h" +#include +#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 \ No newline at end of file diff --git a/test/Snake/test_moving_snake.c b/test/Snake/test_moving_snake.c new file mode 100644 index 0000000..115d55f --- /dev/null +++ b/test/Snake/test_moving_snake.c @@ -0,0 +1,69 @@ +#ifdef TEST +#include "unity.h" +#include +#include +#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 \ No newline at end of file diff --git a/test/Snake/test_part_of_snake.c b/test/Snake/test_part_of_snake.c new file mode 100644 index 0000000..95ce3bd --- /dev/null +++ b/test/Snake/test_part_of_snake.c @@ -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 \ No newline at end of file