From 2efc3db04551dd122c9f6ebf251f1a352f1c1925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Wed, 3 Dec 2014 16:14:30 +0100 Subject: [PATCH] unified codebase --- Makefile | 8 +- src/2048.c | 271 +++++++++++++++++++++++++++++++---- src/2048.h | 65 --------- src/2048_no_curses.c | 326 ------------------------------------------- src/highscore_file.c | 29 ---- 5 files changed, 244 insertions(+), 455 deletions(-) delete mode 100644 src/2048.h delete mode 100644 src/2048_no_curses.c delete mode 100644 src/highscore_file.c diff --git a/Makefile b/Makefile index dc28d95..4a0378b 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,11 @@ LIBS = -lcurses all: 2048 -2048: src/2048.c src/2048.h src/highscore_file.c - $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) src/2048.c src/highscore_file.c -o 2048 +2048: src/2048.c + $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) src/2048.c -o 2048 -2048nc: src/2048_no_curses.c src/2048.h src/highscore_file.c - $(CC) $(CFLAGS) $(LDFLAGS) src/2048_no_curses.c src/highscore_file.c -o 2048nc +2048nc: src/2048.c + $(CC) -DNO_CURSES=1 $(CFLAGS) $(LDFLAGS) src/2048.c -o 2048nc clean: rm -f 2048 2048nc diff --git a/src/2048.c b/src/2048.c index 558b432..b2c8713 100644 --- a/src/2048.c +++ b/src/2048.c @@ -1,20 +1,69 @@ /* - * 2048.c - Main version that should be worked on. + * 2048.c - The game 2048 for your Linux terminal. + * + * Copyright (c) 2014 Tiehuis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. * * Things to do: * - Finish cleaning up code. * - Ask user if they would like to play again instead of exiting immediately. * - Add an actual goal (what happens when we reach 2048?). * - Keep track list of past scores, and store in a better fashion independent - * of cwd. Also, store in not in plaintext. + * of cwd. Also, store not in plaintext. * */ -#include /* for malloc */ -#include /* for time */ -#include /* for getopts */ -#include -#include "2048.h" +#include /* for malloc */ +#include /* for printf, FILE */ +#include /* for strlen, strrchr */ +#include /* for mkdir */ +#include /* for time */ +#include /* for getopts */ +#ifndef NO_CURSES + #include /* for ncurses terminal */ +#else /* ifndef NO_CURSES */ + #include /* for plain terminal */ +#endif /* ifndef NO_CURSES */ + + +/* Constants */ +#define DATADIR_NAME "2048" +#define HIGHSCORE_FILE_NAME "highscore" +#define DEFAULT_GRID_SIZE 4 +#define HISCORE_FILE get_highscore_file() +#define USAGE_STR\ + "Usage:\n"\ + " ./2048 [options]\n"\ + "\n"\ + "Controls:\n"\ + " hjkl, wasd Movement\n"\ + " q Quit\n"\ + "\n"\ + "Options:\n"\ + " -s Set the grid border length\n"\ + " -b Set the block spawn rate\n"\ + " -c Enables color support (ncurses version only)\n"\ + " -C Disables color support (ncurses version only)\n" + + +/* Globals */ int **grid; /* grid pointer */ int grid_size; /* grid size */ int score; /* score */ @@ -22,6 +71,70 @@ int score_last; /* Score for last move */ int score_high; /* Hiscore */ int printwidth; /* maximum length of any value in grid, for printing */ + +/* Typedefs */ +typedef enum { + DIR_UP, + DIR_RIGHT, + DIR_DOWN, + DIR_LEFT +} dir_t; + + +/* Macros */ +/* Repeat an expression y, x times */ +#define ITER(x, expr)\ + do {\ + int i;\ + for (i = 0; i < (x); i++){ expr;}\ + } while (0) + +/* Allocates a square pointer of array of arrays onto heap */ +#define CALLOC2D(ptr, sz)\ + do {\ + int i;\ + ptr = calloc((sz), sizeof(*ptr));\ + for (i = 0; i < (sz); i++)\ + ptr[i] = calloc((sz), sizeof(*ptr));\ + } while (0) + +/* Frees a square pointer of arrays to arrays */ +#define FREE2D(ptr, sz)\ + do {\ + int i;\ + for (i = 0; i < (sz); i++)\ + free(ptr[i]);\ + free(ptr);\ + } while (0) + +/* What occurs during a 'turn' of execution */ +#define TURN(x) (gravitate(x) + merge(x) + gravitate(x)) + + +/* Functions */ +const char* get_highscore_file() { + static char buffer[4096]; + if (getenv("XDG_DATA_HOME") != NULL) { + snprintf(buffer, sizeof(buffer), "%s/%s/%s", getenv("XDG_DATA_HOME"), DATADIR_NAME, HIGHSCORE_FILE_NAME); + } else if (getenv("HOME") != NULL) { + snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", getenv("HOME"), DATADIR_NAME, HIGHSCORE_FILE_NAME); + } else { + return HIGHSCORE_FILE_NAME; + } + + // create hierarrchy of directories up to highscore file location + char* sep = strrchr(buffer, '/'); + while (sep != NULL) { + *sep = '\0'; + if (strlen(buffer) != 0) + mkdir(buffer, 0777); + char* tmpsep = sep; + sep = strrchr(buffer, '/'); + *tmpsep = '/'; + } + return buffer; +} + /* Merges adjacent squares of the same value together in a certain direction */ int merge(dir_t d) { @@ -88,7 +201,7 @@ int merge(dir_t d) return moved; } - + /* move all values in the grid to the edge given by the direction pressed */ /* would be nice to generalize this code a little so didn't need four loops */ /* if animations are wanted, then need to alter this so it moves each square one at a time */ @@ -157,10 +270,11 @@ int gravitate(dir_t d) } /* Return the current highscore */ -int get_score_high() { +int get_score_high() +{ int s = 0; FILE *fd = fopen(HISCORE_FILE, "r"); - if (fd == NULL) + if (fd == NULL) fd = fopen(HISCORE_FILE, "w+"); if (fscanf(fd, "%d", &s) == 1) {}; @@ -169,7 +283,8 @@ int get_score_high() { } /* saves hiscore, but only if playing on standard size grid */ -void save_score_high() { +void save_score_high() +{ if (score > score_high && grid_size == 4) { score_high = score; FILE *fd = fopen(HISCORE_FILE, "w+"); @@ -184,8 +299,8 @@ int moves_available() int i, j; for (i = 0; i < grid_size; i++) for (j = 0; j < grid_size; j++) - if (!grid[i][j] - || ((i + 1 < grid_size) && (grid[i][j] == grid[i + 1][j])) + if (!grid[i][j] + || ((i + 1 < grid_size) && (grid[i][j] == grid[i + 1][j])) || ((j + 1 < grid_size) && (grid[i][j] == grid[i][j + 1]))) return 1; return 0; @@ -209,6 +324,8 @@ int flog2(unsigned int n) return k; } +#ifndef NO_CURSES + /* draws the grid and fills it with the current values */ /* colors just rotate around, works for now, can be confusing when you have some fairly high values on the board */ void draw_grid(WINDOW *gamewin) @@ -218,7 +335,7 @@ void draw_grid(WINDOW *gamewin) mvwprintw(gamewin, 0, 0, scr, score, score_last); mvwprintw(gamewin, 1, 0, "HISCR: %d\n", score_high); - ITER(grid_size*(printwidth + 2) + 1, waddch(gamewin, '-')); + ITER(grid_size*(printwidth + 2) + 1, waddch(gamewin, '-')); int i, j, xps = 0, yps = 3; for (i = 0; i < grid_size; i++, xps = 0, yps++) { mvwprintw(gamewin, yps, xps++, "|"); @@ -236,19 +353,52 @@ void draw_grid(WINDOW *gamewin) xps += (printwidth + 2); } } - ITER(grid_size*(printwidth + 2) + 1, waddch(gamewin, '-')); + ITER(grid_size*(printwidth + 2) + 1, waddch(gamewin, '-')); wrefresh(gamewin); } +#else /* ifndef NO_CURSES */ + +/* draws the grid and fills it with the current values */ +void draw_grid() +{ + printf("HISCORE: %d |", score_high); + printf("| SCORE: %d ", score); + if (score_last) printf("(+%d)", score_last); + printf("\n"); + + // alter this grid_size + 1 to match abitrary grid size + ITER(grid_size, printf("------")); + printf("-\n"); + int i, j; + for (i = 0; i < grid_size; i++) { + printf("|"); + for (j = 0; j < grid_size; j++) { + if (grid[i][j]) + printf("%*d |", 4, grid[i][j]); + else + printf(" |"); + } + printf("\n"); + } + ITER(grid_size, printf("------")); + printf("-\n\n"); +} + +/* store the terminal settings and call this function on exit to restore */ +struct termios sattr; +void reset_term() +{ + tcsetattr(STDIN_FILENO, TCSANOW, &sattr); +} + +#endif /* ifndef NO_CURSES */ + + /* entry point for the program */ /* parses options and stores the main game loop */ int main(int argc, char **argv) { - /* init ncurses environment */ - initscr(); - cbreak(); - noecho(); - curs_set(FALSE); /* init variables */ score = 0; @@ -257,13 +407,22 @@ int main(int argc, char **argv) grid_size = DEFAULT_GRID_SIZE; printwidth = DEFAULT_GRID_SIZE; - int n_blocks = 1; - + int n_blocks = 1; + +#ifndef NO_CURSES + /* init ncurses environment */ + initscr(); + cbreak(); + noecho(); + curs_set(FALSE); + int enable_color = has_colors(); +#endif /* ifndef NO_CURSES */ + /* parse options */ int c; - int enable_color = has_colors(); while ((c = getopt(argc, argv, "rcChs:b:")) != -1) { switch (c) { +#ifndef NO_CURSES /* Color support */ case 'c': enable_color = 1; @@ -271,6 +430,7 @@ int main(int argc, char **argv) case 'C': enable_color = 0; break; +#endif /* ifndef NO_CURSES */ // different board sizes case 's':; int optint = strtol(optarg, NULL, 10); @@ -282,7 +442,9 @@ int main(int argc, char **argv) break; // reset hiscores case 'r': +#ifndef NO_CURSES endwin(); +#endif /* ifndef NO_CURSES */ printf("Are you sure you want to reset your highscores? (Y)es or (N)o\n"); int response; if ((response = getchar()) == 'y' || response == 'Y') { @@ -292,12 +454,21 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); // help menu case 'h': +#ifndef NO_CURSES endwin(); +#endif /* ifndef NO_CURSES */ printf(USAGE_STR); exit(EXIT_SUCCESS); } } + /* Allocate memory once we actually know amount */ + CALLOC2D(grid, grid_size); + +#ifndef NO_CURSES + int width = grid_size * (printwidth + 2) + 1; + int height = grid_size * (printwidth + 2) + 3; + if (enable_color) { if (!has_colors()) { fprintf(stderr, "Terminal does not support color\n"); @@ -313,64 +484,98 @@ int main(int argc, char **argv) } } - /* Allocate memory once we actually know amount */ - CALLOC2D(grid, grid_size); - - int width = grid_size * (printwidth + 2) + 1; - int height = grid_size * (printwidth + 2) + 3; - // might center in middle of screen WINDOW *gamewin = newwin(height, width, 1, 1); keypad(gamewin, TRUE); +#else /* ifndef NO_CURSES */ + + /* store term settings so we can restore on exit */ + tcgetattr(STDIN_FILENO, &sattr); + atexit(reset_term); + + /* alters terminal stdin to not echo and doesn't need \n before reading getchar */ + struct termios tattr; + tcgetattr(STDIN_FILENO, &tattr); + tattr.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDOUT_FILENO, TCSANOW, &tattr); +#endif /* ifndef NO_CURSES */ /* random seed */ srand((unsigned int)time(NULL)); ITER(2, rand_block()); +#ifndef NO_CURSES draw_grid(gamewin); +#else /* ifndef NO_CURSES */ + draw_grid(); +#endif /* ifndef NO_CURSES */ int key, moved; while (1) { /* will goto this if we didn't get a valid keypress */ -retry:; + retry:; + moved = 0; score_last = 0; + +#ifndef NO_CURSES key = wgetch(gamewin); +#else /* ifndef NO_CURSES */ + key = getchar(); +#endif /* ifndef NO_CURSES */ /* should check if anything changed during merge and if not retry */ switch (key) { + case 'h': case 'a': +#ifndef NO_CURSES case KEY_LEFT: +#endif /* ifndef NO_CURSES */ moved = TURN(DIR_LEFT); break; + case 'l': case 'd': +#ifndef NO_CURSES case KEY_RIGHT: +#endif /* ifndef NO_CURSES */ moved = TURN(DIR_RIGHT); break; + case 'j': case 's': +#ifndef NO_CURSES case KEY_DOWN: +#endif /* ifndef NO_CURSES */ moved = TURN(DIR_DOWN); break; + case 'k': case 'w': +#ifndef NO_CURSES case KEY_UP: +#endif /* ifndef NO_CURSES */ moved = TURN(DIR_UP); break; + case 'q': FREE2D(grid, grid_size); +#ifndef NO_CURSES erase(); refresh(); endwin(); +#endif /* ifndef NO_CURSES */ save_score_high(); exit(EXIT_SUCCESS); + default: goto retry; } - + if (!moves_available()) { +#ifndef NO_CURSES endwin(); +#endif /* ifndef NO_CURSES */ printf("\n" "YOU LOSE! - Your score was %d\n", score); save_score_high(); @@ -379,7 +584,11 @@ retry:; if (moved) { ITER(n_blocks, rand_block()); +#ifndef NO_CURSES draw_grid(gamewin); +#else /* ifndef NO_CURSES */ + draw_grid(); +#endif /* ifndef NO_CURSES */ } } diff --git a/src/2048.h b/src/2048.h deleted file mode 100644 index 49937c4..0000000 --- a/src/2048.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _2048_H_ -#define _2048_H_ - -#include -#include -#include - -typedef enum { - DIR_UP, - DIR_RIGHT, - DIR_DOWN, - DIR_LEFT -} dir_t; - -#define DATADIR_NAME "2048" -#define HIGHSCORE_FILE_NAME "highscore" - -const char* get_highscore_file(); - -// Repeat an expression y, x times */ -#define ITER(x, expr)\ - do {\ - int i;\ - for (i = 0; i < (x); i++){ expr;}\ - } while (0) - -/* Allocates a square pointer of array of arrays onto heap */ -#define CALLOC2D(ptr, sz)\ - do {\ - int i;\ - ptr = calloc((sz), sizeof(*ptr));\ - for (i = 0; i < (sz); i++)\ - ptr[i] = calloc((sz), sizeof(*ptr));\ - } while (0) - -/* Frees a square pointer of arrays to arrays */ -#define FREE2D(ptr, sz)\ - do {\ - int i;\ - for (i = 0; i < (sz); i++)\ - free(ptr[i]);\ - free(ptr);\ - } while (0) - -/* What occurs during a 'turn' of execution */ -#define TURN(x) (gravitate(x) + merge(x) + gravitate(x)) - -/* Constants */ -#define DEFAULT_GRID_SIZE 4 -#define HISCORE_FILE get_highscore_file() -#define USAGE_STR\ - "Usage:\n"\ - " ./2048 [options]\n"\ - "\n"\ - "Controls:\n"\ - " hjkl, wasd Movement\n"\ - " q Quit\n"\ - "\n"\ - "Options:\n"\ - " -s Set the grid border length\n"\ - " -b Set the block spawn rate\n"\ - " -c Enables color support (ncurses version only)\n"\ - " -C Disables color support (ncurses version only)\n" - -#endif diff --git a/src/2048_no_curses.c b/src/2048_no_curses.c deleted file mode 100644 index ce281f8..0000000 --- a/src/2048_no_curses.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 2048_no_curses.c - Non-curses version that can be updated at a later time - **/ - -#include /* for printf */ -#include /* for malloc */ -#include /* */ -#include /* for time */ -#include /* for getopts */ -#include "2048.h" - -int **g; /* grid pointer */ -int SZ; /* grid size */ -int s; /* Current score */ -int sl; /* Score for last turn */ -int hs; /* Highscore */ - -/* Merges adjacent squares of the same value together in a certain direction */ -int merge(int d) -{ - int moved = 0; - if (d == DIR_LEFT) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = 0; j < SZ; j++) { - if (j + 1 < SZ && g[i][j] && g[i][j] == g[i][j + 1]) { - g[i][j] <<= 1; - sl += g[i][j]; - s += g[i][j]; - g[i][j++ + 1] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_UP) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = 0; j < SZ; j++) { - if (j + 1 < SZ && g[j][i] && g[j][i] == g[j + 1][i]) { - g[j][i] <<= 1; - sl += g[j][i]; - s += g[j][i]; - g[j++ + 1][i] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_RIGHT) { - int i, j; - for (i = SZ - 1; i >= 0; i--) { - for (j = SZ - 1; j >= 0; j--) { - if (j > 0 && g[i][j] && g[i][j] == g[i][j - 1]) { - g[i][j] <<= 1; - sl += g[i][j]; - s += g[i][j]; - g[i][j-- - 1] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_DOWN) { - int i, j; - for (i = SZ - 1; i >= 0; i--) { - for (j = SZ - 1; j >= 0; j--) { - if (j > 0 && g[j][i] && g[j][i] == g[j - 1][i]) { - g[j][i] <<= 1; - sl += g[j][i]; - s += g[j][i]; - g[j-- - 1][i] = 0; - moved = 1; - } - } - } - } - return moved; -} - - -/* move all values in the grid to the edge given by the direction pressed */ -/* would be nice to generalize this code a little so didn't need four loops */ -int gravitate(int d) -{ - int moved = 0; - if (d == DIR_LEFT) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = 0; j < SZ - 1; j++) { - if (g[i][j]) continue; - int st = 1; - while (j + st < SZ && !g[i][j + st]) st++; - if (j + st < SZ) { - g[i][j] = g[i][j + st]; - g[i][j + st] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_UP) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = 0; j < SZ - 1; j++) { - if (g[j][i]) continue; - int st = 1; - while (j + st < SZ && !g[j + st][i]) st++; - if (j + st < SZ) { - g[j][i] = g[j + st][i]; - g[j + st][i] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_RIGHT) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = SZ - 1; j > 0; j--) { - if (g[i][j]) continue; - int st = 1; - while (j - st >= 0 && !g[i][j - st]) st++; - if (j - st >= 0) { - g[i][j] = g[i][j - st]; - g[i][j - st] = 0; - moved = 1; - } - } - } - } - else if (d == DIR_DOWN) { - int i, j; - for (i = 0; i < SZ; i++) { - for (j = SZ - 1; j > 0; j--) { - if (g[j][i]) continue; - int st = 1; - while (j - st >= 0 && !g[j - st][i]) st++; - if (j - st >= 0) { - g[j][i] = g[j - st][i]; - g[j - st][i] = 0; - moved = 1; - } - } - } - } - return moved; -} - -/* loads hiscore */ -void load_score() { - FILE *fd = fopen(HISCORE_FILE, "r"); - if (fd == NULL) fd = fopen(HISCORE_FILE, "w+"); - if (fscanf(fd, "%d", &hs) == EOF) hs = 0; - fclose(fd); -} - -/* saves hiscore, but only if playing on standard size grid */ -void save_score() { - if (s > hs && SZ == 4) { - hs = s; - FILE *fd = fopen(HISCORE_FILE, "w+"); - fprintf(fd, "%d", hs); - fclose(fd); - } -} - -/* returns if there are any possible moves */ -int moves_available() -{ - int i, j; - for (i = 0; i < SZ; i++) - for (j = 0; j < SZ; j++) - if (!g[i][j] || ((i + 1 < SZ) && (g[i][j] == g[i + 1][j])) || ((j + 1 < SZ) && (g[i][j] == g[i][j + 1]))) - return 1; - return 0; -} - -/* places a random block onto the grid - either a 4, or a 2 with a ratio of 1:3 respectively */ -/* do this in a smarter fashion */ -void rand_block() -{ - int x_p, y_p; - while (g[x_p = rand() % SZ][y_p = rand() % SZ]); - g[x_p][y_p] = (rand() & 3) ? 2 : 4; -} - -/* draws the grid and fills it with the current values */ -void draw_grid() -{ - printf("HISCORE: %d |", hs); - printf("| SCORE: %d ", s); - if (sl) printf("(+%d)", sl); - printf("\n"); - - // alter this SZ + 1 to match abitrary grid size - ITER(SZ, printf("------")); - printf("-\n"); - int i, j; - for (i = 0; i < SZ; i++) { - printf("|"); - for (j = 0; j < SZ; j++) { - if (g[i][j]) - printf("%*d |", 4, g[i][j]); - else - printf(" |"); - } - printf("\n"); - } - ITER(SZ, printf("------")); - printf("-\n\n"); -} - -/* store the terminal settings and call this function on exit to restore */ -struct termios sattr; -void reset_term() -{ - tcsetattr(STDIN_FILENO, TCSANOW, &sattr); -} - -/* entry point for the program */ -/* parses options and stores the main game loop */ -int main(int argc, char **argv) -{ - - /* init variables */ - hs = 0; - s = 0; - sl = 0; - SZ = 4; - CALLOC2D(g, SZ); - - load_score(); - int n_blocks = 1; - - /* parse options */ - int c; - while ((c = getopt(argc, argv, "rhs:b:")) != -1) { - switch (c) { - // different board sizes - case 's': - FREE2D(g, SZ); - int optint = atoi(optarg); - SZ = optint > 4 ? optint : 4; - CALLOC2D(g, SZ); - break; - // different block spawn rate - case 'b': - n_blocks = atoi(optarg); - break; - // reset hiscores - case 'r': - printf("Are you sure you want to reset your highscores? (Y)es or (N)o\n"); - int response; - if ((response = getchar()) == 'y' || response == 'Y') { - FILE *fd = fopen(HISCORE_FILE, "w+"); - fclose(fd); - } - exit(EXIT_SUCCESS); - case 'h': - printf(USAGE_STR); - exit(EXIT_SUCCESS); - } - } - - /* random seed */ - srand((unsigned int)time(NULL)); - ITER(2, rand_block()); - draw_grid(); - - /* store term settings so we can restore on exit */ - tcgetattr(STDIN_FILENO, &sattr); - atexit(reset_term); - - /* alters terminal stdin to not echo and doesn't need \n before reading getchar */ - struct termios tattr; - tcgetattr(STDIN_FILENO, &tattr); - tattr.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDOUT_FILENO, TCSANOW, &tattr); - - int key, moved; - while (1) { - /* will goto this if we didn't get a valid keypress */ - retry:; - moved = 0; - key = getchar(); - sl = 0; - - /* should check if anything changed during merge and if not retry */ - switch (key) { - case 'h': - case 'a': - moved = TURN(DIR_LEFT); - break; - case 'l': - case 'd': - moved = TURN(DIR_RIGHT); - break; - case 'j': - case 's': - moved = TURN(DIR_DOWN); - break; - case 'k': - case 'w': - moved = TURN(DIR_UP); - break; - case 'q': - save_score(); - exit(EXIT_SUCCESS); - default: - goto retry; - } - - if (!moves_available()) { - printf("\n" - "YOU LOSE! - Your score was %d\n", s); - save_score(); - exit(EXIT_SUCCESS); - } - - if (moved) { - ITER(n_blocks, rand_block()); - draw_grid(); - } - } -} diff --git a/src/highscore_file.c b/src/highscore_file.c deleted file mode 100644 index baeab33..0000000 --- a/src/highscore_file.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "2048.h" - -#include -#include -#include -#include - -const char* get_highscore_file() { - static char buffer[4096]; - if (getenv("XDG_DATA_HOME") != NULL) { - snprintf(buffer, sizeof(buffer), "%s/%s/%s", getenv("XDG_DATA_HOME"), DATADIR_NAME, HIGHSCORE_FILE_NAME); - } else if (getenv("HOME") != NULL) { - snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", getenv("HOME"), DATADIR_NAME, HIGHSCORE_FILE_NAME); - } else { - return HIGHSCORE_FILE_NAME; - } - - // create hierarrchy of directories up to highscore file location - char* sep = strrchr(buffer, '/'); - while (sep != NULL) { - *sep = '\0'; - if (strlen(buffer) != 0) - mkdir(buffer, 0777); - char* tmpsep = sep; - sep = strrchr(buffer, '/'); - *tmpsep = '/'; - } - return buffer; -}