blk_box_tc/main/steps/step2.cpp
2024-08-10 11:44:27 -05:00

554 lines
16 KiB
C++

#include "step2.h"
static const char *TAG = "step2";
static lv_obj_t* scr;
static lv_style_t scr_style;
static lv_obj_t* img;
static bool invisible_blocks = false;
static bool text_output = false;
static const int height = 22;
static const int width = 10;
static int board[height][width] = {0};
static lv_obj_t* visual_board[height][width] = {0};
static lv_obj_t* line_clear_img;
static const void* LINE_CLEAR_SRC = (void*)"A:/sdcard/clear.bin";
static const void* BACKGROUND_SRC = (void*)"A:/sdcard/bg.bin";
// LV_IMG_DECLARE(background);
// static const void* BACKGROUND_SRC = (void*)&background;
static const char* PIECE_IMG_SRC[] = {
NULL,
"A:/sdcard/lb.bin",
"A:/sdcard/db.bin",
"A:/sdcard/orange.bin",
"A:/sdcard/yellow.bin",
"A:/sdcard/green.bin",
"A:/sdcard/purple.bin",
"A:/sdcard/red.bin",
};
static bool game = true;
static int target_score = 0;
static int score = 0;
static int piece = 0;
static int piece_rotation = 0;
static int piece_location[] = {0, 0};
static int piece_nodes[4][2] = {
{0, 0},
{0, 0},
{0, 0},
{0, 0},
};
lv_obj_t* piece_imgs[4] = {};
TaskHandle_t music_handle;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> piece_dist(2, 7);
static void generate_block(void);
static void show_board(void);
static void get_node_locations(void);
static void line_clear(int hi);
static void check_line_clears(void);
static void place_piece(void);
static void move_left(void);
static void move_right(void);
static void drop(void);
static void rotate_block(void);
static void update_score(void);
static void clear_board(void);
static int bbcc(int i) { // [0,1,2,3] -> [ 0, 0,+1,+1]
const int map[] = {0, 0, 1, 1};
return map[i];
}
static int bccb(int i) { // [0,1,2,3] -> [ 0,+1,+1, 0]
const int map[] = {0, 1, 1, 0};
return map[i];
}
static int cbbc(int i) { // [0,1,2,3] -> [+1, 0, 0,+1]
const int map[] = {1, 0, 0, 1};
return map[i];
}
static int ccbb(int i) { // [0,1,2,3] -> [+1,+1, 0, 0]
const int map[] = {1, 1, 0, 0};
return map[i];
}
static int acca(int i) { // [0,1,2,3] -> [-1,+1,+1,-1]
const int map[] = {-1, 1, 1, -1};
return map[i];
}
static int aacc(int i) { // [0,1,2,3] -> [-1,-1,+1,+1]
const int map[] = {-1, -1, 1, 1};
return map[i];
}
static int babc(int i) { // [0,1,2,3] -> [ 0,-1, 0,+1]
const int map[] = {0, -1, 0, 1};
return map[i];
}
static int abcb(int i) { // [0,1,2,3] -> [-1, 0,+1, 0]
const int map[] = {-1, 0, 1, 0};
return map[i];
}
static int acdb(int i) { // [0,1,2,3] -> [-1,+1,+2, 0]
const int map[] = {-1, +1, 2, 0};
return map[i];
}
static int bacd(int i) { // [0,1,2,3] -> [ 0,-1,+1,+2]
const int map[] = {0, -1, 1, 2};
return map[i];
}
static int dcab(int i) { // [0,1,2,3] -> [+2,+1,-1, 0]
const int map[] = {2, 1, -1, 0};
return map[i];
}
static int bdca(int i) { // [0,1,2,3] -> [ 0,+2,+1,-1]
const int map[] = {0, 2, 1, -1};
return map[i];
}
static void music_task(void* arg) {
while (1) {
play_raw(MOUNT_POINT "/tetris.pcm");
}
}
static void init_screen(void) {
while (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdFALSE) vTaskDelay(pdMS_TO_TICKS(10));
img = lv_img_create(lv_scr_act());
lv_img_set_src(img, BACKGROUND_SRC);
lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);
line_clear_img = lv_img_create(lv_scr_act());
lv_obj_add_flag(line_clear_img, LV_OBJ_FLAG_HIDDEN);
lv_img_set_src(line_clear_img, LINE_CLEAR_SRC);
lv_obj_align(line_clear_img, LV_ALIGN_BOTTOM_LEFT, 159, -(height*16));
// for (int h = 0; h < height; h++) {
// for (int w = 0; w < width; w++) {
// visual_board[h][w] = lv_img_create(lv_scr_act());
// lv_obj_align(visual_board[h][w], LV_ALIGN_BOTTOM_LEFT, 159 + w*16, -(h*16));
// lv_img_set_src(visual_board[h][w], PIECE_IMG_SRC[((w+h)%7)+1]);
// }
// }
for (int i = 0; i < 4; i++) {
piece_imgs[i] = lv_img_create(lv_scr_act());
lv_obj_align(piece_imgs[i], LV_ALIGN_BOTTOM_LEFT, 159, -320);
}
xSemaphoreGive(xGuiSemaphore);
xTaskCreate(music_task, "music", 4096, NULL, 5, &music_handle);
}
static void deinit_screen(void) {
while (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdFALSE) vTaskDelay(pdMS_TO_TICKS(10));
lv_obj_clean(lv_scr_act());
xSemaphoreGive(xGuiSemaphore);
vTaskDelete(music_handle);
}
bool play_game(int time, int required_score) {
target_score = required_score;
score = 0;
update_score();
set_module_time(time);
vTaskDelay(1000);
start_module_timer();
clear_board();
generate_block();
ButtonKey button;
// SwitchKey switch_;
while(game) {
if (get_pressed_button(&button)) {
switch (button) {
case ButtonKey::b1:
move_left();
break;
case ButtonKey::b2:
move_right();
break;
case ButtonKey::b3:
drop();
break;
case ButtonKey::b4:
rotate_block();
break;
}
show_board();
if (score >= required_score) {
stop_module_timer();
return true;
}
}
if (get_module_time() <= 0) {
stop_module_timer();
strike("Out of time");
return false;
}
// if (get_flipped_switch(&switch_)) {
// printf("%d\n", piece);
// for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
// int* p = piece_nodes[i];
// printf("PieceLocation: %d, %d\n", p[0], p[1]);
// }
// printf("PieceRotation: %d\n", piece_rotation);
// }
vTaskDelay(pdMS_TO_TICKS(10));
}
// game over
ESP_LOGI(TAG, "Game Over. Score: %d", score);
stop_module_timer();
strike("Out of room");
return false;
}
void step2(void) {
init_screen();
while (!play_game(60000, 4)) vTaskDelay(2000);
while (!play_game(60000, 8)) vTaskDelay(2000);
while (!play_game(120000, 16)) vTaskDelay(2000);
deinit_screen();
}
static void show_board(void) {
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
if (board[h][w] == 9) {
board[h][w] = 0;
}
}
}
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
board[p[0]][p[1]] = 9;
}
if (text_output) {
for (int h = height-1; h >= 0; h--) {
for (int w = 0; w < width; w++) {
printf("|%c", board[h][w] == 9 ? 'X' : (invisible_blocks ? '0' : ('0' + board[h][w])));
}
printf("|\n");
}
printf("\n");
}
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
lv_obj_t* piece_img = piece_imgs[i];
lv_obj_align(piece_img, LV_ALIGN_BOTTOM_LEFT, 159 + p[1]*16, -(p[0]*16));
}
xSemaphoreGive(xGuiSemaphore);
}
}
static void generate_block(void) {
int new_piece = piece_dist(gen);
if (new_piece == piece) {
new_piece = 1;
}
piece = new_piece;
piece_rotation = 0;
piece_location[0] = 20;
piece_location[1] = 4;
get_node_locations();
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (board[p[0]][p[1]] != 0) {
game = false;
return;
}
}
}
}
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
for (int i = 0; i < 4; i++) {
lv_obj_t* piece_img = piece_imgs[i];
lv_img_set_src(piece_img, PIECE_IMG_SRC[piece]);
}
xSemaphoreGive(xGuiSemaphore);
}
}
static void rotate_block(void) {
piece_rotation++;
if (piece_rotation > 3) {
piece_rotation = 0;
}
get_node_locations();
bool overlap = false;
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (p[0] < 0) {
overlap = true;
break;
} else if (board[p[0]][p[1]] != 0 && board[p[0]][p[1]] != 9) {
overlap = true;
break;
}
}
if (overlap) {
piece_location[0]++;
get_node_locations();
bool overlap2 = false;
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (p[0] < 0) {
overlap2 = true;
break;
} else if (board[p[0]][p[1]] != 0 && board[p[0]][p[1]] != 9) {
overlap2 = true;
break;
}
}
if (overlap2) {
piece_rotation--;
if (piece_rotation < 0) {
piece_rotation += 4;
}
piece_location[0]--;
get_node_locations();
}
}
}
static void move_left(void) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (p[1] == 0) {
return;
} else if (board[p[0]][p[1]-1] != 0 && board[p[0]][p[1]-1] != 9) {
return;
}
}
piece_location[1]--;
get_node_locations();
}
static void move_right(void) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (p[1] == width-1) {
return;
} else if (board[p[0]][p[1]+1] != 0 && board[p[0]][p[1]+1] != 9) {
return;
}
}
piece_location[1]++;
get_node_locations();
}
static void drop(void) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
if (p[0] == 0) {
place_piece();
check_line_clears();
generate_block();
return;
} else if (board[p[0]-1][p[1]] != 0 && board[p[0]-1][p[1]] != 9) {
place_piece();
check_line_clears();
generate_block();
return;
}
}
piece_location[0]--;
get_node_locations();
}
static void place_piece(void) {
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
if (board[h][w] == 9) {
board[h][w] = piece;
}
}
}
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) {
int* p = piece_nodes[i];
lv_obj_align(piece_imgs[i], LV_ALIGN_BOTTOM_LEFT, 159, -(height*16));
}
xSemaphoreGive(xGuiSemaphore);
}
ESP_LOGI(TAG, "Placed Piece: %d", piece);
}
static void get_node_locations() {
piece_nodes[0][0] = piece_location[0];
piece_nodes[0][1] = piece_location[1];
if (piece == 1) {
piece_nodes[0][0] = piece_location[0]-bacd(piece_rotation);
piece_nodes[0][1] = piece_location[1]+acdb(piece_rotation);
piece_nodes[1][0] = piece_location[0]-bbcc(piece_rotation);
piece_nodes[1][1] = piece_location[1]+bccb(piece_rotation);
piece_nodes[2][0] = piece_location[0]-bccb(piece_rotation);
piece_nodes[2][1] = piece_location[1]+ccbb(piece_rotation);
piece_nodes[3][0] = piece_location[0]-bdca(piece_rotation);
piece_nodes[3][1] = piece_location[1]+dcab(piece_rotation);
} else if (piece == 2) {
piece_nodes[1][0] = piece_location[0]-babc(piece_rotation);
piece_nodes[1][1] = piece_location[1]+abcb(piece_rotation);
piece_nodes[2][0] = piece_location[0]+babc(piece_rotation);
piece_nodes[2][1] = piece_location[1]-abcb(piece_rotation);
piece_nodes[3][0] = piece_location[0]-aacc(piece_rotation);
piece_nodes[3][1] = piece_location[1]+acca(piece_rotation);
} else if (piece == 3) {
piece_nodes[1][0] = piece_location[0]-babc(piece_rotation);
piece_nodes[1][1] = piece_location[1]+abcb(piece_rotation);
piece_nodes[2][0] = piece_location[0]+babc(piece_rotation);
piece_nodes[2][1] = piece_location[1]-abcb(piece_rotation);
piece_nodes[3][0] = piece_location[0]-acca(piece_rotation);
piece_nodes[3][1] = piece_location[1]-aacc(piece_rotation);
} else if (piece == 4) {
piece_nodes[1][0] = piece_location[0]+1;
piece_nodes[1][1] = piece_location[1];
piece_nodes[2][0] = piece_location[0];
piece_nodes[2][1] = piece_location[1]+1;
piece_nodes[3][0] = piece_location[0]+1;
piece_nodes[3][1] = piece_location[1]+1;
} else if (piece == 5) {
piece_nodes[1][0] = piece_location[0]-babc(piece_rotation);
piece_nodes[1][1] = piece_location[1]+abcb(piece_rotation);
piece_nodes[2][0] = piece_location[0]-abcb(piece_rotation);
piece_nodes[2][1] = piece_location[1]-babc(piece_rotation);
piece_nodes[3][0] = piece_location[0]-acca(piece_rotation);
piece_nodes[3][1] = piece_location[1]-aacc(piece_rotation);
} else if (piece == 6) {
piece_nodes[1][0] = piece_location[0]-babc(piece_rotation);
piece_nodes[1][1] = piece_location[1]+abcb(piece_rotation);
piece_nodes[2][0] = piece_location[0]-abcb(piece_rotation);
piece_nodes[2][1] = piece_location[1]-babc(piece_rotation);
piece_nodes[3][0] = piece_location[0]+babc(piece_rotation);
piece_nodes[3][1] = piece_location[1]-abcb(piece_rotation);
} else if (piece == 7) {
piece_nodes[1][0] = piece_location[0]+babc(piece_rotation);
piece_nodes[1][1] = piece_location[1]-abcb(piece_rotation);
piece_nodes[2][0] = piece_location[0]-abcb(piece_rotation);
piece_nodes[2][1] = piece_location[1]-babc(piece_rotation);
piece_nodes[3][0] = piece_location[0]-aacc(piece_rotation);
piece_nodes[3][1] = piece_location[1]+acca(piece_rotation);
}
}
static void check_line_clears(void) {
for (int h = height-2; h >= 0; h--) {
for (int w = 0; w < width; w++) {
if (board[h][w] != 0 && board[h][w] != 9) {
if (w == width-1) {
line_clear(h);
}
} else {
break;
}
}
}
}
static void update_score(void) {
char buff[16] = {};
sprintf(buff, "%d/%d", score, target_score);
lcd_clear(&lcd);
lcd_set_cursor(&lcd, 1, 1);
lcd_print(&lcd, buff);
}
static void line_clear(int hi) {
for (int h = hi; h < height; h++) {
for (int w = 0; w < width; w++) {
board[h][w] = board[h+1][w];
}
}
for (int w = 0; w < width; w++) {
board[height-1][w] = 0;
}
score++;
update_score();
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
lv_obj_align(line_clear_img, LV_ALIGN_BOTTOM_LEFT, 159, -(hi*16));
xSemaphoreGive(xGuiSemaphore);
}
for (int i = 0; i < 3; i++) {
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
lv_obj_clear_flag(line_clear_img, LV_OBJ_FLAG_HIDDEN);
xSemaphoreGive(xGuiSemaphore);
}
vTaskDelay(pdMS_TO_TICKS(300));
if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) {
lv_obj_add_flag(line_clear_img, LV_OBJ_FLAG_HIDDEN);
xSemaphoreGive(xGuiSemaphore);
}
vTaskDelay(pdMS_TO_TICKS(300));
}
}
void clear_board(void) {
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
board[h][w] = 0;
}
}
}