From 7498a49f8848c77794c5a8e0bd521334d0f10cff Mon Sep 17 00:00:00 2001 From: Aaro Saila Date: Sun, 7 Sep 2025 23:52:02 +0300 Subject: [PATCH] started rework --- .gitignore | 1 + compile.sh | 23 +++- compile_release.sh | 3 - src/board.c | 97 +++++++++++++++ src/board/board.c | 30 ----- src/board/board.h | 21 ---- src/headers/board.h | 30 +++++ src/headers/snake.h | 29 +++++ src/{utils => headers}/utils.h | 10 +- src/main.c | 209 +++++++------------------------ src/snake.c | 83 +++++++++++++ src/snake/snake.c | 218 --------------------------------- src/snake/snake.h | 32 ----- src/term.c | 2 + src/{utils => }/utils.c | 33 ++--- target/sanke | Bin 0 -> 30696 bytes 16 files changed, 318 insertions(+), 503 deletions(-) delete mode 100755 compile_release.sh create mode 100644 src/board.c delete mode 100644 src/board/board.c delete mode 100644 src/board/board.h create mode 100644 src/headers/board.h create mode 100644 src/headers/snake.h rename src/{utils => headers}/utils.h (54%) create mode 100644 src/snake.c delete mode 100644 src/snake/snake.c delete mode 100644 src/snake/snake.h create mode 100644 src/term.c rename src/{utils => }/utils.c (50%) create mode 100755 target/sanke 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 0000000000000000000000000000000000000000..1a4da79562d09bdda4b09350205143125c2c2df5 GIT binary patch literal 30696 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 literal 0 HcmV?d00001