u-boot/cmd/2048.c
Tom Rini d678a59d2d Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay
Ethernet"' I failed to notice that b4 noticed it was based on next and
so took that as the base commit and merged that part of next to master.

This reverts commit c8ffd1356d, reversing
changes made to 2ee6f3a5f7.

Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
2024-05-19 08:16:36 -06:00

397 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 <common.h>
#include <cli.h>
#include <command.h>
#include <rand.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!"
);