summaryrefslogtreecommitdiff
path: root/src/draw.c
diff options
context:
space:
mode:
authorLouie S <louie@example.com>2022-12-09 16:20:47 -0800
committerLouie Shprung <lshprung@scu.edu>2022-12-10 16:38:00 -0800
commit86c818d83e2ccf91efed4fcffd49ed3a5d44a173 (patch)
treed3c98b85cbc8b1f02138fd4e7250e6411eb9cbcd /src/draw.c
parentd0c84fc07e29ef8b4abb390831ddb71e5bd220cf (diff)
Replace crude Makefile with Autotools build system
Diffstat (limited to 'src/draw.c')
-rw-r--r--src/draw.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/draw.c b/src/draw.c
new file mode 100644
index 0000000..4926f04
--- /dev/null
+++ b/src/draw.c
@@ -0,0 +1,277 @@
+#include <errno.h>
+#include <math.h>
+#include <ncurses.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "../include/body.h"
+
+#define START_SIZE 4
+//TODO consider having speed be affected by window size
+#define SPEED 50000 //global refresh rate (for usleep())
+#define TIMEOUT 1
+
+//#define DEBUG 1
+
+void updateScore(int which, int score);
+void updateScreen(SNAKE *sp, int dir, bool *collision, int *fruit_loc, bool *fruit, int *score);
+int loadScore(void);
+void saveScore(int highscore);
+
+#ifdef DEBUG
+void count_up(void);
+#endif
+
+int main(){
+ int score = 0;
+ int highscore;
+ int input;
+ int dir;
+ bool collision;
+ int fruit_loc[2]; //index 0 is x, 1 is y
+ bool fruit_bool;
+ bool new_hs_flag;
+ int i;
+
+ //TODO consider removing score2 altogether
+
+ srand(time(NULL));
+
+ initscr();
+ cbreak();
+ keypad(stdscr, true);
+ noecho();
+ curs_set(0);
+ set_escdelay(1);
+
+ while(input != 'q'){
+ clear();
+
+ //reset variables
+ collision = false;
+ fruit_bool = false;
+ score = 0;
+ new_hs_flag = false;
+ highscore = loadScore();
+
+
+ //draw current score, and high score
+ updateScore(0, score);
+ updateScore(1, highscore);
+
+ //the snake will be initially drawn without calling to body.h
+ //functions in body.h will update the snake and check for collision
+ //updateScreen() will actually draw the snake on each update (and update the scoreboard)
+
+ //initialize and draw starting snake
+ SNAKE *player = makeSnake(START_SIZE+2, getmaxy(stdscr)/2, START_SIZE);
+ //TODO consider various choices for drawing the snake (the below sets reverse video and draws spaces)
+ attron(A_REVERSE);
+ mvaddch(getmaxy(stdscr)/2, START_SIZE+2, ':');
+ for(i = 1; START_SIZE-i > 0; i++){
+ mvaddch(getmaxy(stdscr)/2, START_SIZE+2-i, ' ');
+ }
+ attroff(A_REVERSE);
+
+ //TODO add something like "press any key to start!"
+ getch();
+
+ //turn timeout on and set the initial direction to "right"
+ timeout(TIMEOUT);
+ dir = 1;
+ while(!collision){
+ input = getch();
+
+ //update dir based on received input (check that the input is valid as well)
+ switch(input){
+ case KEY_UP:
+ if(dir % 2) dir = 0;
+ break;
+ case KEY_RIGHT:
+ if(!(dir % 2)) dir = 1;
+ break;
+ case KEY_DOWN:
+ if(dir % 2) dir = 2;
+ break;
+ case KEY_LEFT:
+ if(!(dir % 2)) dir = 3;
+ }
+
+ updateScore(0, score);
+ if(score > highscore){
+ highscore = score;
+ new_hs_flag = true;
+ }
+ updateScore(1, highscore);
+ updateScreen(player, dir, &collision, fruit_loc, &fruit_bool, &score);
+ //TODO consider changing SPEED depending on if moving horizontally or vertically
+ refresh();
+ usleep(SPEED);
+ }
+
+ deleteSnake(player);
+ if(new_hs_flag) saveScore(highscore);
+
+ //turn timeout off (wait for input again)
+ timeout(-1);
+
+ //TODO add something like "game over"
+ while(input != 'q' && input != ' ' && input != 10) input = getch();
+
+ //DEBUG
+#ifdef DEBUG
+ //count_up();
+ getch();
+#endif
+ }
+
+ endwin();
+ return 0;
+}
+
+// 0 for p1 score, 1 for highscore, 2 for p2 score
+void updateScore(int which, int score){
+ char *title;
+ int start;
+
+ switch(which){
+ case 0: //p1 score
+ title = "Score";
+ start = 2;
+ break;
+
+ case 1: //high score
+ title = "Highscore";
+ start = getmaxx(stdscr)/2 - 5;
+ break;
+
+ default:
+ exit(1);
+ }
+
+ //draw the title and the score in the right location
+ mvprintw(0, start, "%s", title);
+ mvprintw(1, start + (which % 2 ? 5 : 3) - (!score ? 0 : (int)log10(score)), "%d", score);
+
+ return;
+}
+
+void updateScreen(SNAKE *sp, int dir, bool *collision, int *fruit_loc, bool *fruit, int *score){
+ char eyes;
+
+ //switch case to decide "eyes" char
+ switch(dir){
+ case 0:
+ eyes = '"';
+ break;
+ case 2:
+ eyes = '.';
+ break;
+ default:
+ eyes = ':';
+ }
+
+ //turn off "back"
+ mvaddch(getSnakeHeady(sp), getSnakeHeadx(sp), ' ');
+ //fix previous "front" (no more eyes)
+ attron(A_REVERSE);
+ mvaddch(getSnakeTaily(sp), getSnakeTailx(sp), ' ');
+ //update the snake position
+ updateSnake(sp, dir, getmaxx(stdscr), getmaxy(stdscr), collision, fruit_loc, fruit, score);
+ //turn on front
+ mvaddch(getSnakeTaily(sp), getSnakeTailx(sp), eyes);
+ attroff(A_REVERSE);
+
+ //TODO add logic to prevent fruit from spawning inside snake
+ //draw a new fruit, if necessary (do not draw it over scoreboard)
+ if(!(*fruit)){
+ *fruit_loc = rand() % getmaxx(stdscr);
+ *(fruit_loc+1) = rand() % (getmaxy(stdscr)-2) + 2;
+ attron(A_BOLD);
+ mvaddch(*(fruit_loc+1), *fruit_loc, '@');
+ attroff(A_BOLD);
+ *fruit = true;
+ }
+
+ return;
+}
+
+int loadScore(){
+ FILE *savedata;
+ char *path = malloc(sizeof(char) * 256);
+ int hs = 0;
+ char *home = getenv("HOME");
+
+ sprintf(path, "%s/.local/share/simple-snake/save.bin", home);
+ savedata = fopen(path, "rb");
+
+ if(savedata != NULL){
+ fread(&hs, sizeof(int), 1, savedata);
+ fclose(savedata);
+ }
+
+ free(path);
+ return hs;
+}
+
+void saveScore(int highscore){
+ FILE *savedata;
+ char *path = malloc(sizeof(char) * 256);
+ char *home = getenv("HOME");
+
+ sprintf(path, "%s/.local/share/simple-snake/save.bin", home);
+ savedata = fopen(path, "wb");
+
+ //if the file does not exist, create it
+ if(savedata == NULL){
+ if(home == NULL) return;
+
+ sprintf(path, "%s/.local/", home);
+ mkdir(path, 0700);
+
+ sprintf(path, "%s/.local/share/", home);
+ mkdir(path, 0755);
+
+ sprintf(path, "%s/.local/share/simple-snake/", home);
+ mkdir(path, 0755);
+
+ sprintf(path, "%s/.local/share/simple-snake/save.bin", home);
+ savedata = fopen(path, "wb");
+ if(savedata == NULL) return;
+ }
+
+ fwrite(&highscore, sizeof(int), 1, savedata);
+ fclose(savedata);
+
+ free(path);
+ return;
+}
+
+
+//debug functions start here
+#ifdef DEBUG
+void count_up(){
+ int score = 0;
+ int score2 = 0;
+ int highscore = 0;
+
+ while(1){
+ score++;
+ score2++;
+ highscore++;
+ updateScore(0, score);
+ updateScore(1, highscore);
+ updateScore(2, score2);
+ refresh();
+ usleep(50000);
+ }
+
+ return;
+}
+#endif