1 // SPDX-License-Identifier: MIT
2 // SPDX-FileCopyrightText: © 2014 Maurits van der Schee
4 /* Console version of the game "2048" for GNU/Linux */
10 #include <linux/delay.h>
15 static void getColor(uint value, char *color, size_t length)
18 8, 255, 1, 255, 2, 255, 3, 255,
19 4, 255, 5, 255, 6, 255, 7, 255,
20 9, 0, 10, 0, 11, 0, 12, 0, 13,
21 0, 14, 0, 255, 0, 255, 0};
22 u8 *scheme = original;
23 u8 *background = scheme + 0;
24 u8 *foreground = scheme + 1;
28 if (background + 2 < scheme + sizeof(original)) {
34 snprintf(color, length, "\033[38;5;%d;48;5;%dm", *foreground,
38 static void drawBoard(u16 board[SIZE][SIZE])
41 char color[40], reset[] = "\033[0m";
44 printf("2048.c %17d pts\n\n", score);
46 for (y = 0; y < SIZE; y++) {
47 for (x = 0; x < SIZE; x++) {
48 getColor(board[x][y], color, 40);
54 for (x = 0; x < SIZE; x++) {
55 getColor(board[x][y], color, 40);
57 if (board[x][y] != 0) {
61 snprintf(s, 8, "%u", board[x][y]);
63 printf("%*s%s%*s", t - t / 2, "", s, t / 2, "");
70 for (x = 0; x < SIZE; x++) {
71 getColor(board[x][y], color, 40);
79 printf(" ←, ↑, →, ↓ or q \n");
83 static int8_t findTarget(u16 array[SIZE], int x, int stop)
87 /* if the position is already on the first, don't evaluate */
90 for (t = x - 1; t >= 0; t--) {
92 if (array[t] != array[x]) {
93 /* merge is not possible, take next position */
99 /* we should not slide further, return this one */
103 /* we did not find a */
107 static bool slideArray(u16 array[SIZE])
109 bool success = false;
112 for (x = 0; x < SIZE; x++) {
114 t = findTarget(array, x, stop);
116 * if target is not original position, then move or
121 * if target is not zero, set stop to avoid
125 score += array[t] + array[x];
128 array[t] += array[x];
137 static void rotateBoard(u16 board[SIZE][SIZE])
142 for (i = 0; i < n / 2; i++) {
143 for (j = i; j < n - i - 1; j++) {
145 board[i][j] = board[j][n - i - 1];
146 board[j][n - i - 1] = board[n - i - 1][n - j - 1];
147 board[n - i - 1][n - j - 1] = board[n - j - 1][i];
148 board[n - j - 1][i] = tmp;
153 static bool moveUp(u16 board[SIZE][SIZE])
155 bool success = false;
158 for (x = 0; x < SIZE; x++)
159 success |= slideArray(board[x]);
164 static bool moveLeft(u16 board[SIZE][SIZE])
169 success = moveUp(board);
176 static bool moveDown(u16 board[SIZE][SIZE])
182 success = moveUp(board);
188 static bool moveRight(u16 board[SIZE][SIZE])
195 success = moveUp(board);
200 static bool findPairDown(u16 board[SIZE][SIZE])
202 bool success = false;
205 for (x = 0; x < SIZE; x++) {
206 for (y = 0; y < SIZE - 1; y++) {
207 if (board[x][y] == board[x][y + 1])
215 static int16_t countEmpty(u16 board[SIZE][SIZE])
220 for (x = 0; x < SIZE; x++) {
221 for (y = 0; y < SIZE; y++) {
222 if (board[x][y] == 0)
229 static bool gameEnded(u16 board[SIZE][SIZE])
233 if (countEmpty(board) > 0)
235 if (findPairDown(board))
238 if (findPairDown(board))
247 static void addRandom(u16 board[SIZE][SIZE])
251 u16 n, list[SIZE * SIZE][2];
253 for (x = 0; x < SIZE; x++) {
254 for (y = 0; y < SIZE; y++) {
255 if (board[x][y] == 0) {
267 n = ((rand() % 10) / 9 + 1) * 2;
272 static int test(void)
276 0, 0, 0, 2, 2, 0, 0, 0,
277 0, 0, 2, 2, 4, 0, 0, 0,
278 0, 2, 0, 2, 4, 0, 0, 0,
279 2, 0, 0, 2, 4, 0, 0, 0,
280 2, 0, 2, 0, 4, 0, 0, 0,
281 2, 2, 2, 0, 4, 2, 0, 0,
282 2, 0, 2, 2, 4, 2, 0, 0,
283 2, 2, 0, 2, 4, 2, 0, 0,
284 2, 2, 2, 2, 4, 4, 0, 0,
285 4, 4, 2, 2, 8, 4, 0, 0,
286 2, 2, 4, 4, 4, 8, 0, 0,
287 8, 0, 2, 2, 8, 4, 0, 0,
288 4, 0, 2, 2, 4, 4, 0, 0
295 tests = (sizeof(data) / sizeof(data[0])) / (2 * SIZE);
296 for (t = 0; t < tests; t++) {
297 in = data + t * 2 * SIZE;
299 for (i = 0; i < SIZE; i++)
302 for (i = 0; i < SIZE; i++) {
303 if (array[i] != out[i])
307 for (i = 0; i < SIZE; i++)
308 printf("%d ", in[i]);
310 for (i = 0; i < SIZE; i++)
311 printf("%d ", array[i]);
313 for (i = 0; i < SIZE; i++)
314 printf("%d ", in[i]);
316 for (i = 0; i < SIZE; i++)
317 printf("%d ", out[i]);
323 printf("All %u tests executed successfully\n", tests);
328 static int do_2048(struct cmd_tbl *cmdtp, int flag, int argc,
331 struct cli_ch_state cch_s, *cch = &cch_s;
332 u16 board[SIZE][SIZE];
335 if (argc == 2 && strcmp(argv[1], "test") == 0)
340 printf("\033[?25l\033[2J\033[H");
342 memset(board, 0, sizeof(board));
350 c = cli_ch_process(cch, 0);
353 c = cli_ch_process(cch, c);
356 case CTL_CH('b'): /* left arrow */
357 success = moveLeft(board);
359 case CTL_CH('f'): /* right arrow */
360 success = moveRight(board);
362 case CTL_CH('p'):/* up arrow */
363 success = moveUp(board);
365 case CTL_CH('n'): /* down arrow */
366 success = moveDown(board);
376 if (gameEnded(board)) {
377 printf(" GAME OVER \n");
395 "Use your arrow keys to move the tiles. When two tiles with "
396 "the same number touch, they merge into one!"