2048: Cleanup

- more whitespace to enhance readability
 - better/fixed/more comments ;)
 - some minor optimizations
 - general code cleanup

Change-Id: I2b5f69aba0f83f989abb2c636920646e4315583f
This commit is contained in:
Franklin Wei 2015-04-01 18:15:29 -04:00 committed by Gerrit Rockbox
parent 24533635c0
commit d8ee5fcfc4

View file

@ -46,25 +46,25 @@
#include "pluginbitmaps/_2048_tiles.h"
#endif
/* defines */
/* some constants */
#define ANIM_SLEEPTIME (HZ/20)
static const int ANIM_SLEEPTIME = (HZ/20);
static const int NUM_STARTING_TILES = 2;
static const int VERT_SPACING = 4;
static const int WHAT_FONT = FONT_UI;
static const unsigned int WINNING_TILE = 2048;
/* must use macros for these */
#define GRID_SIZE 4
#define HISCORES_FILE PLUGIN_GAMES_DATA_DIR "/2048.score"
#define MIN_SPACE (BMPHEIGHT__2048_tiles * 0.134)
#define NUM_SCORES 5
#define NUM_STARTING_TILES 2
#define RESUME_FILE PLUGIN_GAMES_DATA_DIR "/2048.save"
#define WHAT_FONT FONT_UI
#define SPACES (GRID_SIZE * GRID_SIZE)
#define MIN_SPACE (BMPHEIGHT__2048_tiles*0.134) /* space between tiles */
#define MAX_UNDOS 64
#define VERT_SPACING 4
#define WINNING_TILE 2048
/* screen-specific configuration */
#if LCD_WIDTH<LCD_HEIGHT
/* tall screens */
#if (LCD_WIDTH < LCD_HEIGHT) /* tall screens */
# define TITLE_X 0
# define TITLE_Y 0
# define BASE_Y (BMPHEIGHT__2048_tiles*1.5)
@ -73,8 +73,7 @@
# define SCORE_Y (max_numeral_height)
# define BEST_SCORE_X 0
# define BEST_SCORE_Y (2*max_numeral_height)
#else
/* wide screens or square screens*/
#else /* wide or square screens */
# define TITLE_X 0
# define TITLE_Y 0
# define BASE_X (LCD_WIDTH-(GRID_SIZE*BMPHEIGHT__2048_tiles)-(((GRID_SIZE+1)*MIN_SPACE)))
@ -85,11 +84,11 @@
# define BEST_SCORE_Y (2*max_numeral_height)
#endif /* LCD_WIDTH < LCD_HEIGHT */
#define BACKGROUND_X (int)(BASE_X-MIN_SPACE)
#define BACKGROUND_Y (int)(BASE_Y-MIN_SPACE)
/* where to draw the background bitmap */
static const int BACKGROUND_X = (BASE_X-MIN_SPACE);
static const int BACKGROUND_Y = (BASE_Y-MIN_SPACE);
/* key mappings */
#define KEY_UP PLA_UP
#define KEY_DOWN PLA_DOWN
#define KEY_LEFT PLA_LEFT
@ -97,48 +96,58 @@
#define KEY_EXIT PLA_CANCEL
#define KEY_UNDO PLA_SELECT
/* notice how "color" is spelled :P */
#ifdef HAVE_LCD_COLOR
/* colors */
#define BACKGROUND (LCD_RGBPACK(0xfa, 0xf8, 0xef))
#define BOARD_BACKGROUND (LCD_RGBPACK(0xbb, 0xad, 0xa0))
#define TEXT_COLOR (LCD_RGBPACK(0x77, 0x6e, 0x65))
static const unsigned BACKGROUND = LCD_RGBPACK(0xfa, 0xf8, 0xef);
static const unsigned BOARD_BACKGROUND = LCD_RGBPACK(0xbb, 0xad, 0xa0);
static const unsigned TEXT_COLOR = LCD_RGBPACK(0x77, 0x6e, 0x65);
#endif
/* PLA data */
static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
/* game data */
/*** game data structures ***/
struct game_ctx_t {
int grid[GRID_SIZE][GRID_SIZE];
int score;
int cksum; /* sum of grid, XORed by score */
bool already_won;
};
unsigned int grid[GRID_SIZE][GRID_SIZE]; /* 0 = empty */
unsigned int score;
unsigned int cksum; /* sum of grid, XORed by score */
bool already_won; /* has the player gotten 2048 yet? */
} game_ctx;
static struct game_ctx_t ctx_data;
/* use a pointer to make save/load easier */
static struct game_ctx_t *ctx=&ctx_data;
static struct game_ctx_t *ctx = &game_ctx;
/*** temporary data ***/
/* temporary data */
static bool merged_grid[GRID_SIZE][GRID_SIZE];
static int old_grid[GRID_SIZE][GRID_SIZE];
static int max_numeral_height = -1;
#if LCD_DEPTH <= 1
static int max_numeral_width;
#endif
static bool loaded=false;
/* first init_game will set this, when it is exceeded, it will be updated in the slide functions */
static int best_score;
static bool loaded = false; /* has a save been loaded? */
/* the high score */
static unsigned int best_score;
static bool abnormal_exit = true;
static struct highscore highscores[NUM_SCORES];
/* returns a random int between min and max */
/***************************** UTILITY FUNCTIONS *****************************/
static inline int rand_range(int min, int max)
{
return rb->rand() % (max-min + 1) + min;
}
/* prepares to exit */
/* prepares for exit */
static void cleanup(void)
{
backlight_use_settings();
@ -154,44 +163,55 @@ static inline int rand_2_or_4(void)
return 2;
}
/* display the help text */
/* displays the help text */
static bool do_help(void)
{
#ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(LCD_WHITE);
rb->lcd_set_background(LCD_BLACK);
#endif
rb->lcd_setfont(FONT_UI);
char* help_text[]= {"2048", "", "Aim",
static char* help_text[]= {"2048", "", "Aim",
"", "Join", "the", "numbers", "to", "get", "to", "the", "2048", "tile!", "", "",
"How", "to", "Play", "",
"", "Use", "the", "directional", "keys", "to", "move", "the", "tiles.", "When",
"two", "tiles", "with", "the", "same", "number", "touch,", "they", "merge", "into", "one!"};
struct style_text style[] = {
{0, TEXT_CENTER | TEXT_UNDERLINE},
{2, C_RED},
{15, C_RED}, {16, C_RED}, {17,C_RED},
{15, C_RED},
{16, C_RED},
{17, C_RED},
LAST_STYLE_ITEM
};
return display_text(ARRAYLEN(help_text), help_text, style, NULL, true);
}
/*** the logic for sliding ***/
/* this is the helper function that does the actual tile moving */
/*** tile movement logic ***/
/* this function performs the tile movement */
static inline void slide_internal(int startx, int starty,
int stopx, int stopy,
int dx, int dy,
int lookx, int looky,
bool update_best)
{
int best_score_before=best_score;
unsigned int best_score_old = best_score;
/* loop over the rows or columns, moving the tiles in the specified direction */
for(int y = starty; y != stopy; y += dy)
{
for(int x = startx; x != stopx; x += dx)
{
if(ctx->grid[x+lookx][y+looky]==ctx->grid[x][y] && ctx->grid[x][y] && !merged_grid[x+lookx][y+looky] && !merged_grid[x][y]) /* Slide into */
if(ctx->grid[x + lookx][y + looky] == ctx->grid[x][y] &&
ctx->grid[x][y] &&
!merged_grid[x + lookx][y + looky] &&
!merged_grid[x][y]) /* merge these two tiles */
{
/* Each merged tile cannot be merged again */
merged_grid[x + lookx][y + looky] = true;
@ -206,7 +226,7 @@ static inline void slide_internal(int startx, int starty,
}
}
}
if(ctx->score>best_score_before && update_best)
if(ctx->score > best_score_old && update_best)
best_score = ctx->score;
}
@ -227,6 +247,7 @@ static void up(bool update_best)
0, -1, /* lookahead values */
update_best);
}
/* Down
0 v v v v
1 v v v v
@ -242,6 +263,7 @@ static void down(bool update_best)
0, 1,
update_best);
}
/* Left
0 < < <
1 < < <
@ -257,6 +279,7 @@ static void left(bool update_best)
-1, 0,
update_best);
}
/* Right
0 > > >
1 > > >
@ -273,8 +296,13 @@ static void right(bool update_best)
update_best);
}
/* slightly modified version of base 2 log, returns 1 when given zero, and log2(n)+1 for anything else */
/* copies old_grid to ctx->grid */
static inline void RESTORE_GRID(void)
{
memcpy(&ctx->grid, &old_grid, sizeof(ctx->grid));
}
/* slightly modified base 2 logarithm, returns 1 when given zero, and log2(n) + 1 for anything else */
static inline int ilog2(int n)
{
if(n == 0)
@ -287,17 +315,25 @@ static inline int ilog2(int n)
}
return log + 1;
}
/* low-depth displays resort to text drawing, see the #else case below */
#if LCD_DEPTH > 1
/* draws game screen + updates LCD */
static void draw(void)
{
#ifdef HAVE_LCD_COLOR
rb->lcd_set_background(BACKGROUND);
#endif
rb->lcd_clear_display();
/* draw the background */
rb->lcd_bitmap(_2048_background, BACKGROUND_X, BACKGROUND_Y, BMPWIDTH__2048_background, BMPWIDTH__2048_background);
rb->lcd_bitmap(_2048_background,
BACKGROUND_X, BACKGROUND_Y,
BMPWIDTH__2048_background, BMPWIDTH__2048_background);
/*
grey_gray_bitmap(_2048_background, BACKGROUND_X, BACKGROUND_Y, BMPWIDTH__2048_background, BMPHEIGHT__2048_background);
@ -316,14 +352,17 @@ static void draw(void)
BMPHEIGHT__2048_tiles, BMPHEIGHT__2048_tiles); /* size of the cut section */
}
}
/* draw the title */
char buf[32];
#ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(TEXT_COLOR);
#endif
rb->snprintf(buf, 31, "%d", WINNING_TILE);
/* check if the title will go into the grid */
rb->snprintf(buf, sizeof(buf), "%d", WINNING_TILE);
/* check if the title will overlap the grid */
int w, h;
rb->lcd_setfont(FONT_UI);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
@ -340,17 +379,24 @@ static void draw(void)
h = 0;
}
}
if(draw_title)
rb->lcd_putsxy(TITLE_X, TITLE_Y, buf);
int score_y = TITLE_Y + h + VERT_SPACING;
/* draw the score */
rb->snprintf(buf, 31, "Score: %d", ctx->score);
rb->snprintf(buf, sizeof(buf), "Score: %d", ctx->score);
#ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(LCD_WHITE);
rb->lcd_set_background(BOARD_BACKGROUND);
#endif
rb->lcd_setfont(FONT_UI);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
/* try making the score fit */
if(w + SCORE_X >= BACKGROUND_X && h + SCORE_Y >= BACKGROUND_Y)
{
/* score overflows */
@ -362,28 +408,28 @@ static void draw(void)
goto draw_lbl;
/* now try with S: and FONT_UI */
rb->snprintf(buf, 31, "S: %d", ctx->score);
rb->snprintf(buf, sizeof(buf), "S: %d", ctx->score);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
rb->lcd_setfont(FONT_UI);
if(w + SCORE_X < BACKGROUND_X)
goto draw_lbl;
/* now try with S: and FONT_SYSFIXED */
rb->snprintf(buf, 31, "S: %d", ctx->score);
rb->snprintf(buf, sizeof(buf), "S: %d", ctx->score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED);
if(w + SCORE_X < BACKGROUND_X)
goto draw_lbl;
/* then try without Score: and FONT_UI */
rb->snprintf(buf, 31, "%d", ctx->score);
rb->snprintf(buf, sizeof(buf), "%d", ctx->score);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
rb->lcd_setfont(FONT_UI);
if(w + SCORE_X < BACKGROUND_X)
goto draw_lbl;
/* as a last resort, don't use Score: and use the system font */
rb->snprintf(buf, 31, "%d", ctx->score);
rb->snprintf(buf, sizeof(buf), "%d", ctx->score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED);
if(w + SCORE_X < BACKGROUND_X)
@ -391,16 +437,20 @@ static void draw(void)
else
goto skip_draw_score;
}
draw_lbl:
rb->lcd_putsxy(SCORE_X, score_y, buf);
score_y += h + VERT_SPACING;
/* draw the best score */
skip_draw_score:
rb->snprintf(buf, 31, "Best: %d", best_score);
rb->snprintf(buf, sizeof(buf), "Best: %d", best_score);
#ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(LCD_WHITE);
rb->lcd_set_background(BOARD_BACKGROUND);
#endif
rb->lcd_setfont(FONT_UI);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
if(w + BEST_SCORE_X >= BACKGROUND_X && h + BEST_SCORE_Y >= BACKGROUND_Y)
@ -414,28 +464,28 @@ skip_draw_score:
goto draw_best;
/* now try with S: and FONT_UI */
rb->snprintf(buf, 31, "B: %d", best_score);
rb->snprintf(buf, sizeof(buf), "B: %d", best_score);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
rb->lcd_setfont(FONT_UI);
if(w + BEST_SCORE_X < BACKGROUND_X)
goto draw_best;
/* now try with S: and FONT_SYSFIXED */
rb->snprintf(buf, 31, "B: %d", best_score);
rb->snprintf(buf, sizeof(buf), "B: %d", best_score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED);
if(w + BEST_SCORE_X < BACKGROUND_X)
goto draw_best;
/* then try without Score: and FONT_UI */
rb->snprintf(buf, 31, "%d", best_score);
rb->snprintf(buf, sizeof(buf), "%d", best_score);
rb->font_getstringsize(buf, &w, &h, FONT_UI);
rb->lcd_setfont(FONT_UI);
if(w + BEST_SCORE_X < BACKGROUND_X)
goto draw_best;
/* as a last resort, don't use Score: and use the system font */
rb->snprintf(buf, 31, "%d", best_score);
rb->snprintf(buf, sizeof(buf), "%d", best_score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED);
if(w + BEST_SCORE_X < BACKGROUND_X)
@ -445,29 +495,38 @@ skip_draw_score:
}
draw_best:
rb->lcd_putsxy(BEST_SCORE_X, score_y, buf);
skip_draw_best:
rb->lcd_update();
/* revert the font back */
/* revert the font */
rb->lcd_setfont(WHAT_FONT);
}
#else /* LCD_DEPTH > 1 */
/* 1-bit display :( */
/* bitmaps are unreadable with these screens, so just resort to text */
/* bitmaps are unreadable on these screens, so just resort to text-based drawing */
static void draw(void)
{
rb->lcd_clear_display();
/* Draw the grid */
/* find the biggest tile */
int biggest_tile=-1;
unsigned int biggest_tile = 0;
for(int x = 0; x < GRID_SIZE; ++x)
{
for(int y = 0; y < GRID_SIZE; ++y)
if(ctx->grid[x][y] > biggest_tile)
biggest_tile = ctx->grid[x][y];
}
char str[32];
rb->snprintf(str, 31,"%d", biggest_tile);
int biggest_tile_width=rb->strlen(str)*rb->font_get_width(rb->font_get(WHAT_FONT), '0')+MIN_SPACE;
char buf[32];
rb->snprintf(buf, 32, "%d", biggest_tile);
int biggest_tile_width = rb->strlen(buf) * rb->font_get_width(rb->font_get(WHAT_FONT), '0') + MIN_SPACE;
for(int y = 0; y < GRID_SIZE; ++y)
{
for(int x = 0; x < GRID_SIZE; ++x)
@ -476,30 +535,34 @@ static void draw(void)
{
if(ctx->grid[x][y] > biggest_tile)
biggest_tile = ctx->grid[x][y];
rb->snprintf(str,31,"%d", ctx->grid[x][y]);
rb->lcd_putsxy(biggest_tile_width*x,y*max_numeral_height+max_numeral_height,str);
rb->snprintf(buf, 32, "%d", ctx->grid[x][y]);
rb->lcd_putsxy(biggest_tile_width * x, y * max_numeral_height + max_numeral_height, buf);
}
}
}
/* Now draw the score, and the game title */
rb->snprintf(str, 31, "Score: %d", ctx->score);
int str_width, str_height;
rb->font_getstringsize(str, &str_width, &str_height, WHAT_FONT);
int score_leftmost=LCD_WIDTH-str_width-1;
rb->snprintf(buf, 32, "Score: %d", ctx->score);
int buf_width, buf_height;
rb->font_getstringsize(buf, &buf_width, &buf_height, WHAT_FONT);
int score_leftmost = LCD_WIDTH - buf_width - 1;
/* Check if there is enough space to display "Score: ", otherwise, only display the score */
if(score_leftmost >= 0)
rb->lcd_putsxy(score_leftmost,0,str);
rb->lcd_putsxy(score_leftmost, 0, buf);
else
rb->lcd_putsxy(score_leftmost,0,str+rb->strlen("Score: "));
/* Reuse the same string for the title */
rb->lcd_putsxy(score_leftmost, 0, buf + rb->strlen("Score: "));
rb->snprintf(buf, 32, "%d", WINNING_TILE);
rb->font_getstringsize(buf, &buf_width, &buf_height, WHAT_FONT);
if(buf_width < score_leftmost)
rb->lcd_putsxy(0, 0, buf);
rb->snprintf(str, 31, "%d", WINNING_TILE);
rb->font_getstringsize(str, &str_width, &str_height, WHAT_FONT);
if(str_width<score_leftmost)
rb->lcd_putsxy(0,0,str);
rb->lcd_update();
}
#endif /* LCD_DEPTH > 1 */
/* place a 2 or 4 in a random empty space */
static void place_random(void)
{
@ -512,61 +575,60 @@ static void place_random(void)
if(!ctx->grid[x][y])
{
xpos[back] = x;
ypos[back]=y;
++back;
ypos[back++] = y;
}
}
if(!back)
/* no empty spaces */
return;
int idx = rand_range(0, back - 1);
ctx->grid[ xpos[idx] ][ ypos[idx] ] = rand_2_or_4();
}
/* copies old_grid to ctx->grid */
static void restore_old_grid(void)
{
memcpy(&ctx->grid, &old_grid, sizeof(int)*SPACES);
}
/* checks for a win or loss */
static bool check_gameover(void)
{
/* first, check for a loss */
int oldscore = ctx->score;
bool have_legal_move = false;
memset(&merged_grid, 0, SPACES * sizeof(bool));
up(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
if(memcmp(&old_grid, &ctx->grid, sizeof(ctx->grid)))
{
restore_old_grid();
RESTORE_GRID();
ctx->score = oldscore;
have_legal_move = true;
}
restore_old_grid();
RESTORE_GRID();
memset(&merged_grid, 0, SPACES * sizeof(bool));
down(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
if(memcmp(&old_grid, &ctx->grid, sizeof(ctx->grid)))
{
restore_old_grid();
RESTORE_GRID();
ctx->score = oldscore;
have_legal_move = true;
}
restore_old_grid();
RESTORE_GRID();
memset(&merged_grid, 0, SPACES * sizeof(bool));
left(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
if(memcmp(&old_grid, &ctx->grid, sizeof(ctx->grid)))
{
restore_old_grid();
RESTORE_GRID();
ctx->score = oldscore;
have_legal_move = true;
}
restore_old_grid();
RESTORE_GRID();
memset(&merged_grid, 0, SPACES * sizeof(bool));
right(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
if(memcmp(&old_grid, &ctx->grid, sizeof(ctx->grid)))
{
restore_old_grid();
RESTORE_GRID();
ctx->score = oldscore;
have_legal_move = true;
}
@ -574,10 +636,11 @@ static bool check_gameover(void)
if(!have_legal_move)
{
/* no more legal moves */
draw(); /* Shame the player :) */
draw(); /* Shame the player */
rb->splash(HZ*2, "Game Over!");
return true;
}
for(int y = 0;y < GRID_SIZE; ++y)
{
for(int x = 0; x < GRID_SIZE; ++x)
@ -588,7 +651,6 @@ static bool check_gameover(void)
draw();
ctx->already_won = true;
rb->splash(HZ*2,"You win!");
/* don't let the user quit here :) */
}
}
}
@ -611,10 +673,11 @@ static void init_game(bool newgame)
best_score = highscores[0].score;
if(loaded && ctx->score > best_score)
best_score = ctx->score;
if(newgame)
{
/* initialize the game context */
memset(ctx->grid, 0, sizeof(int)*SPACES);
memset(ctx->grid, 0, sizeof(ctx->grid));
for(int i = 0; i < NUM_STARTING_TILES; ++i)
{
place_random();
@ -622,18 +685,22 @@ static void init_game(bool newgame)
ctx->score = 0;
ctx->already_won = false;
}
/* using the menu resets the font */
/* set it again here */
rb->lcd_setfont(WHAT_FONT);
/* Now calculate font sizes */
/* Now get the height of the font */
rb->font_getstringsize("0123456789", NULL, &max_numeral_height, WHAT_FONT);
max_numeral_height += VERT_SPACING;
#if LCD_DEPTH <= 1
max_numeral_width = rb->font_get_width(rb->font_get(WHAT_FONT), '0');
#endif
backlight_ignore_timeout();
rb->lcd_clear_display();
draw();
}
@ -646,11 +713,16 @@ static void save_game(void)
{
return;
}
/* calculate checksum */
ctx->cksum = 0;
for(int x = 0; x < GRID_SIZE; ++x)
for(int y = 0; y < GRID_SIZE; ++y)
ctx->cksum += ctx->grid[x][y];
ctx->cksum ^= ctx->score;
rb->write(fd, ctx, sizeof(struct game_ctx_t));
rb->close(fd);
rb->lcd_update();
@ -666,24 +738,31 @@ static bool load_game(void)
rb->remove(RESUME_FILE);
return false;
}
int numread = rb->read(fd, ctx, sizeof(struct game_ctx_t));
int calc=0;
/* verify checksum */
unsigned int calc = 0;
for(int x = 0; x < GRID_SIZE; ++x)
for(int y = 0; y < GRID_SIZE; ++y)
calc += ctx->grid[x][y];
calc ^= ctx->score;
if(numread == sizeof(struct game_ctx_t) && calc == ctx->cksum)
++success;
rb->close(fd);
rb->remove(RESUME_FILE);
return (success==1);
return (success > 0);
}
/* update the highscores with ctx->score */
static void hs_check_update(bool noshow)
{
/* first, find the biggest tile to show as the level */
int biggest=0;
unsigned int biggest = 0;
for(int x = 0; x < GRID_SIZE; ++x)
{
for(int y = 0; y < GRID_SIZE; ++y)
@ -692,6 +771,7 @@ static void hs_check_update(bool noshow)
biggest = ctx->grid[x][y];
}
}
int hs_idx = highscore_update(ctx->score,biggest, "", highscores,NUM_SCORES);
if(!noshow)
{
@ -782,12 +862,14 @@ static void exit_handler(void)
#endif
return;
}
static bool check_hs;
/* main game loop */
static enum plugin_status do_game(bool newgame)
{
init_game(newgame);
rb_atexit(&exit_handler);
rb_atexit(exit_handler);
int made_move = 0;
while(1)
{
@ -797,9 +879,12 @@ static enum plugin_status do_game(bool newgame)
/* Wait for a button press */
int button = pluginlib_getaction(-1, plugin_contexts, ARRAYLEN(plugin_contexts));
made_move = 0;
memset(&merged_grid, 0, SPACES*sizeof(bool));
memcpy(&old_grid, &ctx->grid, sizeof(int)*SPACES);
int grid_before_anim_step[GRID_SIZE][GRID_SIZE];
unsigned int grid_before_anim_step[GRID_SIZE][GRID_SIZE];
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true); /* doing work now... */
#endif
@ -808,9 +893,9 @@ static enum plugin_status do_game(bool newgame)
case KEY_UP:
for(int i = 0; i < GRID_SIZE - 1; ++i)
{
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
memcpy(grid_before_anim_step, ctx->grid, sizeof(ctx->grid));
up(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(ctx->grid)))
{
rb->sleep(ANIM_SLEEPTIME);
draw();
@ -821,9 +906,9 @@ static enum plugin_status do_game(bool newgame)
case KEY_DOWN:
for(int i = 0; i < GRID_SIZE - 1; ++i)
{
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
memcpy(grid_before_anim_step, ctx->grid, sizeof(ctx->grid));
down(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(ctx->grid)))
{
rb->sleep(ANIM_SLEEPTIME);
draw();
@ -834,9 +919,9 @@ static enum plugin_status do_game(bool newgame)
case KEY_LEFT:
for(int i = 0; i < GRID_SIZE - 1; ++i)
{
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
memcpy(grid_before_anim_step, ctx->grid, sizeof(ctx->grid));
left(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(ctx->grid)))
{
rb->sleep(ANIM_SLEEPTIME);
draw();
@ -847,9 +932,9 @@ static enum plugin_status do_game(bool newgame)
case KEY_RIGHT:
for(int i = 0; i < GRID_SIZE - 1; ++i)
{
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
memcpy(grid_before_anim_step, ctx->grid, sizeof(ctx->grid));
right(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(ctx->grid)))
{
rb->sleep(ANIM_SLEEPTIME);
draw();
@ -866,7 +951,6 @@ static enum plugin_status do_game(bool newgame)
init_game(true);
made_move = 1;
continue;
break;
case 2: /* quit without saving */
check_hs = true;
rb->remove(RESUME_FILE);
@ -879,18 +963,19 @@ static enum plugin_status do_game(bool newgame)
break;
default:
{
exit_on_usb(button); /* handles poweroff and USB events */
exit_on_usb(button); /* handle poweroff and USB events */
break;
}
}
if(made_move)
{
/* Check if we actually moved, then add random */
if(memcmp(&old_grid, ctx->grid, sizeof(int)*SPACES))
/* Check if any tiles moved, then add random */
if(memcmp(&old_grid, ctx->grid, sizeof(ctx->grid)))
{
place_random();
}
memcpy(&old_grid, ctx->grid, sizeof(int)*SPACES);
memcpy(&old_grid, ctx->grid, sizeof(ctx->grid));
if(check_gameover())
return PLUGIN_OK;
draw();
@ -917,22 +1002,30 @@ static enum plugin_status do_2048_menu(void)
{
int sel = 0;
loaded = load_game();
MENUITEM_STRINGLIST(menu,"2048 Menu", mainmenu_cb, "Resume Game", "Start New Game","High Scores","Playback Control", "Help", "Quit without Saving", "Quit");
MENUITEM_STRINGLIST(menu,
"2048 Menu",
mainmenu_cb,
"Resume Game",
"Start New Game",
"High Scores",
"Playback Control",
"Help",
"Quit without Saving",
"Quit");
bool quit = false;
while(!quit)
{
int item;
switch(item=rb->do_menu(&menu,&sel,NULL,false))
switch(rb->do_menu(&menu, &sel, NULL, false))
{
case 0: /* Start new game or resume a game */
case 1:
{
if(item==1 && loaded)
if(sel == 1 && loaded)
{
if(!confirm_quit())
break;
}
enum plugin_status ret=do_game(item==1);
enum plugin_status ret = do_game(sel == 1);
switch(ret)
{
case PLUGIN_OK:
@ -977,6 +1070,8 @@ static enum plugin_status do_2048_menu(void)
}
return PLUGIN_OK;
}
/* plugin entry point */
enum plugin_status plugin_start(const void* param)
{
(void)param;
@ -986,8 +1081,11 @@ enum plugin_status plugin_start(const void* param)
/* now start the game menu */
enum plugin_status ret = do_2048_menu();
highscore_save(HISCORES_FILE, highscores, NUM_SCORES);
cleanup();
abnormal_exit = false;
return ret;
}