From 9d5a9c9039316c28e82994179f3497986fc55d43 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 12 Nov 2025 10:03:38 +0800 Subject: [PATCH 1/8] support route board (r, u, 5) allow route board, and rename reset key r to n. --- 2048.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/2048.c b/2048.c index 21244a9..76682bb 100644 --- a/2048.c +++ b/2048.c @@ -89,7 +89,7 @@ void drawBoard(uint8_t board[SIZE][SIZE], uint8_t scheme, uint32_t score) printf("\n"); } printf("\n"); - printf(" ←,↑,→,↓ or q \n"); + printf(" ←,↑,→,↓,r or q \n"); printf("\033[A"); // one line up } @@ -526,6 +526,11 @@ int main(int argc, char *argv[]) case 66: // down arrow success = moveDown(board, &score); break; + case 53: // '5' key + case 114: // 'r' key + case 117: // 'u' key + rotateBoard(board); + drawBoard(board, scheme, score); default: success = false; } @@ -551,7 +556,7 @@ int main(int argc, char *argv[]) } drawBoard(board, scheme, score); } - if (c == 'r') + if (c == 'n') { printf(" RESTART? (y/n) \n"); c = getchar(); From f6d0cd8aaa90ed0f8109ae13484cb4b8f627b86d Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 12 Nov 2025 18:45:09 +0800 Subject: [PATCH 2/8] add termux support (reverse the numpad order ) --- 2048.c | 83 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/2048.c b/2048.c index 76682bb..1df84e1 100644 --- a/2048.c +++ b/2048.c @@ -436,6 +436,57 @@ void signal_callback_handler(int signum) exit(signum); } +typedef enum +{ + UP, + DOWN, + LEFT, + RIGHT, + ROTATE, + OTHER +} key_map_t; + +key_map_t key_map(char c, bool termux) +{ + switch (c) + { + case 52: // '4' key + case 97: // 'a' key + case 104: // 'h' key + case 68: // left arrow + return LEFT; + + case 54: // '6' key + case 100: // 'd' key + case 108: // 'l' key + case 67: // right arrow + return RIGHT; + + case 56: // '8' key + if (termux) + return DOWN; + case 119: // 'w' key + case 107: // 'k' key + case 65: // up arrow + return UP; + + case 50: // '2' key + if (termux) + return UP; + case 115: // 's' key + case 106: // 'j' key + case 66: // down arrow + return DOWN; + + case 53: // '5' key + case 114: // 'r' key + case 117: // 'u' key + return ROTATE; + default: + return OTHER; + } +} + int main(int argc, char *argv[]) { uint8_t board[SIZE][SIZE]; @@ -443,6 +494,7 @@ int main(int argc, char *argv[]) uint32_t score = 0; int c; bool success; + bool termux; // handle the command line options if (argc > 1) @@ -483,6 +535,8 @@ int main(int argc, char *argv[]) } } + termux = getenv("TERMUX__PREFIX") != NULL ? true : false; + // make cursor invisible, erase entire screen printf("\033[?25l\033[2J"); @@ -492,6 +546,7 @@ int main(int argc, char *argv[]) initBoard(board); setBufferedInput(false); drawBoard(board, scheme, score); + while (true) { c = getchar(); @@ -500,38 +555,24 @@ int main(int argc, char *argv[]) puts("\nError! Cannot read keyboard input!"); break; } - switch (c) + switch (key_map(c, termux)) { - case 52: // '4' key - case 97: // 'a' key - case 104: // 'h' key - case 68: // left arrow + case LEFT: success = moveLeft(board, &score); break; - case 54: // '6' key - case 100: // 'd' key - case 108: // 'l' key - case 67: // right arrow + case RIGHT: success = moveRight(board, &score); break; - case 56: // '8' key - case 119: // 'w' key - case 107: // 'k' key - case 65: // up arrow + case UP: success = moveUp(board, &score); break; - case 50: // '2' key - case 115: // 's' key - case 106: // 'j' key - case 66: // down arrow + case DOWN: success = moveDown(board, &score); break; - case 53: // '5' key - case 114: // 'r' key - case 117: // 'u' key + case ROTATE: rotateBoard(board); drawBoard(board, scheme, score); - default: + case OTHER: success = false; } if (success) From 2656337a0d4771a117762b7b6d384d78bfd8140e Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Sun, 16 Nov 2025 14:40:20 +0800 Subject: [PATCH 3/8] fix issue due to key rename (r->n) --- 2048.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2048.c b/2048.c index 1df84e1..5f5afb7 100644 --- a/2048.c +++ b/2048.c @@ -597,7 +597,7 @@ int main(int argc, char *argv[]) } drawBoard(board, scheme, score); } - if (c == 'n') + else if (c == 'n') { printf(" RESTART? (y/n) \n"); c = getchar(); From fbbec47ec84cc10c44ad4d89b7c1bf0223927eaf Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 21 Nov 2025 08:57:51 +0800 Subject: [PATCH 4/8] fix issue white on white when pics is 128 --- 2048.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2048.c b/2048.c index 5f5afb7..8410020 100644 --- a/2048.c +++ b/2048.c @@ -24,7 +24,7 @@ // this function receives 2 pointers (indicated by *) so it can set their values void getColors(uint8_t value, uint8_t scheme, uint8_t *foreground, uint8_t *background) { - uint8_t original[] = {8, 255, 1, 255, 2, 255, 3, 255, 4, 255, 5, 255, 6, 255, 7, 255, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 255, 0, 255, 0}; + uint8_t original[] = {8, 255, 1, 255, 2, 255, 3, 255, 4, 255, 5, 255, 6, 255, 7, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 255, 0, 255, 0}; uint8_t blackwhite[] = {232, 255, 234, 255, 236, 255, 238, 255, 240, 255, 242, 255, 244, 255, 246, 0, 248, 0, 249, 0, 250, 0, 251, 0, 252, 0, 253, 0, 254, 0, 255, 0}; uint8_t bluered[] = {235, 255, 63, 255, 57, 255, 93, 255, 129, 255, 165, 255, 201, 255, 200, 255, 199, 255, 198, 255, 197, 255, 196, 255, 196, 255, 196, 255, 196, 255, 196, 255}; uint8_t *schemes[] = {original, blackwhite, bluered}; From 1f9f4aaa27df105eb8341e7006fbfadb51174519 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 28 Nov 2025 16:43:19 +0800 Subject: [PATCH 5/8] support large board from 4x4 to 9x9 with compile options for example: support 6x6 board, compile with: CFLAGS='-DSIZE=6' make --- 2048.c | 73 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/2048.c b/2048.c index 8410020..cd1db7d 100644 --- a/2048.c +++ b/2048.c @@ -19,7 +19,32 @@ #include // defines: time #include // defines: signal, SIGINT +#if defined(SIZE) && ((SIZE < 4) || (SIZE > 9)) +#warning "The board ranges from 4x4 to 9x9, default to 4x4" +#undef SIZE +#endif +#ifndef SIZE #define SIZE 4 +#endif + +#define ROW_WIDTH SIZE * 7 + +#define PRINT_TITLE(score) \ + do \ + { \ + char fmt[48]; \ + sprintf(fmt, "\n2048.c %%%du pts\n\n\0", ROW_WIDTH - 11); \ + printf(fmt, score); \ + } while (0) + +#define PRINT_FOOT(str, len) \ + do \ + { \ + char pad[ROW_WIDTH]; \ + memset(pad, ' ', ROW_WIDTH); \ + pad[(ROW_WIDTH - len + 1) / 2] = '\0'; \ + printf("\n%s%s%s", pad, str, pad); \ + } while (0) // this function receives 2 pointers (indicated by *) so it can set their values void getColors(uint8_t value, uint8_t scheme, uint8_t *foreground, uint8_t *background) @@ -49,7 +74,7 @@ void drawBoard(uint8_t board[SIZE][SIZE], uint8_t scheme, uint32_t score) { uint8_t x, y, fg, bg; printf("\033[H"); // move cursor to 0,0 - printf("2048.c %17u pts\n\n", score); + PRINT_TITLE(score); for (y = 0; y < SIZE; y++) { for (x = 0; x < SIZE; x++) @@ -88,12 +113,11 @@ void drawBoard(uint8_t board[SIZE][SIZE], uint8_t scheme, uint32_t score) } printf("\n"); } - printf("\n"); - printf(" ←,↑,→,↓,r or q \n"); + PRINT_FOOT("←,↑,→,↓,r or q", 14); printf("\033[A"); // one line up } -uint8_t findTarget(uint8_t array[SIZE], uint8_t x, uint8_t stop) +uint8_t findTarget(uint8_t *array, uint8_t x, uint8_t stop) { uint8_t t; // if the position is already on the first, don't evaluate @@ -125,12 +149,12 @@ uint8_t findTarget(uint8_t array[SIZE], uint8_t x, uint8_t stop) return x; } -bool slideArray(uint8_t array[SIZE], uint32_t *score) +bool slideArray(uint8_t *array, uint32_t *score, uint8_t size) { bool success = false; uint8_t x, t, stop = 0; - for (x = 0; x < SIZE; x++) + for (x = 0; x < size; x++) { if (array[x] != 0) { @@ -183,7 +207,7 @@ bool moveUp(uint8_t board[SIZE][SIZE], uint32_t *score) uint8_t x; for (x = 0; x < SIZE; x++) { - success |= slideArray(board[x], score); + success |= slideArray(board[x], score, SIZE); } return success; } @@ -347,9 +371,10 @@ void setBufferedInput(bool enable) } } +#define TEST_SIZE 4 bool testSucceed() { - uint8_t array[SIZE]; + uint8_t array[TEST_SIZE]; // these are exponents with base 2 (1=2 2=4 3=8) // data holds per line: 4x IN, 4x OUT, 1x POINTS uint8_t data[] = { @@ -372,19 +397,19 @@ bool testSucceed() bool success = true; uint32_t score; - tests = (sizeof(data) / sizeof(data[0])) / (2 * SIZE + 1); + tests = (sizeof(data) / sizeof(data[0])) / (2 * TEST_SIZE + 1); for (t = 0; t < tests; t++) { - in = data + t * (2 * SIZE + 1); - out = in + SIZE; - points = in + 2 * SIZE; - for (i = 0; i < SIZE; i++) + in = data + t * (2 * TEST_SIZE + 1); + out = in + TEST_SIZE; + points = in + 2 * TEST_SIZE; + for (i = 0; i < TEST_SIZE; i++) { array[i] = in[i]; } score = 0; - slideArray(array, &score); - for (i = 0; i < SIZE; i++) + slideArray(array, &score, TEST_SIZE); + for (i = 0; i < TEST_SIZE; i++) { if (array[i] != out[i]) { @@ -397,22 +422,22 @@ bool testSucceed() } if (success == false) { - for (i = 0; i < SIZE; i++) + for (i = 0; i < TEST_SIZE; i++) { printf("%u ", in[i]); } printf("=> "); - for (i = 0; i < SIZE; i++) + for (i = 0; i < TEST_SIZE; i++) { printf("%u ", array[i]); } printf("(%u points) expected ", score); - for (i = 0; i < SIZE; i++) + for (i = 0; i < TEST_SIZE; i++) { printf("%u ", in[i]); } printf("=> "); - for (i = 0; i < SIZE; i++) + for (i = 0; i < TEST_SIZE; i++) { printf("%u ", out[i]); } @@ -429,10 +454,10 @@ bool testSucceed() void signal_callback_handler(int signum) { - printf(" TERMINATED \n"); + PRINT_FOOT("TERMINATED", 10); setBufferedInput(true); // make cursor visible, reset all modes - printf("\033[?25h\033[m"); + printf("\033[?25h\033[m\n"); exit(signum); } @@ -583,13 +608,13 @@ int main(int argc, char *argv[]) drawBoard(board, scheme, score); if (gameEnded(board)) { - printf(" GAME OVER \n"); + PRINT_FOOT("GAME OVER", 9); break; } } if (c == 'q') { - printf(" QUIT? (y/n) \n"); + PRINT_FOOT("QUIT? (y/n)", 11); c = getchar(); if (c == 'y') { @@ -599,7 +624,7 @@ int main(int argc, char *argv[]) } else if (c == 'n') { - printf(" RESTART? (y/n) \n"); + PRINT_FOOT("RESTART? (y/n)", 14); c = getchar(); if (c == 'y') { From 233dac2925e8b70e8a3210436a90de1f54b162bb Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 28 Nov 2025 17:06:58 +0800 Subject: [PATCH 6/8] refine quit with newline && refine name --- 2048.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/2048.c b/2048.c index cd1db7d..f131267 100644 --- a/2048.c +++ b/2048.c @@ -27,14 +27,16 @@ #define SIZE 4 #endif -#define ROW_WIDTH SIZE * 7 - -#define PRINT_TITLE(score) \ - do \ - { \ - char fmt[48]; \ - sprintf(fmt, "\n2048.c %%%du pts\n\n\0", ROW_WIDTH - 11); \ - printf(fmt, score); \ +#define ROW_WIDTH (SIZE * 7) + +#define PRINT_HEAD(score) \ + do \ + { \ + char fmt[48]; \ + uint8_t len = ROW_WIDTH - 11; \ + len = sprintf(fmt, "\n2048.c %%%du pts\n\n", len); \ + fmt[len] = '\0'; \ + printf(fmt, score); \ } while (0) #define PRINT_FOOT(str, len) \ @@ -74,7 +76,7 @@ void drawBoard(uint8_t board[SIZE][SIZE], uint8_t scheme, uint32_t score) { uint8_t x, y, fg, bg; printf("\033[H"); // move cursor to 0,0 - PRINT_TITLE(score); + PRINT_HEAD(score); for (y = 0; y < SIZE; y++) { for (x = 0; x < SIZE; x++) @@ -637,7 +639,7 @@ int main(int argc, char *argv[]) setBufferedInput(true); // make cursor visible, reset all modes - printf("\033[?25h\033[m"); + printf("\033[?25h\033[m\n"); return EXIT_SUCCESS; } From c95450a201f303dfebd06ccbfb19b0ae264744a9 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 1 Dec 2025 08:48:17 +0800 Subject: [PATCH 7/8] re-hiden cursor after vty reset --- 2048.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/2048.c b/2048.c index f131267..a6e7cbc 100644 --- a/2048.c +++ b/2048.c @@ -75,7 +75,8 @@ uint8_t getDigitCount(uint32_t number) void drawBoard(uint8_t board[SIZE][SIZE], uint8_t scheme, uint32_t score) { uint8_t x, y, fg, bg; - printf("\033[H"); // move cursor to 0,0 + printf("\033[?25l"); // hide cursor again due to reset vty + printf("\033[H"); // move cursor to 0,0 PRINT_HEAD(score); for (y = 0; y < SIZE; y++) { From 926df0b00112ded6b9f66e1fb05b438a0cfe5962 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Sat, 6 Dec 2025 22:45:57 +0800 Subject: [PATCH 8/8] add demostration mode support auto run, with left, right, down key --- 2048.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/2048.c b/2048.c index a6e7cbc..293220c 100644 --- a/2048.c +++ b/2048.c @@ -18,6 +18,8 @@ #include // defines: uint8_t, uint32_t #include // defines: time #include // defines: signal, SIGINT +#include // defines: number format +#include #if defined(SIZE) && ((SIZE < 4) || (SIZE > 9)) #warning "The board ranges from 4x4 to 9x9, default to 4x4" @@ -29,14 +31,14 @@ #define ROW_WIDTH (SIZE * 7) -#define PRINT_HEAD(score) \ - do \ - { \ - char fmt[48]; \ - uint8_t len = ROW_WIDTH - 11; \ - len = sprintf(fmt, "\n2048.c %%%du pts\n\n", len); \ - fmt[len] = '\0'; \ - printf(fmt, score); \ +#define PRINT_HEAD(score) \ + do \ + { \ + char fmt[48]; \ + uint8_t len = ROW_WIDTH - 11; \ + len = sprintf(fmt, "\n2048.c %%\'%du pts\n\n", len); \ + fmt[len] = '\0'; \ + printf(fmt, score); \ } while (0) #define PRINT_FOOT(str, len) \ @@ -514,6 +516,10 @@ key_map_t key_map(char c, bool termux) return OTHER; } } +char rand_key() +{ + return "asd"[rand() % 3]; // left down right +} int main(int argc, char *argv[]) { @@ -523,6 +529,7 @@ int main(int argc, char *argv[]) int c; bool success; bool termux; + bool demo; // handle the command line options if (argc > 1) @@ -556,6 +563,10 @@ int main(int argc, char *argv[]) { return testSucceed() ? EXIT_SUCCESS : EXIT_FAILURE; } + else if (strcmp(argv[1], "demo") == 0) + { + demo = true; + } else { printf("Invalid option: %s\n\nTry '%s --help' for more options.\n", argv[1], argv[0]); @@ -564,7 +575,7 @@ int main(int argc, char *argv[]) } termux = getenv("TERMUX__PREFIX") != NULL ? true : false; - + setlocale(LC_NUMERIC, "en_US"); // make cursor invisible, erase entire screen printf("\033[?25l\033[2J"); @@ -577,7 +588,7 @@ int main(int argc, char *argv[]) while (true) { - c = getchar(); + c = demo ? rand_key() : getchar(); if (c == EOF) { puts("\nError! Cannot read keyboard input!"); @@ -606,7 +617,7 @@ int main(int argc, char *argv[]) if (success) { drawBoard(board, scheme, score); - usleep(150 * 1000); // 150 ms + usleep((demo ? 1 : 150) * 1000); // 1 or 150 ms addRandom(board); drawBoard(board, scheme, score); if (gameEnded(board))