diff --git a/.gitignore b/.gitignore index 567609b..0b8cb6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build/ +.clangd diff --git a/compile.sh b/compile.sh index c5ab917..f15cf5d 100755 --- a/compile.sh +++ b/compile.sh @@ -1,3 +1,22 @@ -#!/bin/bash +#!/bin/sh -gcc -Og -g -Wall -Werror -pedantic -o build/sanke src/main.c src/snake/**.c src/utils/**.c src/board/**.c +src="src/*.c" +flags="-std=c23 -ggdb -Og -Wall -Wextra -Werror -Wpedantic -pedantic-errors" +includes="-I src/headers" + +cmd="gcc $flags $includes $src -o target/sanke" + +echo $cmd +$cmd + +if [ $? -gt 0 ]; then + exit +fi + +echo + +if [ -v 1 ]; then + if [ $1 = "run" ]; then + ./target/sanke + fi +fi diff --git a/compile_release.sh b/compile_release.sh deleted file mode 100755 index 6967e1a..0000000 --- a/compile_release.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -gcc -Wall -Werror -pedantic -O3 -o build/sanke src/main.c src/snake/**.c src/utils/**.c src/board/**.c; diff --git a/src/board.c b/src/board.c new file mode 100644 index 0000000..074961b --- /dev/null +++ b/src/board.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#include "board.h" +#include "snake.h" + +#define MAT_INDEX(mat, w, i, j) (mat)[(j) + (w) * (i)] + +Board board_alloc(const int width, const int height) { + Board board = {}; + board.width = width * 2; + board.height = height; + + board.width_with_borders = board.width + 2; + board.height_with_borders = board.height + 2; + board.squares = (char*) malloc(sizeof(char) * board.width_with_borders * board.height_with_borders); + + for (size_t i = 1; i < board.height_with_borders; i++) { + for (size_t j = 1; j < board.width_with_borders; j++) { + MAT_INDEX(board.squares, board.width_with_borders, i, j) = ' '; + } + } + + // Create border pattern + const int width_with_borders_last_i = board.width_with_borders - 1; + const int height_with_borders_last_i = board.height_with_borders - 1; + // Vertical bars + for (int i = 1; i < height_with_borders_last_i; i++) { + MAT_INDEX(board.squares, board.width_with_borders, i, 0) = '|'; + MAT_INDEX(board.squares, board.width_with_borders, i, width_with_borders_last_i) = '|'; + } + // Horizontal lines + for (int j = 1; j < width_with_borders_last_i; j++) { + MAT_INDEX(board.squares, board.width_with_borders, 0, j) = '-'; + MAT_INDEX(board.squares, board.width_with_borders, height_with_borders_last_i, j) = '-'; + } + + // Corners + MAT_INDEX(board.squares, board.width_with_borders, 0, 0) = '+'; + MAT_INDEX(board.squares, board.width_with_borders, height_with_borders_last_i, 0) = '+'; + MAT_INDEX(board.squares, board.width_with_borders, 0, width_with_borders_last_i) = '+'; + MAT_INDEX(board.squares, board.width_with_borders, height_with_borders_last_i, width_with_borders_last_i) = '+'; + + return board; +} + +void board_free(Board* board) { + free(board->squares); +} + +bool board_coords_out_of_bounds(Board* board, const size_t x, const size_t y) { + return x >= board->width_with_borders || y >= board->height_with_borders; +} + +void board_set_square( + Board* board, + int x, + int y, + const char ch + ) +{ + x++; + y++; + if (board_coords_out_of_bounds(board, x, y)) { + fprintf(stderr, "ERROR: Board coords out of bounds: x: %d y: %d\n", x, y); + exit(EXIT_FAILURE); + } + // assert(board_coords_out_of_bounds(board, x, y)); + MAT_INDEX(board->squares, board->width_with_borders, y, x) = ch; +} + +void board_clear(Board* board) { + for (size_t i = 0; i < board->height; i++) { + for (size_t j = 0; j < board->width; j++) { + printf("Clearing board: i: %zu j: %zu\n", i, j); + board_set_square(board, j, i, ' '); + } + } +} + +void board_draw_snake(Board* board, Snake* snake) { + SnakePart part = {}; + for (size_t i = 0; i < snake->length; i++) { + part = snake_get_part(snake, i); + board_set_square(board, part.y, part.x, part.vis_char); + } +} + +void print_board(Board* board) { + for (size_t i = 0; i < board->height_with_borders; i++) { + for (size_t j = 0; j < board->width_with_borders; j++) { + printf("%c", MAT_INDEX(board->squares, board->width_with_borders, i, j)); + } + printf("\n"); + } +} diff --git a/src/board/board.c b/src/board/board.c deleted file mode 100644 index db76383..0000000 --- a/src/board/board.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#include "board.h" - -void setBoardBorders(char board[][brdInfo.x]) { - for (int i = 0; i < brdInfo.y; i++) { - for (int j = 0; j < brdInfo.x; j++) { - if (i == 0 || i == brdInfo.y - 1) - board[i][j] = '-'; - else if (j == 0 || j == brdInfo.x - 1) - board[i][j] = '|'; - else - board[i][j] = ' '; - } - } - - board[0][0] = '+'; - board[brdInfo.y - 1][0] = '+'; - board[0][brdInfo.x - 1] = '+'; - board[brdInfo.y - 1][brdInfo.x - 1] = '+'; -} - -void printBoard(char board[][brdInfo.x]) { - for (int i = 0; i < brdInfo.y; i++) { - for (int j = 0; j < brdInfo.x; j++) { - printf("%c", board[i][j]); - } - printf("\n"); - } -} diff --git a/src/board/board.h b/src/board/board.h deleted file mode 100644 index d51ef14..0000000 --- a/src/board/board.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef BOARD_H_ -#define BOARD_H_ - -typedef struct { - int x; - int y; -} boardInfo; - -typedef struct { - int xs; - int xe; - int ys; - int ye; -} playableBoardInfo; - -extern boardInfo brdInfo; - -void setBoardBorders(char board[][brdInfo.x]); -void printBoard(char board[][brdInfo.x]); - -#endif diff --git a/src/headers/board.h b/src/headers/board.h new file mode 100644 index 0000000..9686d57 --- /dev/null +++ b/src/headers/board.h @@ -0,0 +1,30 @@ +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "snake.h" + +typedef struct { + size_t width; + size_t height; + size_t width_with_borders; + size_t height_with_borders; + char* squares; +} Board; + +Board board_alloc( + const int width, + const int height + ); +void board_free(Board* board); +bool board_coords_out_of_bounds(Board* board, const size_t x, const size_t y); +void board_set_square( + Board* board, + const int x, + const int y, + const char ch + ); +void board_clear(Board* board); +void board_draw_snake(Board* board, Snake* snake); +void print_board(Board* board); + +#endif diff --git a/src/headers/snake.h b/src/headers/snake.h new file mode 100644 index 0000000..ada466c --- /dev/null +++ b/src/headers/snake.h @@ -0,0 +1,29 @@ +#ifndef SNAKE_H_ +#define SNAKE_H_ + +#include + +typedef struct { + int x; + int y; + char vis_char; +} SnakePart; + +typedef struct { + SnakePart* parts; + size_t max_length; + size_t length; + char dir; +} Snake; + +SnakePart snake_get_part(const Snake* snake, const size_t index); +Snake snake_alloc( + const int board_square_count, + const int init_x, + const int init_y, + const char init_dir + ); +void snake_free(Snake* snake); +void snake_move(Snake* snake); + +#endif // SNAKE_H_ diff --git a/src/utils/utils.h b/src/headers/utils.h similarity index 54% rename from src/utils/utils.h rename to src/headers/utils.h index 87b53e4..31b3b13 100644 --- a/src/utils/utils.h +++ b/src/headers/utils.h @@ -1,16 +1,8 @@ #ifndef UTILS_H_ #define UTILS_H_ -#include - -#include "../board/board.h" - -extern boardInfo brdInfo; - int randomInt(const int start, const int end, const unsigned int seed); -int randomX(const clock_t initClock); -int randomY(const clock_t initClock); -void sleep_ms(const int ms); void mallocError(const char* varName, const char* fileName, const char* functionName); +void sleep_ms(const unsigned int ms); #endif // UTILS_H_ diff --git a/src/main.c b/src/main.c index 923eaad..b05530d 100644 --- a/src/main.c +++ b/src/main.c @@ -5,187 +5,56 @@ #include #include #include -#include -#include "./utils/utils.h" -#include "./snake/snake.h" -#include "./board/board.h" +#include "board.h" +#include "snake.h" +#include "utils.h" const char* VERSION = "1.1.9"; const char SNAKE_VIS = '#'; -boardInfo brdInfo; -playableBoardInfo plBrdInfo; - void cmd_args(int argc, char** argv); -void emptyStdinBuffer(); -void getIntOrMinusOne(int* dst); +void empty_stdin_buffer(); +void get_int_or_minus_one(int* dst); +struct termios set_termios(); -int main(int argc, char** argv) { - cmd_args(argc, argv); - - const clock_t initClock = clock(); - - // Board Constraints - printf("Set board size (15 - 60, default: 15): "); - getIntOrMinusOne(&brdInfo.y); - if (!(brdInfo.y >= 15 && brdInfo.y <= 60) || brdInfo.y == -1) { - brdInfo.y = 15; - } - brdInfo.x = brdInfo.y * 2; - /*printf("brdInfo.x: %d\n", brdInfo.x);*/ - /*printf("brdInfo.y: %d\n", brdInfo.y);*/ - char board[brdInfo.y][brdInfo.x]; - - plBrdInfo.xs = 1; - plBrdInfo.xe = brdInfo.x - 2; - plBrdInfo.ys = 1; - plBrdInfo.ye = brdInfo.y - 2; +int main() { + // cmd_args(argc, argv); + // const clock_t initClock = clock(); // Set gamespeed - int gameSpeed = 0; - printf("Enter gamespeed (default: 0, max: 180): "); - getIntOrMinusOne(&gameSpeed); - if (gameSpeed == -1 || gameSpeed > 180) { - gameSpeed = 0; - } + // int gameSpeed = 0; + // printf("Enter gamespeed (default: 0, max: 180): "); + // getIntOrMinusOne(&gameSpeed); + // if (gameSpeed == -1 || gameSpeed > 180) { + // gameSpeed = 0; + // } // Termios setup - struct termios attr; + const struct termios attr_orig = set_termios(); - tcgetattr(STDIN_FILENO, &attr); - - const struct termios ATTR_ORIG = attr; - - attr.c_lflag &= ~(ECHO | ICANON); - attr.c_cc[VMIN] = 0; - attr.c_cc[VTIME] = 0; - - tcsetattr(STDIN_FILENO, 0, &attr); - - // Game board setup - setBoardBorders(board); - - int points = 0; - const int sleepInterval = 200; - - // Snake head setup - snakePart* snakeHead = malloc(sizeof(snakePart)); - if (!snakeHead) { - mallocError("snakeHead", "main.c", "main()"); - } - snakeHead->x = randomX(initClock); - snakeHead->y = randomY(initClock); - snakeHead->visChar = '&'; - snakeHead->dir = 'w'; - snakeHead->order = malloc(sizeof(order)); - if (!snakeHead->order) { - mallocError("snakeHead->order", "main.c", "main()"); - } - snakeHead->order->dir = snakeHead->dir; - snakeHead->order->delay = -1; - snakeHead->order->next = NULL; - snakeHead->next = NULL; - - board[snakeHead->y][snakeHead->x] = snakeHead->visChar; - - // Food setup - struct { - int x; - int y; - char visChar; - } food; - food.x = randomX(initClock); - food.y = randomY(initClock); - food.visChar = '$'; - - board[food.y][food.x] = food.visChar; + // Game model init + const int board_w = 15; + const int board_h = 15; + Board board = board_alloc(board_w, board_h); + Snake snake = snake_alloc(board_w * board_h, 0, 0, 'd'); // Screen init system("clear"); - // Game loop - while (1) { - fflush(stdout); - char buf[1] = {0}; - - // Food collision - if (snakeHead->x == food.x - && snakeHead->y == food.y) { - points++; - if (gameSpeed >= 100) { - gameSpeed += 5; - } else { - gameSpeed += 10; - } - - if (gameSpeed >= 180) { - gameSpeed = 180; - } - - do { - food.x = randomX(initClock); - food.y = randomY(initClock); - } while (checkCollision(snakeHead, food.x, food.y)); - addSnakePart(board, snakeHead); - } - - // Input handling - if (read(STDIN_FILENO, buf, 1) != 0 && isalpha(buf[0])) { - char input = buf[0]; - input = tolower(input); - - if ( - (input == 'w' && snakeHead->dir != 's') - || (input == 's' && snakeHead->dir != 'w') - || (input == 'a' && snakeHead->dir != 'd') - || (input == 'd' && snakeHead->dir != 'a') - ) { - snakeHead->dir = input; - addOrders(snakeHead, input); - } - } - - // Update board - board[food.y][food.x] = food.visChar; - mvSnakeParts(board, snakeHead); - - // Snake collision - if (snakeHead->next != NULL) { - snakePart* current = snakeHead->next; - while (1) { - if (current->x == snakeHead->x - && current->y == snakeHead->y) - goto game_over; - - if (current->next == NULL) - break; - - current = current->next; - } - } - + while (true) { system("clear"); - printBoard(board); - printf("Points: %d\n", points); - printf("Game Speed: %d\n", gameSpeed); - - sleep_ms(sleepInterval - gameSpeed); + snake_move(&snake); + board_clear(&board); + board_draw_snake(&board, &snake); + print_board(&board); + sleep_ms(1000); } -game_over: - - // Game over - system("clear"); - - printBoard(board); - printf("Final Points: %d\n", points); - printf("Final Game Speed: %d\n", gameSpeed); - - tcsetattr(STDIN_FILENO, 0, &ATTR_ORIG); + tcsetattr(STDIN_FILENO, 0, &attr_orig); return 0; } @@ -205,15 +74,15 @@ void cmd_args(int argc, char** argv) { } } -void emptyStdinBuffer() { +void empty_stdin_buffer() { char ch; while ((ch = getchar()) != '\n'); } -void getIntOrMinusOne(int* dst) { +void get_int_or_minus_one(int* dst) { char iBuf[100]; char num[100]; - int i = 0; + size_t i = 0; fgets(iBuf, 100, stdin); @@ -231,3 +100,19 @@ void getIntOrMinusOne(int* dst) { *dst = atoi(num); } + +struct termios set_termios() { + struct termios attr; + + tcgetattr(STDIN_FILENO, &attr); + + const struct termios attr_orig = attr; + + attr.c_lflag &= ~(ECHO | ICANON); + attr.c_cc[VMIN] = 0; + attr.c_cc[VTIME] = 0; + + tcsetattr(STDIN_FILENO, 0, &attr); + + return attr_orig; +} diff --git a/src/snake.c b/src/snake.c new file mode 100644 index 0000000..0325fd7 --- /dev/null +++ b/src/snake.c @@ -0,0 +1,83 @@ +#include +#include +#include + +#include "snake.h" + +static SnakePart* snake_get_part_ptr(const Snake* snake, const size_t index) { + if (index >= snake->max_length) { + return NULL; + } + + return snake->parts + index; +} + +SnakePart snake_get_part(const Snake* snake, const size_t index) { + assert(index < snake->max_length); + return snake->parts[index]; +} + +Snake snake_alloc( + const int board_square_count, + const int init_x, + const int init_y, + const char init_dir + ) +{ + Snake snake = {0}; + snake.max_length = board_square_count; + snake.length = 1; + snake.dir = init_dir; + snake.parts = (SnakePart*) malloc(sizeof(SnakePart) * snake.max_length); + snake.parts[0] = (SnakePart) { .x = init_x, .y = init_y, .vis_char = '&' }; + + return snake; +} + +void snake_free(Snake* snake) { + free(snake->parts); +} + +void snake_move(Snake* snake) { + SnakePart* first_part = snake_get_part_ptr(snake, 0); + int first_part_old_x = first_part->x; + int first_part_old_y = first_part->y; + + // Move first part + switch (snake->dir) { + case 'w': + first_part->y -= 1; + break; + case 'a': + first_part->x -= 1; + break; + case 's': + first_part->y += 1; + break; + case 'd': + first_part->x += 1; + break; + default: + fprintf(stderr, "ERROR: Invalid direction in snake_move: %c.\n", snake->dir); + exit(EXIT_FAILURE); + } + + // Stop here if there is only one part + SnakePart* last_part = snake_get_part_ptr(snake, snake->length - 1); + if (last_part == first_part) { + return; + } + + // Move all other parts except for the second one, gets skipped if there are only 2 parts + SnakePart* second_part = first_part + 1; + SnakePart* prev_part = 0; + for (SnakePart* part = last_part; part != second_part; part--) { + prev_part = part - 1; + part->x = prev_part->x; + part->y = prev_part->y; + } + + // Move second part + second_part->x = first_part_old_x; + second_part->y = first_part_old_y; +} diff --git a/src/snake/snake.c b/src/snake/snake.c deleted file mode 100644 index 127e2f2..0000000 --- a/src/snake/snake.c +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include - -#include "snake.h" -#include "../board/board.h" -#include "../utils/utils.h" - -extern char SNAKE_VIS; -extern boardInfo brdInfo; -extern playableBoardInfo plBrdInfo; - -void mvSnakeParts(char board[][brdInfo.x], snakePart* head) { - snakePart* part = head; - while (1) { - - order* orderHead = part->order; - - if (orderHead->next != NULL) { - if (orderHead->next->delay == 0) { - part->dir = orderHead->next->dir; - removeOrder(orderHead); - } - } - - if (orderHead->next != NULL) { - order* current = orderHead->next; - while (1) { - if (current->delay > 0) - current->delay--; - if (current->next == NULL) - break; - current = current->next; - } - } - - int x = part->x; - int y = part->y; - - board[y][x] = ' '; - - switch (part->dir) { - case 'w': - y = y - 1 < plBrdInfo.ys ? plBrdInfo.ye : y - 1; - break; - case 's': - y = y + 1 > plBrdInfo.ye ? plBrdInfo.ys : y + 1; - break; - case 'a': - x = x - 2 < plBrdInfo.xs ? plBrdInfo.xe - 1 : x - 2; - break; - case 'd': - x = x + 2 > plBrdInfo.xe ? plBrdInfo.xs : x + 2; - break; - default: - printf("ERROR in func mvSnakeParts\n"); - printf("dir: %c\n", part->dir); - exit(1); - } - - part->x = x; - part->y = y; - - board[y][x] = part->visChar; - - if (part->next == NULL) - return; - - part = part->next; - } -} - -void addSnakePart(char board[][brdInfo.x], snakePart* head) { - snakePart* tail = head; - - while (tail->next != NULL) - tail = tail->next; - - snakePart* newTail = malloc(sizeof(snakePart)); - if (!newTail) { - mallocError("newTail", "snake.c", "addSnakePart()"); - } - - newTail->visChar = SNAKE_VIS; - newTail->dir = tail->dir; - // Order head - newTail->order = malloc(sizeof(order)); - if (!newTail->order) { - mallocError("newTail", "snake.c", "addSnakePart()"); - } - newTail->order->dir = newTail->dir; - newTail->order->delay = -1; - // First order if exists - if (tail->order->next != NULL) - copyOrders(tail->order, newTail->order); - - - switch (newTail->dir) { - case 'w': - newTail->x = tail->x; - newTail->y = tail->y + 1; - break; - case 's': - newTail->x = tail->x; - newTail->y = tail->y - 1; - break; - case 'a': - newTail->x = tail->x + 2; - newTail->y = tail->y; - break; - case 'd': - newTail->x = tail->x - 2; - newTail->y = tail->y; - break; - default: - printf("Invalid direction in func addSnakePart\n"); - exit(1); - } - - /* - Untested fix to a bug where the new part - would replace a part of the board border. - */ - if (newTail->x > plBrdInfo.xe) { - newTail->x = plBrdInfo.xs; - } else if (newTail->x < plBrdInfo.xs) { - newTail->x = plBrdInfo.xe; - } - - if (newTail->y > plBrdInfo.ye) { - newTail->y = plBrdInfo.ys; - } else if (newTail->y < plBrdInfo.ys) { - newTail->y = plBrdInfo.ye; - } - // bugfix end - - newTail->next = NULL; - - tail->next = newTail; - - board[newTail->y][newTail->x] = newTail->visChar; -} - -void pushOrder(order* head, char dir, int delay) { - order* current = head; - while (current->next != NULL) - current = current->next; - - order* newOrder = malloc(sizeof(order)); - if (!newOrder) { - mallocError("newOrder", "snake.c", "pushOrder()"); - } - newOrder->dir = dir; - newOrder->delay = delay; - newOrder->next = NULL; - - current->next = newOrder; -} - -void removeOrder(order* head) { - order* newFirstOrder = head->next->next; - free(head->next); - head->next = newFirstOrder; -} - -void addOrders(snakePart* head, char dir) { - snakePart* current = head; - int i = 1; - while (1) { - if (current->next == NULL) - break; - - current = current->next; - - pushOrder(current->order, dir, i); - - i++; - } -} - -void copyOrders(order* srcHead, order* destHead) { - if (srcHead->next == NULL) { - printf("ERROR in copyOrders: no orders to copy\n"); - exit(1); - } - - order* srcCurrent = srcHead; - order* destCurrent = destHead; - order* destPrev = destHead; - - while (srcCurrent->next != NULL) { - srcCurrent = srcCurrent->next; - destPrev = destCurrent; - destCurrent = malloc(sizeof(order)); - if (!destCurrent) { - mallocError("destCurrent", "snake.c", "copyOrders()"); - } - destPrev->next = destCurrent; - destCurrent->dir = srcCurrent->dir; - destCurrent->delay = srcCurrent->delay + 1; - destCurrent->next = NULL; - } -} - -bool checkCollision(snakePart* head, int x, int y) { - snakePart* current = head; - while (1) { - if (current->x == x && current->y == y) - return true; - - if (current->next == NULL) - break; - - current = current->next; - } - - return false; -} diff --git a/src/snake/snake.h b/src/snake/snake.h deleted file mode 100644 index 27411bc..0000000 --- a/src/snake/snake.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SNAKE_H_ -#define SNAKE_H_ - -#include "../board/board.h" - -extern boardInfo brdInfo; - -typedef struct orderNode { - char dir; - int delay; - struct orderNode* next; -} order; - -typedef struct snakeNode { - int x; - int y; - char visChar; - - char dir; - order* order; - struct snakeNode* next; -} snakePart; - -void mvSnakeParts(char board[][brdInfo.x], snakePart* head); -void addSnakePart(char board[][brdInfo.x], snakePart* head); -void pushOrder(order* head, char dir, int delay); -void removeOrder(order* head); -void addOrders(snakePart* head, char dir); -void copyOrders(order* srcHead, order* destHead); -bool checkCollision(snakePart* head, int x, int y); - -#endif // SNAKE_H_ diff --git a/src/term.c b/src/term.c new file mode 100644 index 0000000..2fbc822 --- /dev/null +++ b/src/term.c @@ -0,0 +1,2 @@ +#include + diff --git a/src/utils/utils.c b/src/utils.c similarity index 50% rename from src/utils/utils.c rename to src/utils.c index d499635..61885fa 100644 --- a/src/utils/utils.c +++ b/src/utils.c @@ -1,13 +1,11 @@ -#include +#define _POSIX_C_SOURCE 199309L + #include #include -#include +#include #include "utils.h" -extern boardInfo brdInfo; -extern playableBoardInfo plBrdInfo; - int randomInt(const int start, const int end, const unsigned int seed) { /* * Gets random int from range @@ -19,28 +17,11 @@ int randomInt(const int start, const int end, const unsigned int seed) { return result; } -int randomX(const clock_t initClock) { - int x; - const unsigned int seed = clock() - initClock; - for (int i = randomInt(0, 100, seed); ; i++) { - x = randomInt(plBrdInfo.xs, plBrdInfo.xe, i); - if (x % 2 != 0) - break; - } - - return x; -} - -int randomY(const clock_t initClock) { - const unsigned int seed = clock() - initClock; - return randomInt(plBrdInfo.ys, plBrdInfo.ye, seed); -} - -void sleep_ms(const int ms) { - usleep(ms * 1000); -} - void mallocError(const char* varName, const char* fileName, const char* functionName) { printf("Ran out of memory to allocate to %s in %s/%s\n", varName, fileName, functionName); exit(1); } + +void sleep_ms(const unsigned int ms) { + nanosleep(&(struct timespec){ .tv_sec = 0, .tv_nsec = ms * 1000000}, NULL); +} diff --git a/target/sanke b/target/sanke new file mode 100755 index 0000000..1a4da79 Binary files /dev/null and b/target/sanke differ