diff options
Diffstat (limited to 'snake.c')
| -rw-r--r-- | snake.c | 182 |
1 files changed, 182 insertions, 0 deletions
@@ -0,0 +1,182 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <pthread.h> +#include "vector.h" +#include "snake.h" +#include "conio.h" + +const int boardSize = 12; +const int updateInterval = 300000000L; +vectorp_t snakePositions; +vector_t foodPos; +vector_t lastMoveDir; + +int main(int argc, char **argv) { + //init values + snakePositions = init_vectorp(malloc(5 * sizeof(vector_t)), 5); + snakePositions.vectors[0] = init_vector(5, 5); + snakePositions.vectors[1] = init_vector(5, 4); + snakePositions.vectors[2] = init_vector(5, 3); + snakePositions.vectors[3] = init_vector(4, 3); + snakePositions.vectors[4] = init_vector(3, 3); + foodPos = init_vector(7, 9); + lastMoveDir = init_vector(0, 1); + srand(time(NULL)); + //clear the screen so as to prevent artifacting + printf("\033[2J"); + //prepare the pointers which will be used to communicate with the input getting thread + volatile int* lastInput = calloc(1, sizeof(int)); + int* cancellationToken = calloc(1, sizeof(int)); + //and the wrapper struct + threadArg_t threadArg; + threadArg.returnV = (void*)lastInput; + threadArg.cancellationToken = cancellationToken; + //create listener thread + pthread_t listenerID; + pthread_create(&listenerID, NULL, get_dir_loop, &threadArg); + //main game logic loop + while(1) { + //first, draw the current state of the board + draw_board(); + //handle player input + //wait for the specified interval + struct timespec time; + time.tv_sec = 0; + time.tv_nsec = updateInterval; + nanosleep(&time, NULL); + //read the most recent value emitted by the listener + vector_t dir = parse_dir(*(char*)lastInput); + //if the player inputted a valid direction, use it. otherwise, use his last valid input + if((dir.mx != 0 || dir.my != 0) && !(dir.mx == 1 && lastMoveDir.mx == -1) && !(dir.mx == -1 && lastMoveDir.mx == 1) && !(dir.my == 1 && lastMoveDir.my == -1) && !(dir.my == -1 && lastMoveDir.my == 1)) { + lastMoveDir = dir; + } + else { + } + //check if snake landed on the food + int ateFood = 0; + if((snakePositions.vectors[0].mx + lastMoveDir.mx == foodPos.mx) && (snakePositions.vectors[0].my + lastMoveDir.my == foodPos.my)) { + ateFood = 1; + //move the food + while(1) { + foodPos = init_vector(1 + (rand() % (boardSize - 2)), 1 + (rand() % (boardSize - 2))); + //if food overlaps snake, try again + int overlap = 0; + for(int i = 0; i < snakePositions.length; i++) { + if((snakePositions.vectors[i].mx == foodPos.mx) && (snakePositions.vectors[i].my == foodPos.my)) { + overlap = 1; + } + } + if(!overlap) { + break; + } + } + } + //move the snake + vectorp_t newSnakePositions = move_snake(lastMoveDir, ateFood); + free(snakePositions.vectors); + snakePositions = newSnakePositions; + //check if snake landed on self + int died = 0; + for(int i = 1; i < snakePositions.length; i++) { + if(snakePositions.vectors[0].mx == snakePositions.vectors[i].mx && snakePositions.vectors[0].my == snakePositions.vectors[i].my) { + //game over + died = 1; + } + } + if(died) { + break; + } + } + //clear the last getch call from the listener + *cancellationToken = 1; + printf("\nYou died. Press any key to exit\n"); + pthread_join(listenerID, NULL); + return 0; +} +void* get_dir_loop(void* threadArg) { + while(!*(int*)((threadArg_t*)threadArg)->cancellationToken) { + *(char*)((threadArg_t*)threadArg)->returnV = getch(); + } + return NULL; +} +//parses WASD or HJKL, returns the necessary deltas to move within a 2d array +vector_t parse_dir(char cDir) { + if(cDir == 'w' || cDir == 'k') { + return init_vector(0, -1); + } + else if(cDir == 'd' || cDir == 'l') { + return init_vector(1, 0); + } + else if(cDir == 's' || cDir == 'j') { + return init_vector(0, 1); + } + else if(cDir == 'a' || cDir == 'h') { + return init_vector(-1, 0); + } + else { + return init_vector(0, 0); + } +} +vectorp_t move_snake(vector_t dir, int lengthen) { + int newLength = snakePositions.length + (lengthen ? 1 : 0); + vector_t* newSnakePositions = malloc((newLength * sizeof(vector_t))); + //wrap around edges + int nhx = snakePositions.vectors[0].mx + dir.mx; + nhx = nhx < 0 ? boardSize - 1 : nhx >= boardSize ? 0 : nhx; + int nhy = snakePositions.vectors[0].my + dir.my; + nhy = nhy < 0 ? boardSize - 1 : nhy >= boardSize ? 0 : nhy; + newSnakePositions[0] = init_vector(nhx, nhy); + for(int i = 1; i < newLength; i++) { + newSnakePositions[i] = snakePositions.vectors[i - 1]; + } + return init_vectorp(newSnakePositions, newLength); +} +void draw_board() { + //move the cursor to the top left corner of the screen + printf("\033[0;0H"); + //iterate through and write the board + for(int r = 0; r < boardSize; r++) { + char* line = calloc(boardSize * 2, sizeof(char)); + for(int c = 0; c < boardSize; c++) { + //determine the contents of the board position + int type = 0; + for(int i = 0; i < snakePositions.length; i++) { + if(snakePositions.vectors[i].mx == c && snakePositions.vectors[i].my == r) { + type = i ? 2 : 1; + break; + } + else { + type = 0; + } + } + if(foodPos.mx == c && foodPos.my == r) { + type = 3; + } + //append the appropriate value + if(type == 0) { + //empty square + line[c * 2] = '`'; + line[(c * 2) + 1] = ' '; + } + else if(type == 1) { + //snake head + line[c * 2] = '@'; + line[(c * 2) + 1] = ' '; + } + else if(type == 2) { + //snake body + line[c * 2] = '*'; + line[(c * 2) + 1] = ' '; + } + else if(type == 3) { + //snake body + line[c * 2] = 'F'; + line[(c * 2) + 1] = ' '; + } + } + printf(line); + printf("\n"); + free(line); + } +} |
