From af24a0d667976215456099d85f8b7216c5047f92 Mon Sep 17 00:00:00 2001 From: "Haoran S. Diao" <0@hairydiode.xyz> Date: Mon, 3 Feb 2020 15:04:56 -0800 Subject: Initial Commit --- Makefile | 2 + main.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 Makefile create mode 100644 main.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b974136 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +0x800: main.c + gcc main.c -o 0x800 diff --git a/main.c b/main.c new file mode 100644 index 0000000..0273894 --- /dev/null +++ b/main.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include +/* + *macro for random number from 0, up to but not including x, however this does + *not guarantee absolute equal distribution as RAND_MAX % x isn't guaranteed to + *be x-1, so all values up to and including RAND_MAX %x will have a slight + *advantage + */ +#define r(x) (rand() % x) +/* + * Stores the state of the game + */ +unsigned int field[4][4] = {0}; +//if victory is 1, then 2048 has been found, if -1, then we ran out of space +int victory = 0; +//loop var +int loop = 1; +/* + * Adds another value randomly to board, if this can not be done declare lose + * condition. It also looks for 2048 and handles the win condition + */ +void addlose() { + // Number of empty spaces left, it this is 0 then this function will + // handle the lose condition/ death screen + int empty = 0; + //loops through and counts empty spaces + for (int i = 0; i <4 ; i++) { + for (int j =0; j < 4; j++) { + if (field[i][j] == 0) { + empty++; + } + //victory detected + if (field[i][j] == 2048) { + loop = 0; + victory = 1; + return; + } + } + } + //no empty spaces left, lose + if (empty == 0) { + loop = 0; + victory = -1; + return; + } + int addfield = r(empty); + int k = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + //the kth empty field has been found + if (field[i][j] == 0) { + if ( k == addfield) { + field[i][j] = 2; + } + k++; + } + } + } +} +/* + * Shifts the values in field according to dx and dy, handles all logic even for + * the case where there is no shift. Returns 1 if it has shifted, return 0 if + * not. + */ +int shift (int dx, int dy) { + //if there is no shift, return + if (dx == 0 && dy == 0) { + return 0; + } + int shift = 0; + //initial and final x and y values + int xi, xf, yi, yf = 0; + //increment values, default to going low to high + int di, dj = 1; + /* + * We want it to go from highest x to lowest x if dx is positive, and + * the opposite if it's negative, likewise for y values + */ + if (dx > 0) { + di = -1; + xi = 3; + xf = -1; + } else { + di = 1; + xi = 0; + xf = 4; + } + if (dy > 0) { + dj = -1; + yi = 3; + yf = -1; + } else { + dj = 1; + yi = 0; + yf = 4; + } + //loops through and does all the shifting + for (int i = xi; i != xf; i += di) { + for (int j = yi; j != yf; j += dj) { + //finds prime field to compare to + int xp = i + dx; + int yp = j + dy; + //checks that there's an actual shift and that it's in + //bounds + if (xp == i && yp == j) { + //don't do anything + } else if (xp < 0 || xp > 3 || yp < 0 || yp > 3) { + //don't do anythign either + } else { + //it shifts and it's in bound + //check to see if you should merge + if (field[xp][yp] == 0 || + field[xp][yp] == field[i][j]) { + //make shift not 0 if that wasn't a zero + //being shifted + if (field[i][j] != 0) { + shift = 1; + } + //add the current field to the + //transformed field, then set current + //field to 0 so somebody else can move + //in. + field[xp][yp] += field[i][j]; + field[i][j] = 0; + } + } + + } + } + return shift; +} +int main (int argc, char * argv[]) { + //seeding RNG with time + srand(time(NULL)); + //initializes the game board + field[r(4)][r(4)] = 2; + //sets raw tty mode + struct termios term; + tcgetattr(STDIN_FILENO, &term); + struct termios old_term = term; + cfmakeraw(&term); + tcsetattr(STDIN_FILENO, TCSANOW, &term); + while (loop) { + //clears the screen + printf("\033[2J"); + //homes the cursor + printf("\033[H"); + //displays the field + for (int i =0; i < 4; i ++) { + for (int j = 0; j < 4; j++) { + //adds color + switch (field[j][i]) { + case 0: + printf("\033[31m"); + break; + case 2: + printf("\033[32m"); + break; + case 4: + printf("\033[33m"); + break; + case 8: + printf("\033[34m"); + break; + case 16: + printf("\033[35m"); + break; + case 32: + printf("\033[36m"); + break; + case 64: + printf("\033[1;31m"); + break; + case 128: + printf("\033[1;32m"); + break; + case 256: + printf("\033[30m\033[41m"); + break; + case 512: + printf("\033[30m\033[42m"); + break; + case 1024: + printf("\033[30m\033[43m"); + break; + case 2048: + printf("\033[30m\033[44m"); + break; + } + printf("%.3X\033[0;39m\033[49m ",field[j][i]); + } + printf("\r\n\n"); + } + //Determines the direction that blocks will attempt to move + int dx = 0; + int dy = 0; + //only reads one byte, may get messy with utf-8 + char input; + read(STDIN_FILENO, &input, 1); + //write(STDOUT_FILENO, &input, 1); + //input handling + switch (input) { + case 'q': + loop = 0; + break; + + case 'h': + dx = -1; + break; + + case 'j': + dy = 1; + break; + + case 'k': + dy = -1; + break; + + case 'l': + dx = 1; + break; + + default: + break; + } + //shifts until it can't shift anymore + while ( shift(dx,dy) ) { + //pass + } + //detects win/lose state, add another '2' to field otherwise + if (dx != 0 || dy != 0) { + addlose(); + } + } + //Prints victory or defeat + if (victory == 1) { + printf("YOU WIN\r\n"); + } else if (victory == -1) { + printf("YOU LOSE\r\n"); + } else { + printf("Goodbye!\r\n"); + } + //restores terminal state + printf("\033[0;39m\033[49m"); + tcsetattr(STDIN_FILENO, TCSANOW, &old_term); + return 0; +} -- cgit v1.1