Cleaned up source, directories, and added header file to improve general readability
This commit is contained in:
parent
1bf0c51864
commit
8843fcb658
413
2048_curses.c
413
2048_curses.c
|
@ -1,413 +0,0 @@
|
||||||
#include <curses.h>
|
|
||||||
#include <stdlib.h> /* for malloc */
|
|
||||||
#include <time.h> /* for time */
|
|
||||||
#include <unistd.h> /* for getopts */
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
/* should be executed each turn */
|
|
||||||
#define TURN(x)\
|
|
||||||
gravitate(x) +\
|
|
||||||
merge(x) +\
|
|
||||||
gravitate(x)
|
|
||||||
|
|
||||||
/* maximum length of any value in grid, for printing */
|
|
||||||
int MAXVAL;
|
|
||||||
|
|
||||||
/* direction enumeration */
|
|
||||||
enum {DR, DU, DL, DD};
|
|
||||||
|
|
||||||
/* grid pointer */
|
|
||||||
int **g;
|
|
||||||
|
|
||||||
/* grid size */
|
|
||||||
int SZ;
|
|
||||||
|
|
||||||
/* score, and last turn score */
|
|
||||||
int s;
|
|
||||||
int sl;
|
|
||||||
|
|
||||||
/* highscore */
|
|
||||||
int hs;
|
|
||||||
|
|
||||||
/* highscore file */
|
|
||||||
char *file;
|
|
||||||
|
|
||||||
/* Merges adjacent squares of the same value together in a certain direction */
|
|
||||||
int merge(int d)
|
|
||||||
{
|
|
||||||
int moved = 0;
|
|
||||||
if (d == DL) {
|
|
||||||
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 == DU) {
|
|
||||||
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 == DR) {
|
|
||||||
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 == DD) {
|
|
||||||
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 */
|
|
||||||
/* if animations are wanted, then need to alter this so it moves each square one at a time */
|
|
||||||
int gravitate(int d)
|
|
||||||
{
|
|
||||||
int moved = 0;
|
|
||||||
if (d == DL) {
|
|
||||||
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 == DU) {
|
|
||||||
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 == DR) {
|
|
||||||
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 == DD) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load hiscore */
|
|
||||||
void load_score() {
|
|
||||||
FILE *fd = fopen(file, "r");
|
|
||||||
if (fd == NULL) fd = fopen(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(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 chance of 1:3 respectively */
|
|
||||||
/* could do this in a much smarter fashion by finding which spaces are free */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* quick floor log2(n) */
|
|
||||||
int flog2(int n)
|
|
||||||
{
|
|
||||||
int k = 0;
|
|
||||||
while (n)
|
|
||||||
k++, n >>= 1;
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
// mvwprintw will sometimes have a useless arg, this is warned, but doesn't affect the program
|
|
||||||
char *scr = sl ? "SCORE: %d (+%d)\n" : "SCORE: %d\n";
|
|
||||||
mvwprintw(gamewin, 0, 0, scr, s, sl);
|
|
||||||
mvwprintw(gamewin, 1, 0, "HISCR: %d\n", hs);
|
|
||||||
|
|
||||||
ITER(SZ*(MAXVAL + 2) + 1, waddch(gamewin, '-'));
|
|
||||||
int i, j, xps = 0, yps = 3;
|
|
||||||
for (i = 0; i < SZ; i++, xps = 0, yps++) {
|
|
||||||
mvwprintw(gamewin, yps, xps++, "|");
|
|
||||||
for (j = 0; j < SZ; j++) {
|
|
||||||
if (g[i][j]) {
|
|
||||||
wattron(gamewin, COLOR_PAIR(flog2(g[i][j]) & 7));
|
|
||||||
mvwprintw(gamewin, yps, xps, "%*d", MAXVAL, g[i][j]);
|
|
||||||
wattroff(gamewin, COLOR_PAIR(flog2(g[i][j]) & 7));
|
|
||||||
mvwprintw(gamewin, yps, xps + MAXVAL, " |");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ITER(MAXVAL + 1, waddch(gamewin, ' '));
|
|
||||||
waddch(gamewin, '|');
|
|
||||||
}
|
|
||||||
xps += (MAXVAL + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ITER(SZ*(MAXVAL + 2) + 1, waddch(gamewin, '-'));
|
|
||||||
wrefresh(gamewin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
file = ".hs2048g";
|
|
||||||
hs = 0;
|
|
||||||
s = 0;
|
|
||||||
sl = 0;
|
|
||||||
SZ = 4;
|
|
||||||
MAXVAL = 4;
|
|
||||||
CALLOC2D(g, SZ);
|
|
||||||
|
|
||||||
load_score();
|
|
||||||
int n_blocks = 1;
|
|
||||||
|
|
||||||
/* parse options */
|
|
||||||
int c;
|
|
||||||
while ((c = getopt(argc, argv, "rchs:b:")) != -1) {
|
|
||||||
switch (c) {
|
|
||||||
// color support - assumes your terminal can display colours
|
|
||||||
// should still work regardless
|
|
||||||
case 'c':
|
|
||||||
start_color();
|
|
||||||
init_pair(1, 1, 0);
|
|
||||||
init_pair(2, 2, 0);
|
|
||||||
init_pair(3, 3, 0);
|
|
||||||
init_pair(4, 4, 0);
|
|
||||||
init_pair(5, 5, 0);
|
|
||||||
init_pair(6, 6, 0);
|
|
||||||
init_pair(7, 7, 0);
|
|
||||||
break;
|
|
||||||
// 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':
|
|
||||||
endwin();
|
|
||||||
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(file, "w+");
|
|
||||||
fclose(fd);
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
// help menu
|
|
||||||
case 'h':
|
|
||||||
endwin();
|
|
||||||
printf("Controls:\n"
|
|
||||||
" hjkl, wasd Movement\n"
|
|
||||||
" q Quit\n"
|
|
||||||
"\n"
|
|
||||||
"Usage:\n"
|
|
||||||
" 2048 [options]\n"
|
|
||||||
"\n"
|
|
||||||
"Options:\n"
|
|
||||||
" -s <size> Set the grid border length\n"
|
|
||||||
" -b <rate> Set the block spawn rate\n"
|
|
||||||
" -c Enables color support\n");
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = SZ * (MAXVAL + 2) + 1;
|
|
||||||
int height = SZ * (MAXVAL + 2) + 3;
|
|
||||||
|
|
||||||
// might center in middle of screen
|
|
||||||
WINDOW *gamewin = newwin(height, width, 1, 1);
|
|
||||||
keypad(gamewin, TRUE);
|
|
||||||
|
|
||||||
/* random seed */
|
|
||||||
srand((unsigned int)time(NULL));
|
|
||||||
ITER(2, rand_block());
|
|
||||||
draw_grid(gamewin);
|
|
||||||
|
|
||||||
int key, moved;
|
|
||||||
while (1) {
|
|
||||||
/* will goto this if we didn't get a valid keypress */
|
|
||||||
retry:;
|
|
||||||
moved = 0;
|
|
||||||
key = wgetch(gamewin);
|
|
||||||
sl = 0;
|
|
||||||
|
|
||||||
/* should check if anything changed during merge and if not retry */
|
|
||||||
switch (key) {
|
|
||||||
case 'h':
|
|
||||||
case 'a':
|
|
||||||
case KEY_LEFT:
|
|
||||||
moved = TURN(DL);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
case 'd':
|
|
||||||
case KEY_RIGHT:
|
|
||||||
moved = TURN(DR);
|
|
||||||
break;
|
|
||||||
case 'j':
|
|
||||||
case 's':
|
|
||||||
case KEY_DOWN:
|
|
||||||
moved = TURN(DD);
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
case 'w':
|
|
||||||
case KEY_UP:
|
|
||||||
moved = TURN(DU);
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
FREE2D(g, SZ);
|
|
||||||
erase();
|
|
||||||
refresh();
|
|
||||||
endwin();
|
|
||||||
save_score();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
default:
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moves_available()) {
|
|
||||||
endwin();
|
|
||||||
printf("\n"
|
|
||||||
"YOU LOSE! - Your score was %d\n", s);
|
|
||||||
save_score();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moved) {
|
|
||||||
ITER(n_blocks, rand_block());
|
|
||||||
draw_grid(gamewin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
Makefile
15
Makefile
|
@ -1,13 +1,14 @@
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS+=
|
CFLAGS += -Wall -Wextra
|
||||||
|
LIBS = -lcurses
|
||||||
|
|
||||||
all: 2048 2048_no_curses
|
all: 2048
|
||||||
|
|
||||||
2048: 2048_curses.c
|
2048: src/2048.c
|
||||||
$(CC) $(CFLAGS) 2048_curses.c -lcurses -o 2048
|
$(CC) $(CFLAGS) src/2048.c -o 2048 $(LIBS)
|
||||||
|
|
||||||
2048_no_curses: 2048_no_curses.c
|
2048nc: src/2048_no_curses.c
|
||||||
$(CC) $(CFLAGS) 2048_no_curses.c -o 2048_no_curses
|
$(CC) $(CFLAGS) src/2048_no_curses.c -o 2048nc
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f 2048 2048_no_curses
|
rm -f 2048 2048nc
|
||||||
|
|
13
README.md
13
README.md
|
@ -1,6 +1,7 @@
|
||||||
#2048-cli
|
#2048-cli
|
||||||
|
|
||||||
A cli version of the game [2048](https://github.com/gabrielecirulli/2048) for your Linux terminal.
|
A cli version of the game [2048](https://github.com/gabrielecirulli/2048) for your Linux
|
||||||
|
terminal.
|
||||||
|
|
||||||
#####2048_curses.c
|
#####2048_curses.c
|
||||||
![Screenshot](http://i.imgur.com/QU7t5mH.png)
|
![Screenshot](http://i.imgur.com/QU7t5mH.png)
|
||||||
|
@ -9,11 +10,13 @@ A cli version of the game [2048](https://github.com/gabrielecirulli/2048) for yo
|
||||||
![Screenshot](http://i.imgur.com/fwZEvdh.png)
|
![Screenshot](http://i.imgur.com/fwZEvdh.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
If you want to use the ncurses version, make sure that you have the required ncurses library and link against this during compilation with `-lcurses`. The program creates and uses a file named `.hs2048g` in the directory it is run. Ensure that you have no file of this name in the directory otherwise it will be overwritten.
|
This requires the ncurses library to link against during compilation. It is available
|
||||||
|
in most package managers. The program creates and uses a file name `.hs2048g` in the
|
||||||
|
working directory. Any file with this name will be modified and replaced.
|
||||||
|
|
||||||
### Get
|
### Get
|
||||||
cd ~/$INSTALL_DIR
|
git clone https://github.com/Tiehuis/2048-cli.git
|
||||||
wget https://raw.githubusercontent.com/Tiehuis/2048-cli/master/2048_no_curses.c
|
make
|
||||||
gcc 2048_no_curses.c -o 2048
|
|
||||||
### Run
|
### Run
|
||||||
./2048
|
./2048
|
||||||
|
|
||||||
|
|
350
src/2048.c
Normal file
350
src/2048.c
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
/*
|
||||||
|
* 2048.c - Main version that should be worked on.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* */
|
||||||
|
|
||||||
|
#include <stdlib.h> /* for malloc */
|
||||||
|
#include <time.h> /* for time */
|
||||||
|
#include <unistd.h> /* for getopts */
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include "2048.h"
|
||||||
|
|
||||||
|
int **grid; /* grid pointer */
|
||||||
|
int grid_size; /* grid size */
|
||||||
|
int score; /* score */
|
||||||
|
int score_last; /* Score for last move */
|
||||||
|
int score_high; /* Hiscore */
|
||||||
|
int printwidth; /* maximum length of any value in grid, for printing */
|
||||||
|
|
||||||
|
/* Merges adjacent squares of the same value together in a certain direction */
|
||||||
|
int merge(dir_t d)
|
||||||
|
{
|
||||||
|
int moved = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (d == DIR_LEFT || d == DIR_RIGHT) {
|
||||||
|
for (i = 0; i < grid_size; i++) {
|
||||||
|
for (j = 0; j < grid_size - 1; j++) {
|
||||||
|
if (grid[i][j] == grid[i][j + 1]) {
|
||||||
|
grid[i][j] <<= 1;
|
||||||
|
grid[i][j + 1] = 0;
|
||||||
|
score_last += grid[i][j];
|
||||||
|
score += grid[i][j];
|
||||||
|
moved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i = 0; i < grid_size - 1; i++) {
|
||||||
|
for (j = 0; j < grid_size; j++) {
|
||||||
|
if (grid[i][j] == grid[i + 1][j]) {
|
||||||
|
grid[i][j] <<= 2;
|
||||||
|
grid[i + 1][j] = 0;
|
||||||
|
score_last += grid[i][j];
|
||||||
|
score += grid[i][j];
|
||||||
|
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 */
|
||||||
|
/* if animations are wanted, then need to alter this so it moves each square one at a time */
|
||||||
|
int gravitate(dir_t d)
|
||||||
|
{
|
||||||
|
int moved = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (d == DIR_LEFT) {
|
||||||
|
for (i = 0; i < grid_size; i++) {
|
||||||
|
for (j = 0; j < grid_size - 1; j++) {
|
||||||
|
if (grid[i][j]) continue;
|
||||||
|
int st = 1;
|
||||||
|
while (j + st < grid_size && !grid[i][j + st]) st++;
|
||||||
|
if (j + st < grid_size) {
|
||||||
|
grid[i][j] = grid[i][j + st];
|
||||||
|
grid[i][j + st] = 0;
|
||||||
|
moved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (d == DIR_UP) {
|
||||||
|
for (i = 0; i < grid_size; i++) {
|
||||||
|
for (j = 0; j < grid_size - 1; j++) {
|
||||||
|
if (grid[j][i]) continue;
|
||||||
|
int st = 1;
|
||||||
|
while (j + st < grid_size && !grid[j + st][i]) st++;
|
||||||
|
if (j + st < grid_size) {
|
||||||
|
grid[j][i] = grid[j + st][i];
|
||||||
|
grid[j + st][i] = 0;
|
||||||
|
moved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (d == DIR_RIGHT) {
|
||||||
|
for (i = 0; i < grid_size; i++) {
|
||||||
|
for (j = grid_size - 1; j > 0; j--) {
|
||||||
|
if (grid[i][j]) continue;
|
||||||
|
int st = 1;
|
||||||
|
while (j - st >= 0 && !grid[i][j - st]) st++;
|
||||||
|
if (j - st >= 0) {
|
||||||
|
grid[i][j] = grid[i][j - st];
|
||||||
|
grid[i][j - st] = 0;
|
||||||
|
moved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (d == DIR_DOWN) {
|
||||||
|
for (i = 0; i < grid_size; i++) {
|
||||||
|
for (j = grid_size - 1; j > 0; j--) {
|
||||||
|
if (grid[j][i]) continue;
|
||||||
|
int st = 1;
|
||||||
|
while (j - st >= 0 && !grid[j - st][i]) st++;
|
||||||
|
if (j - st >= 0) {
|
||||||
|
grid[j][i] = grid[j - st][i];
|
||||||
|
grid[j - st][i] = 0;
|
||||||
|
moved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the current highscore */
|
||||||
|
int get_score_high() {
|
||||||
|
int s = 0;
|
||||||
|
FILE *fd = fopen(HISCORE_FILE, "r");
|
||||||
|
if (fd == NULL)
|
||||||
|
fd = fopen(HISCORE_FILE, "w+");
|
||||||
|
|
||||||
|
fscanf(fd, "%d", &s);
|
||||||
|
fclose(fd);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* saves hiscore, but only if playing on standard size grid */
|
||||||
|
void save_score_high() {
|
||||||
|
if (score > score_high && grid_size == 4) {
|
||||||
|
score_high = score;
|
||||||
|
FILE *fd = fopen(HISCORE_FILE, "w+");
|
||||||
|
fprintf(fd, "%d", score_high);
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns if there are any possible moves */
|
||||||
|
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]))
|
||||||
|
|| ((j + 1 < grid_size) && (grid[i][j] == grid[i][j + 1])))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* places a random block onto the grid - either a 4, or a 2 with a chance of 1:3 respectively */
|
||||||
|
/* could do this in a much smarter fashion by finding which spaces are free */
|
||||||
|
void rand_block()
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
while (grid[x = rand() % grid_size][y = rand() % grid_size]);
|
||||||
|
grid[x][y] = (rand() & 3) ? 2 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* quick floor log2(n) */
|
||||||
|
int flog2(int n)
|
||||||
|
{
|
||||||
|
int k = 0;
|
||||||
|
while (n)
|
||||||
|
k++, n >>= 1;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// mvwprintw will sometimes have a useless arg, this is warned, but doesn't affect the program
|
||||||
|
char *scr = score_last ? "SCORE: %d (+%d)\n" : "SCORE: %d\n";
|
||||||
|
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, '-'));
|
||||||
|
int i, j, xps = 0, yps = 3;
|
||||||
|
for (i = 0; i < grid_size; i++, xps = 0, yps++) {
|
||||||
|
mvwprintw(gamewin, yps, xps++, "|");
|
||||||
|
for (j = 0; j < grid_size; j++) {
|
||||||
|
if (grid[i][j]) {
|
||||||
|
wattron(gamewin, COLOR_PAIR(flog2(grid[i][j]) & 7));
|
||||||
|
mvwprintw(gamewin, yps, xps, "%*d", printwidth, grid[i][j]);
|
||||||
|
wattroff(gamewin, COLOR_PAIR(flog2(grid[i][j]) & 7));
|
||||||
|
mvwprintw(gamewin, yps, xps + printwidth, " |");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ITER(printwidth + 1, waddch(gamewin, ' '));
|
||||||
|
waddch(gamewin, '|');
|
||||||
|
}
|
||||||
|
xps += (printwidth + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ITER(grid_size*(printwidth + 2) + 1, waddch(gamewin, '-'));
|
||||||
|
wrefresh(gamewin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
score_last = 0;
|
||||||
|
score_high = get_score_high();
|
||||||
|
grid_size = DEFAULT_GRID_SIZE;
|
||||||
|
printwidth = DEFAULT_GRID_SIZE;
|
||||||
|
|
||||||
|
int n_blocks = 1;
|
||||||
|
|
||||||
|
/* parse options */
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "rchs:b:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
/* Color support */
|
||||||
|
case 'c':
|
||||||
|
if (has_colors()) {
|
||||||
|
start_color();
|
||||||
|
init_pair(0, 1, 0);
|
||||||
|
init_pair(1, 2, 0);
|
||||||
|
init_pair(2, 3, 0);
|
||||||
|
init_pair(3, 4, 0);
|
||||||
|
init_pair(4, 5, 0);
|
||||||
|
init_pair(5, 6, 0);
|
||||||
|
init_pair(6, 7, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Terminal does not support color\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// different board sizes
|
||||||
|
case 's':;
|
||||||
|
int optint = strtol(optarg, NULL, 10);
|
||||||
|
grid_size = optint > DEFAULT_GRID_SIZE ? optint : DEFAULT_GRID_SIZE;
|
||||||
|
break;
|
||||||
|
// different block spawn rate
|
||||||
|
case 'b':
|
||||||
|
n_blocks = strtol(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
// reset hiscores
|
||||||
|
case 'r':
|
||||||
|
endwin();
|
||||||
|
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);
|
||||||
|
// help menu
|
||||||
|
case 'h':
|
||||||
|
endwin();
|
||||||
|
printf(USAGE_STR);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* random seed */
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
ITER(2, rand_block());
|
||||||
|
draw_grid(gamewin);
|
||||||
|
|
||||||
|
int key, moved;
|
||||||
|
while (1) {
|
||||||
|
/* will goto this if we didn't get a valid keypress */
|
||||||
|
retry:;
|
||||||
|
moved = 0;
|
||||||
|
score_last = 0;
|
||||||
|
key = wgetch(gamewin);
|
||||||
|
|
||||||
|
/* should check if anything changed during merge and if not retry */
|
||||||
|
switch (key) {
|
||||||
|
case 'h':
|
||||||
|
case 'a':
|
||||||
|
case KEY_LEFT:
|
||||||
|
moved = TURN(DIR_LEFT);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
case 'd':
|
||||||
|
case KEY_RIGHT:
|
||||||
|
moved = TURN(DIR_RIGHT);
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
case 's':
|
||||||
|
case KEY_DOWN:
|
||||||
|
moved = TURN(DIR_DOWN);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
case 'w':
|
||||||
|
case KEY_UP:
|
||||||
|
moved = TURN(DIR_UP);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
FREE2D(grid, grid_size);
|
||||||
|
erase();
|
||||||
|
refresh();
|
||||||
|
endwin();
|
||||||
|
save_score_high();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
default:
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moves_available()) {
|
||||||
|
endwin();
|
||||||
|
printf("\n"
|
||||||
|
"YOU LOSE! - Your score was %d\n", score);
|
||||||
|
save_score_high();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moved) {
|
||||||
|
ITER(n_blocks, rand_block());
|
||||||
|
draw_grid(gamewin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
55
src/2048.h
Normal file
55
src/2048.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef _2048_H_
|
||||||
|
#define _2048_H_
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DIR_UP,
|
||||||
|
DIR_RIGHT,
|
||||||
|
DIR_DOWN,
|
||||||
|
DIR_LEFT
|
||||||
|
} dir_t;
|
||||||
|
|
||||||
|
// 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 ".hs2048g"
|
||||||
|
#define USAGE_STR\
|
||||||
|
"Usage:\n"\
|
||||||
|
" ./2048 [options]\n"\
|
||||||
|
"\n"\
|
||||||
|
"Controls:\n"\
|
||||||
|
" hjkl, wasd Movement\n"\
|
||||||
|
" q Quit\n"\
|
||||||
|
"\n"\
|
||||||
|
"Options:\n"\
|
||||||
|
" -s <size> Set the grid border length\n"\
|
||||||
|
" -b <rate> Set the block spawn rate\n"\
|
||||||
|
" -c Enables color support (ncurses version only)\n"
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,66 +1,25 @@
|
||||||
/* animations would be nice */
|
/*
|
||||||
|
* 2048_no_curses.c - Non-curses version that can be updated at a later time
|
||||||
|
**/
|
||||||
|
|
||||||
#include <stdio.h> /* for printf */
|
#include <stdio.h> /* for printf */
|
||||||
#include <stdlib.h> /* for malloc */
|
#include <stdlib.h> /* for malloc */
|
||||||
#include <termios.h>/* */
|
#include <termios.h>/* */
|
||||||
#include <time.h> /* for time */
|
#include <time.h> /* for time */
|
||||||
#include <unistd.h> /* for getopts */
|
#include <unistd.h> /* for getopts */
|
||||||
|
#include "2048.h"
|
||||||
|
|
||||||
// Repeat an expression y, x times */
|
int **g; /* grid pointer */
|
||||||
#define ITER(x, expr)\
|
int SZ; /* grid size */
|
||||||
do {\
|
int s; /* Current score */
|
||||||
int i;\
|
int sl; /* Score for last turn */
|
||||||
for (i = 0; i < x; i++){ expr;}\
|
int hs; /* Highscore */
|
||||||
} 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)
|
|
||||||
|
|
||||||
/* Define a sequence that should be executed each turn */
|
|
||||||
#define TURN(x)\
|
|
||||||
gravitate(x) +\
|
|
||||||
merge(x) +\
|
|
||||||
gravitate(x)
|
|
||||||
|
|
||||||
/* direction enumeration */
|
|
||||||
enum {DR, DU, DL, DD};
|
|
||||||
|
|
||||||
/* grid pointer */
|
|
||||||
int **g;
|
|
||||||
|
|
||||||
/* grid size */
|
|
||||||
int SZ;
|
|
||||||
|
|
||||||
/* score, and last turn score */
|
|
||||||
int s;
|
|
||||||
int sl;
|
|
||||||
|
|
||||||
/* highscore */
|
|
||||||
int hs;
|
|
||||||
|
|
||||||
/* highscore file */
|
|
||||||
char *file;
|
|
||||||
|
|
||||||
/* Merges adjacent squares of the same value together in a certain direction */
|
/* Merges adjacent squares of the same value together in a certain direction */
|
||||||
int merge(int d)
|
int merge(int d)
|
||||||
{
|
{
|
||||||
int moved = 0;
|
int moved = 0;
|
||||||
if (d == DL) {
|
if (d == DIR_LEFT) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = 0; j < SZ; j++) {
|
for (j = 0; j < SZ; j++) {
|
||||||
|
@ -74,7 +33,7 @@ int merge(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DU) {
|
else if (d == DIR_UP) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = 0; j < SZ; j++) {
|
for (j = 0; j < SZ; j++) {
|
||||||
|
@ -88,7 +47,7 @@ int merge(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DR) {
|
else if (d == DIR_RIGHT) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = SZ - 1; i >= 0; i--) {
|
for (i = SZ - 1; i >= 0; i--) {
|
||||||
for (j = SZ - 1; j >= 0; j--) {
|
for (j = SZ - 1; j >= 0; j--) {
|
||||||
|
@ -102,7 +61,7 @@ int merge(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DD) {
|
else if (d == DIR_DOWN) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = SZ - 1; i >= 0; i--) {
|
for (i = SZ - 1; i >= 0; i--) {
|
||||||
for (j = SZ - 1; j >= 0; j--) {
|
for (j = SZ - 1; j >= 0; j--) {
|
||||||
|
@ -125,7 +84,7 @@ int merge(int d)
|
||||||
int gravitate(int d)
|
int gravitate(int d)
|
||||||
{
|
{
|
||||||
int moved = 0;
|
int moved = 0;
|
||||||
if (d == DL) {
|
if (d == DIR_LEFT) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = 0; j < SZ - 1; j++) {
|
for (j = 0; j < SZ - 1; j++) {
|
||||||
|
@ -140,7 +99,7 @@ int gravitate(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DU) {
|
else if (d == DIR_UP) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = 0; j < SZ - 1; j++) {
|
for (j = 0; j < SZ - 1; j++) {
|
||||||
|
@ -155,7 +114,7 @@ int gravitate(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DR) {
|
else if (d == DIR_RIGHT) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = SZ - 1; j > 0; j--) {
|
for (j = SZ - 1; j > 0; j--) {
|
||||||
|
@ -170,7 +129,7 @@ int gravitate(int d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == DD) {
|
else if (d == DIR_DOWN) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < SZ; i++) {
|
for (i = 0; i < SZ; i++) {
|
||||||
for (j = SZ - 1; j > 0; j--) {
|
for (j = SZ - 1; j > 0; j--) {
|
||||||
|
@ -190,8 +149,8 @@ int gravitate(int d)
|
||||||
|
|
||||||
/* loads hiscore */
|
/* loads hiscore */
|
||||||
void load_score() {
|
void load_score() {
|
||||||
FILE *fd = fopen(file, "r");
|
FILE *fd = fopen(HISCORE_FILE, "r");
|
||||||
if (fd == NULL) fd = fopen(file, "w+");
|
if (fd == NULL) fd = fopen(HISCORE_FILE, "w+");
|
||||||
if (fscanf(fd, "%d", &hs) == EOF) hs = 0;
|
if (fscanf(fd, "%d", &hs) == EOF) hs = 0;
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +159,7 @@ void load_score() {
|
||||||
void save_score() {
|
void save_score() {
|
||||||
if (s > hs && SZ == 4) {
|
if (s > hs && SZ == 4) {
|
||||||
hs = s;
|
hs = s;
|
||||||
FILE *fd = fopen(file, "w+");
|
FILE *fd = fopen(HISCORE_FILE, "w+");
|
||||||
fprintf(fd, "%d", hs);
|
fprintf(fd, "%d", hs);
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
|
@ -265,7 +224,6 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* init variables */
|
/* init variables */
|
||||||
file = ".hs2048g";
|
|
||||||
hs = 0;
|
hs = 0;
|
||||||
s = 0;
|
s = 0;
|
||||||
sl = 0;
|
sl = 0;
|
||||||
|
@ -295,21 +253,12 @@ int main(int argc, char **argv)
|
||||||
printf("Are you sure you want to reset your highscores? (Y)es or (N)o\n");
|
printf("Are you sure you want to reset your highscores? (Y)es or (N)o\n");
|
||||||
int response;
|
int response;
|
||||||
if ((response = getchar()) == 'y' || response == 'Y') {
|
if ((response = getchar()) == 'y' || response == 'Y') {
|
||||||
FILE *fd = fopen(file, "w+");
|
FILE *fd = fopen(HISCORE_FILE, "w+");
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("Controls:\n"
|
printf(USAGE_STR);
|
||||||
" hjkl, wasd Movement\n"
|
|
||||||
" q Quit\n"
|
|
||||||
"\n"
|
|
||||||
"Usage:\n"
|
|
||||||
" 2048 [options]\n"
|
|
||||||
"\n"
|
|
||||||
"Options:\n"
|
|
||||||
" -s <size> Set the grid border length\n"
|
|
||||||
" -b <rate> Set the block spawn rate\n");
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,19 +290,19 @@ int main(int argc, char **argv)
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'a':
|
case 'a':
|
||||||
moved = TURN(DL);
|
moved = TURN(DIR_LEFT);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'd':
|
case 'd':
|
||||||
moved = TURN(DR);
|
moved = TURN(DIR_RIGHT);
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
case 's':
|
case 's':
|
||||||
moved = TURN(DD);
|
moved = TURN(DIR_DOWN);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
case 'w':
|
case 'w':
|
||||||
moved = TURN(DU);
|
moved = TURN(DIR_UP);
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
save_score();
|
save_score();
|
Loading…
Reference in New Issue
Block a user