diff --git a/applications/plugins/game2048/2048.png b/applications/plugins/game2048/2048.png deleted file mode 100644 index 6f46d4de5..000000000 Binary files a/applications/plugins/game2048/2048.png and /dev/null differ diff --git a/applications/plugins/game2048/application.fam b/applications/plugins/game2048/application.fam deleted file mode 100644 index 61e474046..000000000 --- a/applications/plugins/game2048/application.fam +++ /dev/null @@ -1,12 +0,0 @@ -App( - appid="2048", - name="2048 (Original)", - apptype=FlipperAppType.EXTERNAL, - entry_point="game_2048_app", - cdefines=["APP_2048_GAME"], - requires=["gui"], - stack_size=2 * 1024, - order=10, - fap_icon="2048.png", - fap_category="Games", -) diff --git a/applications/plugins/game2048/font.c b/applications/plugins/game2048/font.c deleted file mode 100644 index 9acfe8d23..000000000 --- a/applications/plugins/game2048/font.c +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include - -/* 7px 3 width digit font by Sefjor - * digit encoding example - *7 ¦¦¦ 111 - *6 ¦ ¦ 101 - *5 ¦ ¦ 101 - *4 ¦ ¦ 101 - *3 ¦ ¦ 101 - *2 ¦ ¦ 101 - *1 ¦¦¦ 111 - *0 000 this string is empty, used to align - * ? ? ? - * FE 82 FE //0 - */ - -static uint8_t font[10][3] = { - {0xFE, 0x82, 0xFE}, // 0; - {0x00, 0xFE, 0x00}, // 1; - {0xF2, 0x92, 0x9E}, // 2; - {0x92, 0x92, 0xFE}, // 3; - {0x1E, 0x10, 0xFE}, // 4; - {0x9E, 0x92, 0xF2}, // 5; - {0xFE, 0x92, 0xF2}, // 6; - {0x02, 0x02, 0xFE}, // 7; - {0xFE, 0x92, 0xFE}, // 8; - {0x9E, 0x92, 0xFE}, // 9; -}; - -#define FONT_HEIGHT 8 -#define FONT_WIDTH 3 - -static void game_2048_draw_black_point(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_dot(canvas, x, y); -} - -static void game_2048_draw_white_square(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, x, y, 15 - 1, 15 - 3); -} - -static void _game_2048_draw_column( - Canvas* const canvas, - int digit, - int coord_x, - int coord_y, - uint8_t column) { - for(int x = 0; x < FONT_HEIGHT; ++x) { - bool is_filled = (font[digit][column] >> x) & 0x1; - if(is_filled) { - game_2048_draw_black_point(canvas, coord_x, coord_y + x); - } - } -} - -static uint8_t - _game_2048_draw_digit(Canvas* const canvas, uint8_t digit, uint8_t coord_x, uint8_t coord_y) { - uint8_t x_shift = 0; - - if(digit != 1) { - for(int column = 0; column < FONT_WIDTH; column++) { - _game_2048_draw_column(canvas, digit, coord_x + column, coord_y, column); - } - x_shift = 3; - } else { - _game_2048_draw_column(canvas, digit, coord_x, coord_y, true); - x_shift = 1; - } - - return x_shift; -} - -/* We drawing text field with 1px white border - * at given coords. Total size is: - * x = 9 = 1 + 7 + 1 - * y = 1 + total text width + 1 - */ - -/* - * Returns array of digits and it's size, - * digits should be at least 4 size - * works from 1 to 9999 - */ -static void _game_2048_parse_number(uint16_t number, uint8_t* digits, uint8_t* size) { - *size = 0; - uint16_t divider = 1000; - //find first digit, result is highest divider - while(number / divider == 0) { - divider /= 10; - if(divider == 0) { - break; - } - } - - for(int i = 0; divider != 0; i++) { - digits[i] = number / divider; - number %= divider; - *size += 1; - divider /= 10; - } -} - -uint8_t _game_2048_calculate_shift(uint16_t num) { - uint8_t shift = 0; - switch(num) { - case 1: - shift = 7; - break; - case 2: - case 4: - case 8: - shift = 6; - break; - case 16: - shift = 5; - break; - case 32: - case 64: - shift = 4; - break; - case 128: - shift = 3; - break; - case 256: - shift = 2; - break; - case 512: - shift = 3; - break; - case 1024: - shift = 2; - break; - } - return shift; -} - -void game_2048_draw_number(Canvas* const canvas, uint8_t x, uint8_t y, int number) { - uint8_t digits[4]; - uint8_t size; - - _game_2048_parse_number(number, digits, &size); - if(number > 512) { - game_2048_draw_white_square(canvas, x, y); - } - - x += _game_2048_calculate_shift(number); - y += 4; - for(int i = 0; i < size; ++i) { - x += _game_2048_draw_digit(canvas, digits[i], x, y); - x++; - } -} \ No newline at end of file diff --git a/applications/plugins/game2048/font.h b/applications/plugins/game2048/font.h deleted file mode 100644 index 500123ac3..000000000 --- a/applications/plugins/game2048/font.h +++ /dev/null @@ -1,3 +0,0 @@ -#include - -void game_2048_draw_number(Canvas* const canvas, uint8_t x, uint8_t y, int number); \ No newline at end of file diff --git a/applications/plugins/game2048/game_2048.c b/applications/plugins/game2048/game_2048.c deleted file mode 100644 index 706b95ce5..000000000 --- a/applications/plugins/game2048/game_2048.c +++ /dev/null @@ -1,495 +0,0 @@ -#include -#include -#include -#include -#include - -#include "font.h" - -#define DEBUG false -/* - 0 empty - 1 2 - 2 4 - 3 8 - 4 16 - 5 32 - 6 64 - 7 128 - 8 256 - 9 512 -10 1024 -11 2048 -12 4096 -... - */ -typedef uint8_t cell_state; - -/* DirectionLeft <-- -┌╌╌╌╌â”┌╌╌╌╌â”┌╌╌╌╌â”┌╌╌╌╌┠-╎ ╎╎ ╎╎ ╎╎ ╎ -└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘ -┌╌╌╌╌â”┌╌╌╌╌â”┌╌╌╌╌â”┌╌╌╌╌┠-╎ ╎╎ ╎╎ ╎╎ ╎ -└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘ -┌╌╌┌╌╌╌╌â”╌╌â”┌╌╌╌╌â”┌╌╌╌╌┠-╎ 2╎ 2 ╎ ╎╎ ╎╎ ╎ -└╌╌└╌╌╌╌┘╌╌┘└╌╌╌╌┘└╌╌╌╌┘ -┌╌╌┌╌╌╌╌â”┌╌╌┌╌╌╌╌â”┌╌╌╌╌┠-╎ 4╎ 4 ╎╎ 2╎ 2 ╎╎ ╎ -└╌╌└╌╌╌╌┘└╌╌└╌╌╌╌┘└╌╌╌╌┘ -*/ -typedef enum { - DirectionIdle, - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -typedef struct { - uint8_t y; // 0 <= y <= 3 - uint8_t x; // 0 <= x <= 3 -} Point; - -typedef struct { - uint32_t gameScore; - uint32_t highScore; -} Score; - -typedef struct { - /* - +----X - | - | field[x][y] - Y - */ - uint8_t field[4][4]; - - uint8_t next_field[4][4]; - - Score score; // original scoring - - Direction direction; - /* - field { - animation-timing-function: linear; - animation-duration: 300ms; - } - */ - uint32_t animation_start_ticks; - - Point keyframe_from[4][4]; - - Point keyframe_to[4][4]; - - bool debug; - -} GameState; - -#define XtoPx(x) (33 + x * 15) - -#define YtoPx(x) (1 + y * 15) - -static void game_2048_render_callback(Canvas* const canvas, ValueMutex* const vm) { - const GameState* game_state = acquire_mutex(vm, 25); - if(game_state == NULL) { - return; - } - - // Before the function is called, the state is set with the canvas_reset(canvas) - - if(game_state->direction == DirectionIdle) { - for(uint8_t y = 0; y < 4; y++) { - for(uint8_t x = 0; x < 4; x++) { - uint8_t field = game_state->field[y][x]; - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, XtoPx(x), YtoPx(y), 16, 16); - if(field != 0) { - game_2048_draw_number(canvas, XtoPx(x), YtoPx(y), 1 << field); - } - } - } - - // display score - char buffer[12]; - snprintf(buffer, sizeof(buffer), "%lu", game_state->score.gameScore); - canvas_draw_str_aligned(canvas, 127, 8, AlignRight, AlignBottom, buffer); - - if(game_state->score.highScore > 0) { - char buffer2[12]; - snprintf(buffer2, sizeof(buffer2), "%lu", game_state->score.highScore); - canvas_draw_str_aligned(canvas, 127, 62, AlignRight, AlignBottom, buffer2); - } - } else { // if animation - // for animation - // (osKernelGetSysTimerCount() - game_state->animation_start_ticks) / osKernelGetSysTimerFreq(); - - // TODO: end animation event/callback/set AnimationIdle - } - - release_mutex(vm, game_state); -} - -static void - game_2048_input_callback(const InputEvent* const input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -// if return false then Game Over -static bool game_2048_set_new_number(GameState* const game_state) { - uint8_t empty = 0; - for(uint8_t y = 0; y < 4; y++) { - for(uint8_t x = 0; x < 4; x++) { - if(game_state->field[y][x] == 0) { - empty++; - } - } - } - - if(empty == 0) { - return false; - } - - if(empty == 1) { - // If it is 1 move before losing, we help the player and get rid of randomness. - for(uint8_t y = 0; y < 4; y++) { - for(uint8_t x = 0; x < 4; x++) { - if(game_state->field[y][x] == 0) { - bool haveFour = - // +----X - // | - // | field[x][y], 0 <= x, y <= 3 - // Y - - // up == 4 or - (y > 0 && game_state->field[y - 1][x] == 2) || - // right == 4 or - (x < 3 && game_state->field[y][x + 1] == 2) || - // down == 4 - (y < 3 && game_state->field[y + 1][x] == 2) || - // left == 4 - (x > 0 && game_state->field[y][x - 1] == 2); - - if(haveFour) { - game_state->field[y][x] = 2; - return true; - } - - game_state->field[y][x] = 1; - return true; - } - } - } - } - - uint8_t target = rand() % empty; - uint8_t twoOrFore = rand() % 4 < 3; - for(uint8_t y = 0; y < 4; y++) { - for(uint8_t x = 0; x < 4; x++) { - if(game_state->field[y][x] == 0) { - if(target == 0) { - if(twoOrFore) { - game_state->field[y][x] = 1; // 2^1 == 2 75% - } else { - game_state->field[y][x] = 2; // 2^2 == 4 25% - } - goto exit; - } - target--; - } - } - } -exit: - return true; -} - -// static void game_2048_process_row(uint8_t before[4], uint8_t *(after[4])) { -// // move 1 row left. -// for(uint8_t i = 0; i <= 2; i++) { -// if(before[i] != 0 && before[i] == before[i + 1]) { -// before[i]++; -// before[i + 1] = 0; -// i++; -// } -// } -// for(uint8_t i = 0, j = 0; i <= 3; i++) { -// if (before[i] != 0) { -// before[j] = before[i]; -// i++; -// } -// } -// } - -static void game_2048_process_move(GameState* const game_state) { - memset(game_state->next_field, 0, sizeof(game_state->next_field)); - // +----X - // | - // | field[x][y], 0 <= x, y <= 3 - // Y - - // up - if(game_state->direction == DirectionUp) { - for(uint8_t x = 0; x < 4; x++) { - uint8_t next_y = 0; - for(int8_t y = 0; y < 4; y++) { - uint8_t field = game_state->field[y][x]; - if(field == 0) { - continue; - } - - if(game_state->next_field[next_y][x] == 0) { - game_state->next_field[next_y][x] = field; - continue; - } - - if(field == game_state->next_field[next_y][x]) { - game_state->next_field[next_y][x]++; - game_state->score.gameScore += pow(2, game_state->next_field[next_y][x]); - if(game_state->next_field[next_y][x] == 11 && !game_state->debug) { - DOLPHIN_DEED(getRandomDeed()); - } // get some xp for making a 2048 tile - next_y++; - continue; - } - - next_y++; - game_state->next_field[next_y][x] = field; - } - } - } - - // right - if(game_state->direction == DirectionRight) { - for(uint8_t y = 0; y < 4; y++) { - uint8_t next_x = 3; - for(int8_t x = 3; x >= 0; x--) { - uint8_t field = game_state->field[y][x]; - if(field == 0) { - continue; - } - - if(game_state->next_field[y][next_x] == 0) { - game_state->next_field[y][next_x] = field; - continue; - } - - if(field == game_state->next_field[y][next_x]) { - game_state->next_field[y][next_x]++; - game_state->score.gameScore += pow(2, game_state->next_field[y][next_x]); - if(game_state->next_field[y][next_x] == 11 && !game_state->debug) { - DOLPHIN_DEED(getRandomDeed()); - } // get some xp for making a 2048 tile - next_x--; - continue; - } - - next_x--; - game_state->next_field[y][next_x] = field; - } - } - } - - // down - if(game_state->direction == DirectionDown) { - for(uint8_t x = 0; x < 4; x++) { - uint8_t next_y = 3; - for(int8_t y = 3; y >= 0; y--) { - uint8_t field = game_state->field[y][x]; - if(field == 0) { - continue; - } - - if(game_state->next_field[next_y][x] == 0) { - game_state->next_field[next_y][x] = field; - continue; - } - - if(field == game_state->next_field[next_y][x]) { - game_state->next_field[next_y][x]++; - game_state->score.gameScore += pow(2, game_state->next_field[next_y][x]); - if(game_state->next_field[next_y][x] == 11 && !game_state->debug) { - DOLPHIN_DEED(getRandomDeed()); - } // get some xp for making a 2048 tile - next_y--; - continue; - } - - next_y--; - game_state->next_field[next_y][x] = field; - } - } - } - - // 0, 0, 1, 1 - // 1, 0, 0, 0 - - // left - if(game_state->direction == DirectionLeft) { - for(uint8_t y = 0; y < 4; y++) { - uint8_t next_x = 0; - for(uint8_t x = 0; x < 4; x++) { - uint8_t field = game_state->field[y][x]; - if(field == 0) { - continue; - } - - if(game_state->next_field[y][next_x] == 0) { - game_state->next_field[y][next_x] = field; - continue; - } - - if(field == game_state->next_field[y][next_x]) { - game_state->next_field[y][next_x]++; - game_state->score.gameScore += pow(2, game_state->next_field[y][next_x]); - if(game_state->next_field[y][next_x] == 11 && !game_state->debug) { - DOLPHIN_DEED(getRandomDeed()); - } // get some xp for making a 2048 tile - next_x++; - continue; - } - - next_x++; - game_state->next_field[y][next_x] = field; - } - } - } - - // - game_state->direction = DirectionIdle; - memcpy(game_state->field, game_state->next_field, sizeof(game_state->field)); - // -} - -static void game_2048_restart(GameState* const game_state) { - game_state->debug = DEBUG; - - // check score - if(game_state->score.gameScore > game_state->score.highScore) { - game_state->score.highScore = game_state->score.gameScore; - } - - // clear all cells - for(uint8_t y = 0; y < 4; y++) { - for(uint8_t x = 0; x < 4; x++) { - game_state->field[y][x] = 0; - } - } - - // start next game - game_state->score.gameScore = 0; - game_2048_set_new_number(game_state); - game_2048_set_new_number(game_state); -} - -int32_t game_2048_app(void* p) { - UNUSED(p); - int32_t return_code = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - GameState* game_state = malloc(sizeof(GameState)); - - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, game_state, sizeof(GameState))) { - return_code = 255; - goto free_and_exit; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set( - view_port, (ViewPortDrawCallback)game_2048_render_callback, &state_mutex); - view_port_input_callback_set( - view_port, (ViewPortInputCallback)game_2048_input_callback, event_queue); - - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - game_state->direction = DirectionIdle; - game_2048_restart(game_state); - - if(game_state->debug) { - game_state->field[0][0] = 0; - game_state->field[0][1] = 0; - game_state->field[0][2] = 0; - game_state->field[0][3] = 0; - - game_state->field[1][0] = 1; - game_state->field[1][1] = 2; - game_state->field[1][2] = 3; - game_state->field[1][3] = 4; - - game_state->field[2][0] = 5; - game_state->field[2][1] = 6; - game_state->field[2][2] = 7; - game_state->field[2][3] = 8; - - game_state->field[3][0] = 9; - game_state->field[3][1] = 10; - game_state->field[3][2] = 11; - game_state->field[3][3] = 12; - } - - InputEvent event; - for(bool loop = true; loop;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - GameState* game_state = (GameState*)acquire_mutex_block(&state_mutex); - - if(event_status == FuriStatusOk) { - if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyUp: - game_state->direction = DirectionUp; - game_2048_process_move(game_state); - game_2048_set_new_number(game_state); - break; - case InputKeyDown: - game_state->direction = DirectionDown; - game_2048_process_move(game_state); - game_2048_set_new_number(game_state); - break; - case InputKeyRight: - game_state->direction = DirectionRight; - game_2048_process_move(game_state); - game_2048_set_new_number(game_state); - break; - case InputKeyLeft: - game_state->direction = DirectionLeft; - game_2048_process_move(game_state); - game_2048_set_new_number(game_state); - break; - case InputKeyOk: - game_state->direction = DirectionIdle; - break; - case InputKeyBack: - loop = false; - break; - default: - break; - } - } else if(event.type == InputTypeLong) { - if(event.key == InputKeyOk) { - game_state->direction = DirectionIdle; - game_2048_restart(game_state); - } - } - } - - view_port_update(view_port); - release_mutex(&state_mutex, game_state); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - delete_mutex(&state_mutex); - -free_and_exit: - free(game_state); - furi_message_queue_free(event_queue); - - return return_code; -} \ No newline at end of file