summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rwxr-xr-xa.outbin0 -> 19464 bytes
-rw-r--r--conio.h14
-rwxr-xr-xsnakebin0 -> 19464 bytes
-rw-r--r--snake.c182
-rw-r--r--snake.h12
-rw-r--r--vector.c48
-rw-r--r--vector.h21
8 files changed, 288 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5ce9ec3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+CC=gcc
+CFLAGS=-I. -pthread
+
+generate:
+ $(CC) -o snake snake.c vector.c $(CFLAGS)
+
+install:
+ cp snake /usr/local/bin/
+
+clean:
+ rm snake
diff --git a/a.out b/a.out
new file mode 100755
index 0000000..24eb6ac
--- /dev/null
+++ b/a.out
Binary files differ
diff --git a/conio.h b/conio.h
new file mode 100644
index 0000000..fa866f2
--- /dev/null
+++ b/conio.h
@@ -0,0 +1,14 @@
+#include <termios.h>
+#include <unistd.h>
+#include <stdio.h>
+int getch(void) {
+ struct termios oldattr, newattr;
+ int ch;
+ tcgetattr(STDIN_FILENO, &oldattr);
+ newattr = oldattr;
+ newattr.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
+ ch = getchar();
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
+ return ch;
+}
diff --git a/snake b/snake
new file mode 100755
index 0000000..24eb6ac
--- /dev/null
+++ b/snake
Binary files differ
diff --git a/snake.c b/snake.c
new file mode 100644
index 0000000..44d4b67
--- /dev/null
+++ b/snake.c
@@ -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);
+ }
+}
diff --git a/snake.h b/snake.h
new file mode 100644
index 0000000..9675a17
--- /dev/null
+++ b/snake.h
@@ -0,0 +1,12 @@
+#include "vector.h"
+#ifndef SNAKE
+#define SNAKE
+typedef struct ThreadArg {
+ int* cancellationToken;
+ void* returnV;
+} threadArg_t;
+void* get_dir_loop(void* threadArg);
+vector_t parse_dir(char cDir);
+vectorp_t move_snake(vector_t dir, int lengthen);
+void draw_board();
+#endif
diff --git a/vector.c b/vector.c
new file mode 100644
index 0000000..6ab3bf2
--- /dev/null
+++ b/vector.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include "vector.h"
+vector_t init_vector(int mx, int my) {
+ vector_t vector;
+ vector.mx = mx;
+ vector.my = my;
+ return vector;
+}
+vectorp_t init_vectorp(vector_t* vectors, int length) {
+ vectorp_t vectorP;
+ vectorP.vectors = vectors;
+ vectorP.length = length;
+ return vectorP;
+}
+vectorp_t remove_vector(vectorp_t vectorp, int index) {
+ vector_t* vectors = malloc((vectorp.length - 1) * sizeof(vector_t));
+ for(int i = 0; i < vectorp.length - 1; i++) {
+ int correctedIndex = i > index ? i - 1 : i;
+ if(i != index) {
+ vectors[correctedIndex] = vectorp.vectors[i];
+ }
+ }
+ return init_vectorp(vectors, vectorp.length - 1);
+}
+vectorp_t remove_vectors(vectorp_t vectorp, int* indexes, int indexCount) {
+ vector_t* vectors = malloc((vectorp.length - indexCount) * sizeof(vector_t));
+ int correctedIndex = 0;
+ for(int i = 0; i < vectorp.length - indexCount; i++) {
+ int toRemove = 0;
+ for(int j = 0; j < indexCount; j++) {
+ if(i == indexes[j]) {
+ toRemove = 1;
+ break;
+ }
+ }
+ if(!toRemove) {
+ vectors[correctedIndex] = vectorp.vectors[i];
+ correctedIndex++;
+ }
+ }
+ return init_vectorp(vectors, vectorp.length - indexCount);
+}
+vectorpp_t init_vectorpp(vectorp_t* vectorps, int length) {
+ vectorpp_t vectorPP;
+ vectorPP.vectorps = vectorps;
+ vectorPP.length = length;
+ return vectorPP;
+}
diff --git a/vector.h b/vector.h
new file mode 100644
index 0000000..ea2ddcd
--- /dev/null
+++ b/vector.h
@@ -0,0 +1,21 @@
+#ifndef VECTOR
+#define VECTOR
+typedef struct Vector {
+ int mx;
+ int my;
+} vector_t;
+vector_t init_vector(int mx, int my);
+typedef struct VectorP {
+ vector_t* vectors;
+ int length;
+} vectorp_t;
+vectorp_t init_vectorp(vector_t* vectors, int length);
+//removes a vector from vectorp
+vectorp_t remove_vector(vectorp_t vectorp, int index);
+vectorp_t remove_vectors(vectorp_t vectorp, int* indexes, int indexCount);
+typedef struct VectorPP {
+ vectorp_t* vectorps;
+ int length;
+} vectorpp_t;
+vectorpp_t init_vectorpp(vectorp_t* vectorps, int length);
+#endif