mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	As part of bringing the master branch back in to next, we need to allow for all of these changes to exist here. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			398 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			398 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: MIT
 | 
						|
// SPDX-FileCopyrightText: © 2014 Maurits van der Schee
 | 
						|
 | 
						|
/* Console version of the game "2048" for GNU/Linux */
 | 
						|
 | 
						|
#include <cli.h>
 | 
						|
#include <command.h>
 | 
						|
#include <rand.h>
 | 
						|
#include <vsprintf.h>
 | 
						|
#include <linux/delay.h>
 | 
						|
 | 
						|
#define SIZE 4
 | 
						|
static uint score;
 | 
						|
 | 
						|
static void getColor(uint value, char *color, size_t length)
 | 
						|
{
 | 
						|
	u8 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};
 | 
						|
	u8 *scheme = original;
 | 
						|
	u8 *background = scheme + 0;
 | 
						|
	u8 *foreground = scheme + 1;
 | 
						|
 | 
						|
	if (value > 0) {
 | 
						|
		while (value >>= 1) {
 | 
						|
			if (background + 2 < scheme + sizeof(original)) {
 | 
						|
				background += 2;
 | 
						|
				foreground += 2;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	snprintf(color, length, "\033[38;5;%d;48;5;%dm", *foreground,
 | 
						|
		 *background);
 | 
						|
}
 | 
						|
 | 
						|
static void drawBoard(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	int x, y;
 | 
						|
	char color[40], reset[] = "\033[0m";
 | 
						|
 | 
						|
	printf("\033[H");
 | 
						|
	printf("2048.c %17d pts\n\n", score);
 | 
						|
 | 
						|
	for (y = 0; y < SIZE; y++) {
 | 
						|
		for (x = 0; x < SIZE; x++) {
 | 
						|
			getColor(board[x][y], color, 40);
 | 
						|
			printf("%s", color);
 | 
						|
			printf("       ");
 | 
						|
			printf("%s", reset);
 | 
						|
		}
 | 
						|
		printf("\n");
 | 
						|
		for (x = 0; x < SIZE; x++) {
 | 
						|
			getColor(board[x][y], color, 40);
 | 
						|
			printf("%s", color);
 | 
						|
			if (board[x][y] != 0) {
 | 
						|
				char s[8];
 | 
						|
				s8 t;
 | 
						|
 | 
						|
				snprintf(s, 8, "%u", board[x][y]);
 | 
						|
				t = 7 - strlen(s);
 | 
						|
				printf("%*s%s%*s", t - t / 2, "", s, t / 2, "");
 | 
						|
			} else {
 | 
						|
				printf("   ·   ");
 | 
						|
			}
 | 
						|
			printf("%s", reset);
 | 
						|
		}
 | 
						|
		printf("\n");
 | 
						|
		for (x = 0; x < SIZE; x++) {
 | 
						|
			getColor(board[x][y], color, 40);
 | 
						|
			printf("%s", color);
 | 
						|
			printf("       ");
 | 
						|
			printf("%s", reset);
 | 
						|
		}
 | 
						|
		printf("\n");
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
	printf("        ←, ↑, →, ↓ or q        \n");
 | 
						|
	printf("\033[A");
 | 
						|
}
 | 
						|
 | 
						|
static int8_t findTarget(u16 array[SIZE], int x, int stop)
 | 
						|
{
 | 
						|
	int t;
 | 
						|
 | 
						|
	/* if the position is already on the first, don't evaluate */
 | 
						|
	if (x == 0)
 | 
						|
		return x;
 | 
						|
	for (t = x - 1; t >= 0; t--) {
 | 
						|
		if (array[t]) {
 | 
						|
			if (array[t] != array[x]) {
 | 
						|
				/* merge is not possible, take next position */
 | 
						|
				return t + 1;
 | 
						|
			}
 | 
						|
			return t;
 | 
						|
		}
 | 
						|
 | 
						|
		/* we should not slide further, return this one */
 | 
						|
		if (t == stop)
 | 
						|
			return t;
 | 
						|
	}
 | 
						|
	/* we did not find a */
 | 
						|
	return x;
 | 
						|
}
 | 
						|
 | 
						|
static bool slideArray(u16 array[SIZE])
 | 
						|
{
 | 
						|
	bool success = false;
 | 
						|
	int x, t, stop = 0;
 | 
						|
 | 
						|
	for (x = 0; x < SIZE; x++) {
 | 
						|
		if (array[x] != 0) {
 | 
						|
			t = findTarget(array, x, stop);
 | 
						|
			/*
 | 
						|
			 * if target is not original position, then move or
 | 
						|
			 * merge
 | 
						|
			 */
 | 
						|
			if (t != x) {
 | 
						|
				/*
 | 
						|
				 * if target is not zero, set stop to avoid
 | 
						|
				 * double merge
 | 
						|
				 */
 | 
						|
				if (array[t]) {
 | 
						|
					score += array[t] + array[x];
 | 
						|
					stop = t + 1;
 | 
						|
				}
 | 
						|
				array[t] += array[x];
 | 
						|
				array[x] = 0;
 | 
						|
				success = true;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static void rotateBoard(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	s8 i, j, n = SIZE;
 | 
						|
	int tmp;
 | 
						|
 | 
						|
	for (i = 0; i < n / 2; i++) {
 | 
						|
		for (j = i; j < n - i - 1; j++) {
 | 
						|
			tmp = board[i][j];
 | 
						|
			board[i][j] = board[j][n - i - 1];
 | 
						|
			board[j][n - i - 1] = board[n - i - 1][n - j - 1];
 | 
						|
			board[n - i - 1][n - j - 1] = board[n - j - 1][i];
 | 
						|
			board[n - j - 1][i] = tmp;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static bool moveUp(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool success = false;
 | 
						|
	int x;
 | 
						|
 | 
						|
	for (x = 0; x < SIZE; x++)
 | 
						|
		success |= slideArray(board[x]);
 | 
						|
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static bool moveLeft(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool success;
 | 
						|
 | 
						|
	rotateBoard(board);
 | 
						|
	success = moveUp(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static bool moveDown(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool success;
 | 
						|
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	success = moveUp(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static bool moveRight(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool success;
 | 
						|
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	success = moveUp(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static bool findPairDown(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool success = false;
 | 
						|
	int x, y;
 | 
						|
 | 
						|
	for (x = 0; x < SIZE; x++) {
 | 
						|
		for (y = 0; y < SIZE - 1; y++) {
 | 
						|
			if (board[x][y] == board[x][y + 1])
 | 
						|
				return true;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return success;
 | 
						|
}
 | 
						|
 | 
						|
static int16_t countEmpty(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	int x, y;
 | 
						|
	int count = 0;
 | 
						|
 | 
						|
	for (x = 0; x < SIZE; x++) {
 | 
						|
		for (y = 0; y < SIZE; y++) {
 | 
						|
			if (board[x][y] == 0)
 | 
						|
				count++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
static bool gameEnded(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	bool ended = true;
 | 
						|
 | 
						|
	if (countEmpty(board) > 0)
 | 
						|
		return false;
 | 
						|
	if (findPairDown(board))
 | 
						|
		return false;
 | 
						|
	rotateBoard(board);
 | 
						|
	if (findPairDown(board))
 | 
						|
		ended = false;
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
	rotateBoard(board);
 | 
						|
 | 
						|
	return ended;
 | 
						|
}
 | 
						|
 | 
						|
static void addRandom(u16 board[SIZE][SIZE])
 | 
						|
{
 | 
						|
	int x, y;
 | 
						|
	int r, len = 0;
 | 
						|
	u16 n, list[SIZE * SIZE][2];
 | 
						|
 | 
						|
	for (x = 0; x < SIZE; x++) {
 | 
						|
		for (y = 0; y < SIZE; y++) {
 | 
						|
			if (board[x][y] == 0) {
 | 
						|
				list[len][0] = x;
 | 
						|
				list[len][1] = y;
 | 
						|
				len++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (len > 0) {
 | 
						|
		r = rand() % len;
 | 
						|
		x = list[r][0];
 | 
						|
		y = list[r][1];
 | 
						|
		n = ((rand() % 10) / 9 + 1) * 2;
 | 
						|
		board[x][y] = n;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int test(void)
 | 
						|
{
 | 
						|
	u16 array[SIZE];
 | 
						|
	u16 data[] = {
 | 
						|
		0, 0, 0, 2,	2, 0, 0, 0,
 | 
						|
		0, 0, 2, 2,	4, 0, 0, 0,
 | 
						|
		0, 2, 0, 2,	4, 0, 0, 0,
 | 
						|
		2, 0, 0, 2,	4, 0, 0, 0,
 | 
						|
		2, 0, 2, 0,	4, 0, 0, 0,
 | 
						|
		2, 2, 2, 0,	4, 2, 0, 0,
 | 
						|
		2, 0, 2, 2,	4, 2, 0, 0,
 | 
						|
		2, 2, 0, 2,	4, 2, 0, 0,
 | 
						|
		2, 2, 2, 2,	4, 4, 0, 0,
 | 
						|
		4, 4, 2, 2,	8, 4, 0, 0,
 | 
						|
		2, 2, 4, 4,	4, 8, 0, 0,
 | 
						|
		8, 0, 2, 2,	8, 4, 0, 0,
 | 
						|
		4, 0, 2, 2,	4, 4, 0, 0
 | 
						|
	};
 | 
						|
	u16 *in, *out;
 | 
						|
	u16 t, tests;
 | 
						|
	int i;
 | 
						|
	bool success = true;
 | 
						|
 | 
						|
	tests = (sizeof(data) / sizeof(data[0])) / (2 * SIZE);
 | 
						|
	for (t = 0; t < tests; t++) {
 | 
						|
		in = data + t * 2 * SIZE;
 | 
						|
		out = in + SIZE;
 | 
						|
		for (i = 0; i < SIZE; i++)
 | 
						|
			array[i] = in[i];
 | 
						|
		slideArray(array);
 | 
						|
		for (i = 0; i < SIZE; i++) {
 | 
						|
			if (array[i] != out[i])
 | 
						|
				success = false;
 | 
						|
		}
 | 
						|
		if (!success) {
 | 
						|
			for (i = 0; i < SIZE; i++)
 | 
						|
				printf("%d ", in[i]);
 | 
						|
			printf(" = > ");
 | 
						|
			for (i = 0; i < SIZE; i++)
 | 
						|
				printf("%d ", array[i]);
 | 
						|
			printf("expected ");
 | 
						|
			for (i = 0; i < SIZE; i++)
 | 
						|
				printf("%d ", in[i]);
 | 
						|
			printf(" = > ");
 | 
						|
			for (i = 0; i < SIZE; i++)
 | 
						|
				printf("%d ", out[i]);
 | 
						|
			printf("\n");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (success)
 | 
						|
		printf("All %u tests executed successfully\n", tests);
 | 
						|
 | 
						|
	return !success;
 | 
						|
}
 | 
						|
 | 
						|
static int do_2048(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
						|
		   char *const argv[])
 | 
						|
{
 | 
						|
	struct cli_ch_state cch_s, *cch = &cch_s;
 | 
						|
	u16 board[SIZE][SIZE];
 | 
						|
	bool success;
 | 
						|
 | 
						|
	if (argc == 2 && strcmp(argv[1], "test") == 0)
 | 
						|
		return test();
 | 
						|
 | 
						|
	score = 0;
 | 
						|
 | 
						|
	printf("\033[?25l\033[2J\033[H");
 | 
						|
 | 
						|
	memset(board, 0, sizeof(board));
 | 
						|
	addRandom(board);
 | 
						|
	addRandom(board);
 | 
						|
	drawBoard(board);
 | 
						|
	cli_ch_init(cch);
 | 
						|
	while (true) {
 | 
						|
		int c;
 | 
						|
 | 
						|
		c = cli_ch_process(cch, 0);
 | 
						|
		if (!c) {
 | 
						|
			c = getchar();
 | 
						|
			c = cli_ch_process(cch, c);
 | 
						|
		}
 | 
						|
		switch (c) {
 | 
						|
		case CTL_CH('b'): /* left arrow */
 | 
						|
			success = moveLeft(board);
 | 
						|
			break;
 | 
						|
		case CTL_CH('f'): /* right arrow */
 | 
						|
			success = moveRight(board);
 | 
						|
			break;
 | 
						|
		case CTL_CH('p'):/* up arrow */
 | 
						|
			success = moveUp(board);
 | 
						|
			break;
 | 
						|
		case CTL_CH('n'): /* down arrow */
 | 
						|
			success = moveDown(board);
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			success = false;
 | 
						|
		}
 | 
						|
		if (success) {
 | 
						|
			drawBoard(board);
 | 
						|
			mdelay(150);
 | 
						|
			addRandom(board);
 | 
						|
			drawBoard(board);
 | 
						|
			if (gameEnded(board)) {
 | 
						|
				printf("         GAME OVER          \n");
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (c == 'q') {
 | 
						|
			printf("            QUIT            \n");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	printf("\033[?25h");
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
U_BOOT_CMD(
 | 
						|
	2048,	2,	1,	do_2048,
 | 
						|
	"The 2048 game",
 | 
						|
	"Use your arrow keys to move the tiles. When two tiles with "
 | 
						|
	"the same number touch, they merge into one!"
 | 
						|
);
 |