Signed-off-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
393 lines
8.3 KiB
C
393 lines
8.3 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2014 Maurits van der Schee
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
*
|
|
* ============================================================================
|
|
* Name : 2048.c
|
|
* Author : Maurits van der Schee
|
|
* Description : Console version of the game "2048" for GNU/Linux
|
|
* ============================================================================
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <readkey.h>
|
|
#include <command.h>
|
|
#include <stdlib.h>
|
|
|
|
#define SIZE 4
|
|
static uint32_t score;
|
|
|
|
static void getColor(uint16_t value, char *color, size_t length)
|
|
{
|
|
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 *scheme = original;
|
|
uint8_t *background = scheme+0;
|
|
uint8_t *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(uint16_t board[SIZE][SIZE])
|
|
{
|
|
int8_t x,y;
|
|
char color[40], reset[] = "\033[m";
|
|
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];
|
|
int8_t 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(uint16_t array[SIZE],int8_t x,int8_t stop)
|
|
{
|
|
int8_t 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]!=0) {
|
|
if (array[t]!=array[x]) {
|
|
/* merge is not possible, take next position */
|
|
return t+1;
|
|
}
|
|
return t;
|
|
} else {
|
|
/* we should not slide further, return this one */
|
|
if (t==stop) {
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
/* we did not find a */
|
|
return x;
|
|
}
|
|
|
|
static bool slideArray(uint16_t array[SIZE])
|
|
{
|
|
bool success = false;
|
|
int8_t 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]!=0) {
|
|
score+=array[t]+array[x];
|
|
stop = t+1;
|
|
}
|
|
array[t]+=array[x];
|
|
array[x]=0;
|
|
success = true;
|
|
}
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
static void rotateBoard(uint16_t board[SIZE][SIZE])
|
|
{
|
|
int8_t i,j,n=SIZE;
|
|
uint16_t 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(uint16_t board[SIZE][SIZE])
|
|
{
|
|
bool success = false;
|
|
int8_t x;
|
|
for (x=0;x<SIZE;x++) {
|
|
success |= slideArray(board[x]);
|
|
}
|
|
return success;
|
|
}
|
|
|
|
static bool moveLeft(uint16_t board[SIZE][SIZE])
|
|
{
|
|
bool success;
|
|
rotateBoard(board);
|
|
success = moveUp(board);
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
return success;
|
|
}
|
|
|
|
static bool moveDown(uint16_t board[SIZE][SIZE])
|
|
{
|
|
bool success;
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
success = moveUp(board);
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
return success;
|
|
}
|
|
|
|
static bool moveRight(uint16_t board[SIZE][SIZE])
|
|
{
|
|
bool success;
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
rotateBoard(board);
|
|
success = moveUp(board);
|
|
rotateBoard(board);
|
|
return success;
|
|
}
|
|
|
|
static bool findPairDown(uint16_t board[SIZE][SIZE])
|
|
{
|
|
bool success = false;
|
|
int8_t 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(uint16_t board[SIZE][SIZE])
|
|
{
|
|
int8_t x,y;
|
|
int16_t 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(uint16_t 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(uint16_t board[SIZE][SIZE])
|
|
{
|
|
int8_t x,y;
|
|
int16_t r,len=0;
|
|
uint16_t 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)
|
|
{
|
|
uint16_t array[SIZE];
|
|
uint16_t 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
|
|
};
|
|
uint16_t *in,*out;
|
|
uint16_t t,tests;
|
|
uint8_t 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==false) {
|
|
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(int argc, char *argv[])
|
|
{
|
|
uint16_t board[SIZE][SIZE];
|
|
char c;
|
|
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);
|
|
while (true) {
|
|
c=read_key();
|
|
switch(c) {
|
|
case BB_KEY_LEFT: /* left arrow */
|
|
success = moveLeft(board); break;
|
|
case BB_KEY_RIGHT: /* right arrow */
|
|
success = moveRight(board); break;
|
|
case BB_KEY_UP: /* up arrow */
|
|
success = moveUp(board); break;
|
|
case BB_KEY_DOWN: /* down arrow */
|
|
success = moveDown(board); break;
|
|
default: success = false;
|
|
}
|
|
if (success) {
|
|
drawBoard(board);
|
|
udelay(150000);
|
|
addRandom(board);
|
|
drawBoard(board);
|
|
if (gameEnded(board)) {
|
|
printf(" GAME OVER \n");
|
|
break;
|
|
}
|
|
}
|
|
if (c=='q') {
|
|
printf(" QUIT \n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf("\033[?25h");
|
|
|
|
return 0;
|
|
}
|
|
|
|
BAREBOX_CMD_HELP_START(2048)
|
|
BAREBOX_CMD_HELP_TEXT("Use your arrow keys to move the tiles. When two tiles with")
|
|
BAREBOX_CMD_HELP_TEXT("the same number touch, they merge into one!")
|
|
BAREBOX_CMD_HELP_END
|
|
|
|
BAREBOX_CMD_START(2048)
|
|
.cmd = do_2048,
|
|
BAREBOX_CMD_DESC("the 2048 game")
|
|
BAREBOX_CMD_GROUP(CMD_GRP_MISC)
|
|
BAREBOX_CMD_HELP(cmd_2048_help)
|
|
BAREBOX_CMD_END
|