From 2f6796f57fc0043e3010a1c6ba80645f365c32f5 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Mon, 12 Aug 2024 22:46:09 -0500 Subject: [PATCH] rearrange steps --- main/steps/step2.cpp | 763 ++++-------------------- main/steps/step2.h | 19 +- main/steps/step3.cpp | 1308 ++++++++++++------------------------------ main/steps/step3.h | 23 +- main/steps/step4.cpp | 1000 ++++++++++++++++++++------------ main/steps/step4.h | 18 +- main/steps/step5.cpp | 1041 +++++++++++++++++++++++++++++---- main/steps/step5.h | 10 +- 8 files changed, 2090 insertions(+), 2092 deletions(-) diff --git a/main/steps/step2.cpp b/main/steps/step2.cpp index b87e8ac..6f38701 100644 --- a/main/steps/step2.cpp +++ b/main/steps/step2.cpp @@ -2,690 +2,123 @@ 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 lv_style_t game_over_style; -static lv_obj_t* game_over_label; - -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", +// one: 0b00000110 +// seven: 0b00000111 +static const uint8_t SSEG_NUMS[8] = {0b00111111, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b01111111, 0b01101111}; +static const uint8_t SSEG_MAPS[5][4] = { + {0b0101101, 0b1111010, 0b1000010, 0b1010100}, + {0b01000101, 0b00100100, 0b00110110, 0b01111011}, + {0b00101010, 0b00000010, 0b00010111, 0b00111100}, + {0b00111000, 0b01010010, 0b00101011, 0b00111010}, + {0b01000111, 0b00011001, 0b01111000, 0b00111110} }; -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; +static const int INDICATOR_RED[5] = {15, 0, 0, 10, 5}; +static const int INDICATOR_GREEN[5] = {0, 0, 10, 5, 5}; +static const int INDICATOR_BLUE[5] = {0, 10, 0, 0, 5}; +// random number generators static std::random_device rd; static std::mt19937 gen(rd()); -static std::uniform_int_distribution<> piece_dist(2, 7); +static std::uniform_int_distribution<> answer_dist(0, 7); +static std::uniform_int_distribution<> map_dist(0, 4); +static std::uniform_int_distribution<> display_dist(0, 3); +static std::uniform_int_distribution<> random_segment_dist(0, 127); -static void generate_block(void); -static void show_board(void); -static void get_node_locations(void); -static bool check_overlap(void); +static int answer = 0; +static uint8_t answer_sseg = SSEG_NUMS[0]; +static char answer_char = '0'; +static uint8_t display_map[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000}; +static int chosen_map = 0; -static void line_clear(int hi); -static void check_line_clears(void); -static void place_piece(void); +std::map number_map = { + {0, 0}, + {1, 2}, + {2, 3}, + {3, 4}, + {4, 5}, + {5, 6}, + {6, 8}, + {7, 9}, +}; -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)); - - lv_style_init(&game_over_style); - lv_style_set_text_color(&game_over_style, lv_color_white()); - lv_style_set_bg_color(&game_over_style, lv_color_black()); - lv_style_set_bg_opa(&game_over_style, LV_OPA_100); - lv_style_set_text_align(&game_over_style, LV_TEXT_ALIGN_CENTER); - - game_over_label = lv_label_create(lv_scr_act()); - lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); - lv_obj_align(game_over_label, LV_ALIGN_CENTER, 0, 0); - lv_obj_add_style(game_over_label, &game_over_style, LV_STATE_DEFAULT); - - // 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) { - game = true; - target_score = required_score; - score = 0; - update_score(); - set_module_time(time); - start_module_timer(); - - clear_board(); - - generate_block(); - show_board(); - - ButtonKey button; - while (get_pressed_button(&button)); - // SwitchKey switch_; - - const TickType_t first_repeat_time = pdMS_TO_TICKS(700); - const TickType_t repeat_time = pdMS_TO_TICKS(100); - TickType_t down_held = 0; - TickType_t last_repeat = 0; - - while(game) { - if (get_pressed_button(&button)) { - switch (button) { - case ButtonKey::b1: - move_left(); - break; - case ButtonKey::b2: - move_right(); - break; - case ButtonKey::b3: - down_held = xTaskGetTickCount(); - last_repeat = 0; - drop(); - break; - case ButtonKey::b4: - rotate_block(); - break; - } - - show_board(); - - if (score >= required_score) { - stop_module_timer(); - return true; - } +static void new_puzzle(void) { + // scramble lights + for (int i = 0; i < 5; i++) { + led_strip_set_pixel(leds, 9, INDICATOR_RED[map_dist(gen)], INDICATOR_GREEN[map_dist(gen)], INDICATOR_BLUE[map_dist(gen)]); + led_strip_refresh(leds); + + uint8_t random_segments[4] = {0, 0, 0, 0}; + for (int i = 0; i < 4; i++) { + random_segments[i] = random_segment_dist(gen); } - if (get_released_button(&button)) { - if (button == ButtonKey::b3) { - down_held = 0; - } + set_module_sseg_raw(random_segments); + vTaskDelay(pdMS_TO_TICKS(100)); + } + + answer = answer_dist(gen); + answer_sseg = SSEG_NUMS[answer]; + // convert answer to number value to account for missing 1 and 7 + answer = number_map[answer]; + answer_char = '0' + answer; + // ESP_LOGI(TAG, "Answer: %i", answer); + + chosen_map = map_dist(gen); + for (int i = 0; i < 4; ++i) { + display_map[i] = SSEG_MAPS[chosen_map][i]; + } + // ESP_LOGI(TAG, "Chosen Map: %i", chosen_map); + + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, INDICATOR_RED[chosen_map], INDICATOR_GREEN[chosen_map], INDICATOR_BLUE[chosen_map])); + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + for (int i = 0; i < 8; i++) { + bool bit = (answer_sseg >> i) & 1; + if (bit == 1) { + // choose display and flip bit + int display = display_dist(gen); + display_map[display] ^= (1 << i); + // ESP_LOGI(TAG, "Flipping bit %i on display %i", i, display); } - - if (down_held != 0) { - // check repeat - TickType_t now = xTaskGetTickCount(); - if (now - down_held > first_repeat_time) { - // repeat! - if (now - last_repeat > repeat_time) { - last_repeat = now; - drop(); - 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; -} - -static void complete(void) { - if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { - lv_label_set_text(game_over_label, "Winner!\nPress any button to continue"); - lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); - xSemaphoreGive(xGuiSemaphore); - } - vTaskDelay(pdMS_TO_TICKS(500)); - while (get_pressed_button(nullptr)); - while (1) { - if (get_pressed_button(nullptr)) break; - vTaskDelay(pdMS_TO_TICKS(10)); - } - if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { - lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); - xSemaphoreGive(xGuiSemaphore); - } -} - -static void fail(void) { - if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { - lv_label_set_text(game_over_label, "Game Over\nPress any button to continue"); - lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); - xSemaphoreGive(xGuiSemaphore); - } - vTaskDelay(pdMS_TO_TICKS(500)); - while (get_pressed_button(nullptr)); - while (1) { - if (get_pressed_button(nullptr)) break; - vTaskDelay(pdMS_TO_TICKS(10)); - } - if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { - lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); - xSemaphoreGive(xGuiSemaphore); } } void step2(void) { - StarCodeHandler star_code = { - .code = "*3850", - .display_text = "Starting...", - .should_exit = true, - .callback = nullptr, - }; - do_star_codes(&star_code, 1); - init_screen(); + KeypadKey key; + int solved_times = 0; - while (!play_game(4*60*1000, 2)) fail(); - complete(); - while (!play_game(4*60*1000, 4)) fail(); - complete(); - while (!play_game(6*60*1000, 8)) fail(); - complete(); - - 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] = 18; - 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(); - - // Check overlap without moving - if (check_overlap()) { - - // Check overlap after moving up 1 - piece_location[0]--; - get_node_locations(); - if (check_overlap()) { - - // Check overlap after moving down 1 - piece_location[0]++; - piece_location[0]++; - get_node_locations(); - if (check_overlap()) { - - // Check overlap after moving left 1 - piece_location[0]--; - piece_location[1]--; - get_node_locations(); - if (check_overlap()) { - - // Check overlap after moving right 1 - piece_location[1]++; - piece_location[1]++; - get_node_locations(); - if (check_overlap()) { - piece_location[1]--; - // This is Original Position - - // If Line Piece, check 2 left, 2 right, 2 up and 2 down - - // Check 2 left - if (piece == 1 && piece_rotation == 0) { - piece_location[1]-=2; - get_node_locations(); - if (check_overlap()) { - piece_location[1]+=2; - get_node_locations(); - } - // Check 2 up - } else if (piece == 1 && piece_rotation == 1) { - piece_location[0]+=2; - get_node_locations(); - if (check_overlap()) { - piece_location[0]-=2; - get_node_locations(); - } - // Check 2 right - } else if (piece == 1 && piece_rotation == 2) { - piece_location[1]+=2; - get_node_locations(); - if (check_overlap()) { - piece_location[1]-=2; - get_node_locations(); - } - // Check 2 down - } else if (piece == 1 && piece_rotation == 3) { - piece_location[0]-=2; - get_node_locations(); - if (check_overlap()) { - piece_location[0]+=2; - get_node_locations(); - } - } - } - } - } - } - } -} - -// Check if nodes are outside of map or interposed onto placed nodes -static bool check_overlap(void) { - for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) { - int* p = piece_nodes[i]; - if (p[0] < 0 || p[1] < 0 || p[1] >= width) { - return true; - } else if (board[p[0]][p[1]] != 0 && board[p[0]][p[1]] != 9) { - return true; - } - } - return false; -} - -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); + new_puzzle(); + int strike_time = xTaskGetTickCount(); + bool striked = false; + while(solved_times < 4) { + // for every bit in the answer- + set_module_sseg_raw(display_map); + if (get_pressed_keypad(&key)) { + lcd_clear(&lcd); + char c = char_of_keypad_key(key); + // ESP_LOGI(TAG, "Pressed: %c", c); + if (c == answer_char) { + play_raw(MOUNT_POINT "/correct.pcm"); + solved_times++; + if (solved_times < 3) { + clean_bomb(); + new_puzzle(); + } else { + uint8_t display_tmp[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000}; + set_module_sseg_raw(display_tmp); } } else { - break; + strike_time = xTaskGetTickCount(); + striked = true; + strike("Incorrect Character!"); } } - } -} -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); -} + if (xTaskGetTickCount() - strike_time > pdMS_TO_TICKS(5000)) { + striked = false; + lcd_clear(&lcd); + } + vTaskDelay(pdMS_TO_TICKS(10)); + } -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; - } - } } diff --git a/main/steps/step2.h b/main/steps/step2.h index 2d925e6..23c630c 100644 --- a/main/steps/step2.h +++ b/main/steps/step2.h @@ -1,22 +1,15 @@ #ifndef STEP_2_H #define STEP_2_H -#include -#include "../drivers/tft.h" -#include "../drivers/speaker.h" #include "../drivers/bottom_half.h" -#include "../drivers/game_timer.h" #include "../drivers/wires.h" -#include "../drivers/char_lcd.h" +#include "../drivers/game_timer.h" +#include "../drivers/leds.h" +#include "../drivers/speaker.h" #include "../helper.h" - -// TODO: -// - [ ] set up real game loop -// - [ ] stop music -// - [ ] set up strike on falure -// - [ ] set up module timer - - +#include +#include +#include void step2(void); diff --git a/main/steps/step3.cpp b/main/steps/step3.cpp index f413a40..5007688 100644 --- a/main/steps/step3.cpp +++ b/main/steps/step3.cpp @@ -1,49 +1,69 @@ #include "step3.h" +#define ONE_SECOND_TIME 90'000 +#define THREE_SECOND_TIME 90'000 +#define SIX_SECOND_TIME 75'000 + static const char *TAG = "step3"; +static int tone = 0; +static int times = 0; + +static const char* TONE_FILES[] = { + MOUNT_POINT "/low-1.pcm", + MOUNT_POINT "/low-3.pcm", + MOUNT_POINT "/low-6.pcm", + MOUNT_POINT "/high-1.pcm", + MOUNT_POINT "/high-3.pcm", + MOUNT_POINT "/high-6.pcm", +}; + +static const char* LCD_STRINGS[] = { + "something", + "nothing", + "", + "a word", + "somethink", + "what?", + "LCD", + "display", +}; + +static int indicator_led_idxs[LED_COUNT] = {0}; + +static bool contains_coconut = false; +static char* COCONUT = "coconut"; +static char lcd_random_char_set[] = "aeiou tnsrhldm"; +static char random_lcd_text[21] = {0}; + static std::random_device rd; static std::mt19937 gen(rd()); -static std::uniform_int_distribution<> puzzle_dist(0, 7); -static std::uniform_int_distribution<> led_picker_dist(0, 20); -static std::uniform_int_distribution<> led_color_dist(0, 5); +static std::uniform_int_distribution<> tone_dist(0, 5); +static std::uniform_int_distribution<> color_dist(0, 6); +static std::uniform_int_distribution<> lcd_string_dist(0, 7); +static std::uniform_int_distribution<> lcd_number_dist(0, 15); +static std::uniform_int_distribution<> lcd_rand_char_dist(0, sizeof(lcd_random_char_set)-2); +static std::uniform_int_distribution<> has_coconut_dist(0, 2); +static std::uniform_int_distribution<> coconut_position_dist(0, 13); -void set_unique_leds(std::vector& input_options, const int num, const int r, const int g, const int b) { - for (int i = 0; i < num; i++) { - std::uniform_int_distribution<> led_option_dist(0, input_options.size() - 1); - int led = led_option_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, input_options[led], r, g, b)); - input_options.erase(input_options.begin() + led); - } -} +static uint8_t NEOPIXEL_COLORS[7][3] = { + {20, 0, 0}, // red + {20, 10, 0}, // orange + {20, 20, 0}, // yellow + {0, 20, 0}, // green + {0, 0, 20}, // blue + {20, 0, 20}, // purple + {0, 0, 0}, // off +}; -void set_unique_leds_random_color(std::vector& input_options, const int num, const int* r, const int* g, const int* b) { - for (int i = 0; i < num; i++) { - std::uniform_int_distribution<> led_option_dist(0, input_options.size() - 1); - int led = led_option_dist(gen); - - std::uniform_int_distribution<> led_color_dist(0, sizeof(r) - 1); - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, input_options[led], r[color], g[color], b[color])); - input_options.erase(input_options.begin() + led); - } -} - -std::vector unique_values(std::vector& input_options, int num) { - std::vector output_vec; - for (int i = 0; i < num; i++) { - std::uniform_int_distribution<> option_num_dist(0, input_options.size() - 1); - int option_num = option_num_dist(gen); - output_vec.push_back(input_options[option_num]); - input_options.erase(input_options.begin() + option_num); - } - return output_vec; -} +static bool one_second(); +static bool three_second(); +static bool six_second(); void step3(void) { StarCodeHandler star_codes[] = { { - .code = "*2648", + .code = "*1642", .display_text = "Starting...", .should_exit = true, .callback = nullptr, @@ -52,908 +72,330 @@ void step3(void) { int len = sizeof(star_codes)/sizeof(StarCodeHandler); do_star_codes(star_codes, len); - std::vector all_leds; + while (times < 4) { + tone = tone_dist(gen); + // tone = 2; + while (get_pressed_button(nullptr)) vTaskDelay(pdMS_TO_TICKS(10)); - for (int i = 0; i < 21; i++) { - all_leds.push_back(i); - } - - const int INDICATOR_RED[6] = {20, 0, 0, 10, 10, 5}; - const int INDICATOR_GREEN[6] = {0, 0, 10, 5, 0, 5}; - const int INDICATOR_BLUE[6] = {0, 10, 0, 0, 5, 5}; - static std::uniform_int_distribution<> led_number_dist(0, 21); - - int last_cycle_tick = xTaskGetTickCount(); - int scrambled_times = 0; - while (scrambled_times < 5) { - if ((xTaskGetTickCount() - last_cycle_tick) > pdMS_TO_TICKS(100)) { + play_raw(MOUNT_POINT "/que.pcm"); + play_raw(TONE_FILES[tone]); + + bool correct = false; + switch (tone % 3) { + case 0: + correct = one_second(); + break; + case 1: + correct = three_second(); + break; + case 2: + correct = six_second(); + break; + } + if (correct) { + times++; clean_bomb(); - std::vector led_options = all_leds; - set_unique_leds_random_color(led_options, led_number_dist(gen), INDICATOR_RED, INDICATOR_GREEN, INDICATOR_BLUE); - ESP_ERROR_CHECK(led_strip_refresh(leds)); - last_cycle_tick = xTaskGetTickCount(); - scrambled_times++; - } - } - - clean_bomb(); - int solved_puzzles = 0; - while (solved_puzzles < 3) { - lcd_set_cursor(&lcd, 1, 1); - - int puzzle = puzzle_dist(gen); - // int puzzle = 6; - - bool solved_correctly = false; - switch (puzzle) { - case 0: { - lcd_print(&lcd, "Clear"); - set_module_time(15000); - start_module_timer(); - - std::vector indicator_options = all_leds; - - // set green - std::uniform_int_distribution<> green_indicators_dist(1, 15); - uint8_t green_indicators = green_indicators_dist(gen); - set_unique_leds(indicator_options, green_indicators, 0, 10, 0); - - // set non-green - const int NON_GREEN_INDICATOR_RED[3] = {30, 0, 15}; - const int NON_GREEN_INDICATOR_GREEN[3] = {0, 0, 0}; - const int NON_GREEN_INDICATOR_BLUE[3] = {0, 30, 15}; - std::uniform_int_distribution<> non_green_indicators_dist(0, (20 - green_indicators)); - set_unique_leds_random_color(indicator_options, non_green_indicators_dist(gen), NON_GREEN_INDICATOR_RED, NON_GREEN_INDICATOR_GREEN, NON_GREEN_INDICATOR_BLUE); - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - // wait for time - while (1) { - if (get_module_time() <= 0) { - uint8_t state = get_switch_state(); - uint8_t flipped_state = 0; - flipped_state |= (state & 0x01) << 3; - flipped_state |= (state & 0x02) << 1; - flipped_state |= (state & 0x04) >> 1; - flipped_state |= (state & 0x08) >> 3; - - if (flipped_state == green_indicators) { - solved_puzzles++; - } else { - strike("Incorrect Switches"); - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - - break; - } - case 1: { - lcd_print(&lcd, "Blank"); - set_module_time(30000); - start_module_timer(); - - std::uniform_int_distribution<> on_indicators_dist(16, 21); - uint8_t indicators_num = on_indicators_dist(gen); - - std::vector indicator_options = all_leds; - const int INDICATOR_RED[6] = {20, 0, 0, 10, 10, 5}; - const int INDICATOR_GREEN[6] = {0, 0, 10, 5, 0, 5}; - const int INDICATOR_BLUE[6] = {0, 10, 0, 0, 5, 5}; - - set_unique_leds_random_color(indicator_options, indicators_num, INDICATOR_RED, INDICATOR_BLUE, INDICATOR_GREEN); - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - // ESP_LOGI(TAG, "puzzle 1 LEDs set (%i leds)", indicators_num); - - if (indicators_num < 18) { - while (1) { - if (get_module_time() <= 0) { - if (get_switch_state() == 0b1111) { - solved_puzzles++; - // ESP_LOGI(TAG, "puzzle 1 solved (switches)!"); - } else { - strike("Switch State Changed"); - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - } else { - uint8_t starting_switch_state = get_switch_state(); - KeypadKey key; - std::string pressed_keys; - while (1) { - if (get_pressed_keypad(&key)) { - pressed_keys += char_of_keypad_key(key); - // ESP_LOGI(TAG, "key %c pressed", char_of_keypad_key(key)); - } - if (get_module_time() <= 0) { - if (starting_switch_state == get_switch_state()) { - if (pressed_keys == "ADCB") { - solved_puzzles++; - solved_correctly = true; - // ESP_LOGI(TAG, "puzzle 1 solved (keypad)!"); - } - } else { - strike("Switches Changed!"); - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - } - - - - break; - } - case 2: { - set_module_time(30000); - start_module_timer(); - - std::uniform_int_distribution<> lit_led_dist(0, 1); - bool rfid_lit = lit_led_dist(gen); - bool lcd_lit = lit_led_dist(gen); - bool speaker_lit = lit_led_dist(gen); - bool keypad_lit = lit_led_dist(gen); - bool tft_lit = lit_led_dist(gen); - - if (rfid_lit) { - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 10, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); - } - if (lcd_lit) { - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 12, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); - } - if (speaker_lit) { - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); - } - if (keypad_lit) { - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 11, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); - } - if (tft_lit) { - int color = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 6, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); - } - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - int green_button_pressed = 0; - // ESP_LOGI(TAG, "green pressed: %i", green_button_pressed); - int blue_button_pressed = 0; - int fingerprint_sensor_pressed = 0; - std::string keypad_string; - - ButtonKey button; - KeypadKey key; - SwitchKey switch1 = s1; - SwitchKey switch2 = s2; - - while (1) { - if (get_pressed_button(&button)) { - uint8_t button_state = get_button_state(); - // ESP_LOGI(TAG, "Button pressed! (%i)", button_state()); - - if ((button_state & 0b1) == 0b1) { - green_button_pressed++; - if ((green_button_pressed > 1) || !rfid_lit) { - strike("Too many times!"); - break; - } - } - if ((button_state & 0b1000) == 0b1000) { - blue_button_pressed++; - if ((blue_button_pressed > 1) || !lcd_lit) { - strike("Too many times!"); - break; - } - } - } - if (get_touch_pressed()) { - fingerprint_sensor_pressed++; - if ((fingerprint_sensor_pressed > 2) || !speaker_lit) { - strike("Too many times!"); - break; - } - } - if (get_pressed_keypad(&key)) { - bool wrong = false; - keypad_string += char_of_keypad_key(key); - switch (keypad_string.length()) { - case 1: { - if (keypad_string != "1") { - strike("Incorrect Keypad!"); - wrong = true; - } - break; - } - case 2: { - if (keypad_string != "12") { - strike("Incorrect Keypad!"); - wrong = true; - } - break; - } - default: { - strike("Incorrect Keypad!"); - wrong = true; - break; - } - } - if (wrong) { - break; - } - } - if (get_flipped_up_switch(&switch1) || get_flipped_up_switch(&switch2)) { - if (!tft_lit) { - strike("Incorrect Switches"); - break; - } - } - if (get_module_time() <= 0) { - bool rfid_correct = !(rfid_lit && (green_button_pressed != 1)); - bool lcd_correct = !(lcd_lit && (blue_button_pressed != 1)); - bool speaker_correct = !(speaker_lit && (fingerprint_sensor_pressed != 2)); - bool keypad_correct = !(keypad_lit && (keypad_string != "12")); - bool tft_correct = !(tft_lit && ((get_switch_state() & 0b11) != 0b11)); - - if (rfid_correct && lcd_correct && speaker_correct && keypad_correct && tft_correct) { - solved_puzzles++; - solved_correctly = true; - } else { - strike("Incorrect state!"); - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - - break; - } - case 3: { - lcd_print(&lcd, "Nothing"); - set_module_time(20000); - start_module_timer(); - - const int COLOR_RED[5] = {0, 20, 10, 0, 0}; - const int COLOR_GREEN[5] = {20, 0, 10, 0, 0}; - const int COLOR_BLUE[5] = {0, 0, 0, 20, 0}; - - static std::uniform_int_distribution<> color_dist(0, 4); - - int tft_color = color_dist(gen); - int speaker_color = color_dist(gen); - int s3_color = color_dist(gen); - - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 6, COLOR_RED[tft_color], COLOR_GREEN[tft_color], COLOR_BLUE[tft_color])); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, COLOR_RED[speaker_color], COLOR_GREEN[speaker_color], COLOR_BLUE[speaker_color])); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 14, COLOR_RED[s3_color], COLOR_GREEN[s3_color], COLOR_BLUE[s3_color])); - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - int buttons_pressed = 0; - - ButtonKey button; - - while (1) { - if (get_pressed_button(&button)) { - buttons_pressed++; - uint8_t button_state = get_button_state(); - - if (buttons_pressed == 1) { - if ((button_state >> tft_color) != 0b1) { - strike("Wrong button!"); - break; - } - } else if (buttons_pressed == 2) { - if ((button_state >> speaker_color) != 0b1) { - strike("Wrong button!"); - break; - } - } else if (buttons_pressed == 3) { - if ((button_state >> s3_color) != 0b1) { - strike("Wrong button!"); - } else { - solved_puzzles++; - solved_correctly = true; - } - break; - } - - } - if (get_module_time() <= 0) { - strike("Ran out of time!"); - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - - - - break; - } - case 4: { - lcd_print(&lcd, "Blink"); - set_module_time(30000); - start_module_timer(); - - // buttons - const int BUTTON_COLOR_RED[4] = {0, 20, 10, 0}; - const int BUTTON_COLOR_GREEN[4] = {10, 0, 5, 0}; - const int BUTTON_COLOR_BLUE[4] = {0, 0, 0, 10}; - - static std::uniform_int_distribution<> button_color_dist(0, 3); - int button_colors[4] = {button_color_dist(gen), button_color_dist(gen), button_color_dist(gen), button_color_dist(gen)}; - - for (int i = 0; i < 4; i++) { - ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), BUTTON_COLOR_RED[button_colors[i]], BUTTON_COLOR_GREEN[button_colors[i]], BUTTON_COLOR_BLUE[button_colors[i]])); - } - - // switches - const int SWITCH_COLOR_RED[3] = {20, 0, 10}; - const int SWITCH_COLOR_GREEN[3] = {0, 10, 5}; - - static std::uniform_int_distribution<> switch_color_dist(0, 2); - - int switch_colors[4] = {switch_color_dist(gen), switch_color_dist(gen), switch_color_dist(gen), switch_color_dist(gen)}; - - for (int i = 0; i < 4; i++) { - ESP_ERROR_CHECK(led_strip_set_pixel(leds, (16 - i), SWITCH_COLOR_RED[switch_colors[i]], SWITCH_COLOR_GREEN[switch_colors[i]], 0)); - } - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - ButtonKey button; - SwitchKey switch_key; - uint8_t starting_switch_state = get_switch_state(); - - while (1) { - if (get_pressed_button(&button)) { - uint8_t button_state = get_button_state(); - - for (int i = 0; i < 4; i++) { - if (((button_state >> i) & 0b1) == 0b1) { - button_colors[i]++; - if (button_colors[i] > 3) { - button_colors[i] = 0; - } - ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), BUTTON_COLOR_RED[button_colors[i]], BUTTON_COLOR_GREEN[button_colors[i]], BUTTON_COLOR_BLUE[button_colors[i]])); - } - - } - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { - // check switch state - uint8_t switch_state = get_switch_state(); - bool correct = true; - - for (int i = 0; i < 4; i++) { - if (switch_colors[i] == 2) { - if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { - correct = false; - break; - } - } else { - if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { - correct = false; - break; - } - } - } - - if (correct) { - solved_puzzles++; - solved_correctly = true; - break; - } - } - } - if (get_flipped_switch(&switch_key)) { - if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { - // check switch state - uint8_t switch_state = get_switch_state(); - bool correct = true; - - for (int i = 0; i < 4; i++) { - if (switch_colors[i] == 2) { - if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { - correct = false; - break; - } - } else { - if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { - correct = false; - break; - } - } - } - - if (correct) { - solved_puzzles++; - solved_correctly = true; - break; - } - } - } - if (get_module_time() <= 0) { - // check button state - if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { - // check switch state - uint8_t switch_state = get_switch_state(); - bool correct = true; - // ESP_LOGI(TAG, "starting switch state: %i, current switch state: %i", starting_switch_state, switch_state); - - - - for (int i = 0; i < 4; i++) { - if (switch_colors[i] == 2) { - // ESP_LOGI(TAG, "color yellow triggered: %i", (((switch_state ^ starting_switch_state) >> i) & 0b1)); - if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { - correct = false; - break; - } - } else { - // ESP_LOGI(TAG, "color green or red triggered: %i != %i", ((switch_state >> i) & 0b1), (switch_colors[i] & 0b1)); - if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { - correct = false; - break; - } - } - } - - if (correct) { - solved_puzzles++; - solved_correctly = true; - } else { - strike("Wrong switch state!"); - } - } else { - strike("Wrong button state!"); - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - - - break; - } - case 5: { - lcd_print(&lcd, "Ummm"); - set_module_time(30000); - start_module_timer(); - - std::uniform_int_distribution<> indicator_number_dist(0, 5); - - const int INDICATOR_RED[4] = {0, 20, 10, 10}; - const int INDICATOR_GREEN[4] = {10, 0, 5, 5}; - const int INDICATOR_BLUE[4] = {0, 0, 0, 10}; - - // green, red, yellow, blue - std::array indicator_numbers = {indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen)}; - std::vector indicator_options = all_leds; - - for (int i = 0; i < 4; i++) { - set_unique_leds(indicator_options, indicator_numbers[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); - } - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - std::array buttons_pressed = {0, 0, 0, 0}; - - ButtonKey button; - - while (1) { - if (get_pressed_button(&button)) { - uint8_t button_state = get_button_state(); - - for (int i = 0; i < 4; i++) { - if (((button_state >> i) & 0b1) == 0b1) { - buttons_pressed[i]++; - if (buttons_pressed[i] > indicator_numbers[i]) { - strike("Too many times!"); - break; - } - } - } - } - if (get_module_time() <= 0) { - // check for correct button presses - for (int i = 0; i < 4; i++) { - if (buttons_pressed == indicator_numbers) { - strike("Wrong button state!"); - break; - } - } - - uint8_t switch_state = get_switch_state(); - - // check for correct switch states - for (int i = 0; i < 4; i++) { - if (((switch_state >> i) & 0b1) == (indicator_numbers[i] & 0b1)) { - strike("Wrong switch state!"); - break; - } - } - - solved_puzzles++; - solved_correctly = true; - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - - - - break; - } - case 6: { - lcd_print(&lcd, "Plank"); - set_module_time(40000); - start_module_timer(); - - std::uniform_int_distribution<> led_color_dist(0, 5); - std::uniform_int_distribution<> led_off_dist(-1, 3); - - // red, purple, blue, white, green, yellow - const uint8_t COLORS_RED[6] = {20, 10, 0, 5, 0, 10}; - const uint8_t COLORS_GREEN[6] = {0, 0, 0, 5, 10, 5}; - const uint8_t COLORS_BLUE[6] = {0, 10, 10, 5, 0, 0}; - - int button_colors[4]; - bool buttons_cycling[4]; - int led_off = led_off_dist(gen); - - for (int i = 0; i < 4; i++) { - if (led_off != i) { - button_colors[i] = led_color_dist(gen); - ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), COLORS_RED[button_colors[i]], COLORS_GREEN[button_colors[i]], COLORS_BLUE[button_colors[i]])); - buttons_cycling[i] = true; - } else { - button_colors[i] = -1; - buttons_cycling[i] = false; - } - } - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - const uint8_t CORRECT_COLORS[4] = {4, 0, 5, 2}; - TickType_t lastCycleTime = xTaskGetTickCount(); - bool button_turned_on = false; - - ButtonKey button; - - std::uniform_int_distribution<> led_turn_on_dist(0, 3); - while (1) { - if (get_pressed_button(&button)) { - uint8_t button_state = get_button_state(); - - for (int i = 0; i < 4; i++) { - if (((button_state >> i) & 0b1) == 0b1) { - if (button_colors[i] == -1) { - if (led_turn_on_dist(gen) == 0) { - button_turned_on = true; - led_strip_set_pixel(leds, (20 - i), COLORS_RED[CORRECT_COLORS[i]], COLORS_GREEN[CORRECT_COLORS[i]], COLORS_BLUE[CORRECT_COLORS[i]]); - led_strip_refresh(leds); - } - } else if (button_colors[i] != CORRECT_COLORS[i]) { - strike("Wrong time!"); - break; - } else { - buttons_cycling[i] = false; - } - } - } - - bool success = true; - for (int i = 0; i < sizeof(buttons_cycling); i++) { - if ((buttons_cycling[i] == true) || (button_turned_on == false && led_off != -1)) { - success = false; - break; - } - } - if (success) { - solved_puzzles++; - solved_correctly = true; - break; - } - } - if ((xTaskGetTickCount() - lastCycleTime) >= pdMS_TO_TICKS(500)) { - ESP_LOGI(TAG, "Cycling LEDs"); - for (int i = 0; i < 4; i++) { - if (buttons_cycling[i]) { - button_colors[i]++; - if (button_colors[i] > 5) { - button_colors[i] = 0; - } - ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), COLORS_RED[button_colors[i]], COLORS_GREEN[button_colors[i]], COLORS_BLUE[button_colors[i]])); - } - } - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - lastCycleTime = xTaskGetTickCount(); - } - if (get_module_time() <= 0) { - bool success = true; - for (int i = 0; i < sizeof(buttons_cycling); i++) { - if ((buttons_cycling[i] == true) || (button_turned_on == false && led_off != -1)) { - strike("Ran out of time!"); - success = false; - break; - } - } - if (success) { - solved_puzzles++; - solved_correctly = true; - } - break; - } - vTaskDelay(pdMS_TO_TICKS(10)); - } - break; - } - case 7: { - lcd_print(&lcd, "What"); - set_module_time(40000); - start_module_timer(); - - std::uniform_int_distribution<> math_number_dist(1, 9); - - std::vector math_numbers; - std::vector math_operations; - - std::map operation_map = { - {0, '+'}, - {1, '-'}, - {2, '*'}, - {3, '/'}, - }; - - int expression_answer = -1; - std::string display_expression; - - while (expression_answer < 0) { - math_numbers = {static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen))}; - std::vector possible_math_operations = {0, 1, 2, 3}; - math_operations = unique_values(possible_math_operations, 3); - - display_expression = std::to_string(static_cast(math_numbers[0])); - for (int i = 0; i < 3; i++) { - display_expression += operation_map[math_operations[i]]; - display_expression += std::to_string(static_cast(math_numbers[i + 1])); - } - - // Solve - for (int j = 0; j < 3; j++) { - bool found = false; - for (int i = 0; i < math_operations.size(); i++) { - if (math_operations[i] == 2) { - // ESP_LOGI(TAG, "i = %i, condensing %f * %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] * math_numbers[i+1])); - math_numbers[i] = math_numbers[i] * math_numbers[i + 1]; - math_numbers.erase(math_numbers.begin() + i + 1); - math_operations.erase(math_operations.begin() + i); - found = true; - break; - } else if (math_operations[i] == 3) { - // ESP_LOGI(TAG, "i = %i, condensing %f / %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] / math_numbers[i+1])); - math_numbers[i] = math_numbers[i] / math_numbers[i + 1]; - math_numbers.erase(math_numbers.begin() + i + 1); - math_operations.erase(math_operations.begin() + i); - found = true; - break; - } - } - if (found) continue; - for (int i = 0; i < math_operations.size(); i++) { - if (math_operations[i] == 0) { - // ESP_LOGI(TAG, "i = %i, condensing %f + %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] + math_numbers[i+1])); - math_numbers[i] = math_numbers[i] + math_numbers[i + 1]; - math_numbers.erase(math_numbers.begin() + i + 1); - math_operations.erase(math_operations.begin() + i); - found = true; - break; - } else if (math_operations[i] == 1) { - // ESP_LOGI(TAG, "i = %i, condensing %f - %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] - math_numbers[i+1])); - math_numbers[i] = math_numbers[i] - math_numbers[i + 1]; - math_numbers.erase(math_numbers.begin() + i + 1); - math_operations.erase(math_operations.begin() + i); - found = true; - break; - } - } - } - expression_answer = static_cast(std::floor(math_numbers[0])); - } - - // display expression - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, display_expression.c_str()); - - // ESP_LOGI(TAG, "Display expression: %s", display_expression.c_str()); - // ESP_LOGI(TAG, "Solved expression answer: %i", static_cast(expression_answer)); - - // set LEDs - - // blue, red, green, yellow - const int INDICATOR_RED[4] = {0, 20, 0, 10}; - const int INDICATOR_GREEN[4] = {0, 0, 10, 5}; - const int INDICATOR_BLUE[4] = {10, 0, 0, 0}; - - std::uniform_int_distribution<> add_sub_indicator_dist(1, 6); - std::uniform_int_distribution<> mult_div_indicator_dist(1, 3); - - int modifier_indicators[4] = {add_sub_indicator_dist(gen), add_sub_indicator_dist(gen), mult_div_indicator_dist(gen), mult_div_indicator_dist(gen)}; - - while ((((expression_answer + (modifier_indicators[0] * 3) - modifier_indicators[1]) * (3 ^ modifier_indicators[2])) / (2 ^ modifier_indicators[3])) < 0) { - modifier_indicators[0] = add_sub_indicator_dist(gen); - modifier_indicators[1] = add_sub_indicator_dist(gen); - modifier_indicators[2] = mult_div_indicator_dist(gen); - modifier_indicators[3] = mult_div_indicator_dist(gen); - } - - expression_answer += modifier_indicators[0] * 3; - expression_answer -= modifier_indicators[1]; - expression_answer *= 3 ^ modifier_indicators[2]; - expression_answer /= 2 ^ modifier_indicators[3]; - - std::vector led_options = all_leds; - for (int i = 0; i < 4; i++) { - set_unique_leds(led_options, modifier_indicators[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); - } - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - std::string answer_string = std::to_string(expression_answer); - std::string entered_string; - - // ESP_LOGI(TAG, "Solved full answer: %s", answer_string.c_str()); - - KeypadKey key; - - while (1) { - if (get_pressed_keypad(&key)) { - if (key == KeypadKey::star) { - // clear - entered_string = ""; - } else if (key == KeypadKey::pound) { - // submit - if (entered_string != answer_string) { - strike("Incorrect answer!"); - } else { - solved_puzzles++; - solved_correctly = true; - } - break; - } else { - entered_string += char_of_keypad_key(key); - } - - lcd_clear(&lcd); - lcd_set_cursor(&lcd, 1, 1); - lcd_print(&lcd, "What"); - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, display_expression.c_str()); - lcd_set_cursor(&lcd, 1, 3); - lcd_print(&lcd, entered_string.c_str()); - } - if (get_module_time() <= 0) { - strike("Ran out of time!"); - break; - } - - - vTaskDelay(pdMS_TO_TICKS(10)); - } - - break; - } - case 8: { - lcd_print(&lcd, "Plink"); - set_module_time(15000); - start_module_timer(); - - std::uniform_int_distribution<> indicator_number_dist(0, 4); - - // ESP_LOGI(TAG, "Green: %i, Red: %i, Yellow: %i, Blue: %i", green_indicators, red_indicators, yellow_indicators, blue_indicators); - - // green, red, yellow, blue, purple - const int INDICATOR_RED[5] = {0, 20, 10, 0, 10}; - const int INDICATOR_GREEN[5] = {10, 0, 5, 0, 0}; - const int INDICATOR_BLUE[5] = {0, 0, 0, 10, 5}; - - int solved_times = 0; - bool failed = false; - while (solved_times < 3 && !failed) { - int indicator_numbers[5] = {indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen)}; - - std::vector led_options = all_leds; - for (int i = 0; i < 5; i++) { - set_unique_leds(led_options, indicator_numbers[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); - } - - - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - std::uniform_int_distribution<> answer_color_dist(0, 4); - - std::map color_name_map = { - {0, "Green"}, - {1, "Red"}, - {2, "Yellow"}, - {3, "Blue"}, - {4, "Purple"}, - }; - - int answer_color = answer_color_dist(gen); - - std::string color_string = color_name_map[answer_color]; - std::string answer_num = std::to_string(indicator_numbers[answer_color]); - - // ESP_LOGI(TAG, "color string: %s", color_string.c_str()); - - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, color_string.c_str()); - - std::string entered_string; - - KeypadKey key; - while (1) { - if (get_pressed_keypad(&key)) { - if (key == KeypadKey::star) { - // clear - entered_string = ""; - } else if (key == KeypadKey::pound) { - // submit - if (entered_string != answer_num) { - strike("Incorrect answer!"); - } else { - solved_times++; - } - break; - } else { - entered_string += char_of_keypad_key(key); - } - - lcd_clear(&lcd); - lcd_set_cursor(&lcd, 1, 1); - lcd_print(&lcd, "Plink"); - lcd_set_cursor(&lcd, 1, 2); - lcd_print(&lcd, color_string.c_str()); - lcd_set_cursor(&lcd, 1, 3); - lcd_print(&lcd, entered_string.c_str()); - } - if (get_module_time() <= 0) { - strike("Ran out of time!"); - break; - } - - - vTaskDelay(pdMS_TO_TICKS(10)); - } - - break; - - } - if (!failed) { - solved_puzzles++; - solved_correctly = true; - } - } - - - } - stop_module_timer(); - if (solved_correctly) { - play_raw(MOUNT_POINT "/correct.pcm"); - vTaskDelay(pdMS_TO_TICKS(500)); - solved_correctly = false; + play_raw(MOUNT_POINT "/correct.pcm"); } else { - vTaskDelay(pdMS_TO_TICKS(3000)); + vTaskDelay(pdMS_TO_TICKS(1500)); } - clean_bomb(); + vTaskDelay(pdMS_TO_TICKS(3000)); } } + +static void generate_random_lcd_text(void) { + for (int i = 0; i < 20; i++) { + int char_idx = lcd_rand_char_dist(gen); + random_lcd_text[i] = lcd_random_char_set[char_idx]; + } + contains_coconut = (has_coconut_dist(gen) == 0); + if (contains_coconut) { + int idx = coconut_position_dist(gen); + for (int i = 0; i < 7; i++) { + random_lcd_text[idx+i] = COCONUT[i]; + // ESP_LOGI(TAG, "Writing idx %d to %c. Is %c", idx+i, COCONUT[i], random_lcd_text[idx+i]); + } + // ESP_LOGI(TAG, "Now: %s", random_lcd_text); + } +} + +/// Sets the leds to random values. +/// +/// This does not flush the leds. +static void rng_leds() { + for (int i = 0; i < LED_COUNT; i++) { + indicator_led_idxs[i] = color_dist(gen); + } +} + +static void write_leds() { + // update all the leds + for (int i = 0; i < LED_COUNT; i++) { + auto colors = NEOPIXEL_COLORS[indicator_led_idxs[i]]; + led_strip_set_pixel(leds, i, colors[0], colors[1], colors[2]); + } + led_strip_refresh(leds); +} + +static uint8_t four_bit_flag(bool b0, bool b1, bool b2, bool b3) { + return + (b0 << 0) | + (b1 << 1) | + (b2 << 2) | + (b3 << 3) + ; +} + +static void print_bin(char* out_str, uint8_t n) { + out_str[0] = ((n & 0b1000) ? '1' : '0'); + out_str[1] = ((n & 0b0100) ? '1' : '0'); + out_str[2] = ((n & 0b0010) ? '1' : '0'); + out_str[3] = ((n & 0b0001) ? '1' : '0'); + out_str[4] = ' '; + out_str[5] = 'i'; + out_str[6] = 'n'; + out_str[7] = ' '; + out_str[8] = 'o'; + out_str[9] = 'r'; + out_str[10] = 'd'; + out_str[11] = 'e'; + out_str[12] = 'r'; + out_str[13] = ':'; + out_str[14] = ' '; + out_str[15] = ((n & 0b0001) ? '1' : '0'); + out_str[16] = ((n & 0b0010) ? '1' : '0'); + out_str[17] = ((n & 0b0100) ? '1' : '0'); + out_str[18] = ((n & 0b1000) ? '1' : '0'); +} + +static void debug_correct_values(uint8_t correct_buttons, uint8_t button_mask, uint8_t correct_switches) { + char buf[20] = {0}; + print_bin(buf, correct_switches); + ESP_LOGI(TAG, "Expected Switch State: 0b%s", buf); + print_bin(buf, correct_buttons); + ESP_LOGI(TAG, "Expected Button State: 0b%s", buf); + print_bin(buf, button_mask); + ESP_LOGI(TAG, "Button Mask: 0b%s", buf); +} + +static void debug_actual_values(uint8_t buttons, uint8_t switch_) { + char buf[20] = {0}; + print_bin(buf, switch_); + ESP_LOGI(TAG, "Actual Switch State: 0b%s", buf); + print_bin(buf, buttons); + ESP_LOGI(TAG, "Actual Button State: 0b%s", buf); + ESP_LOGI(TAG, ""); +} + +static void wait_for_timer(void) { + KeypadKey key; + while (get_module_time() > 0) { + if (get_pressed_keypad(&key) && key == KeypadKey::kd) { + set_module_time(0); + return; + } + vTaskDelay(pdMS_TO_TICKS(100)); + } +} + +static bool one_second() { + clean_bomb(); + set_module_time(ONE_SECOND_TIME); + start_module_timer(); + + rng_leds(); + int speaker_color = indicator_led_idxs[Led::speaker]; + int lcd_string_idx = lcd_string_dist(gen); + bool was_high = (tone / 3) == 1; + write_leds(); + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, LCD_STRINGS[lcd_string_idx]); + + int red_led_count = 0; + int blue_led_count = 0; + for (int i = 0; i < LED_COUNT; i++) { + if (indicator_led_idxs[i] == 0) { + red_led_count++; + } else if (indicator_led_idxs[i] == 4) { + blue_led_count++; + } + } + + uint8_t correct_switches = four_bit_flag( + speaker_color == 0 || speaker_color == 1 || speaker_color == 2, + lcd_string_idx == 0 || lcd_string_idx == 1, + was_high, + !was_high + ); + + uint8_t correct_button_mask = 0b1011; + uint8_t correct_buttons = four_bit_flag( + indicator_led_idxs[Led::char_lcd] != 6, // green + red_led_count > blue_led_count, // red + 0, // yellow UNCHECKED + indicator_led_idxs[Led::rfid] == 4 || indicator_led_idxs[Led::rfid] == 6 // blue + ); + + debug_correct_values(correct_buttons, correct_button_mask, correct_switches); + + wait_for_timer(); + + debug_actual_values(get_button_state(), get_switch_state()); + + if (get_switch_state() != correct_switches) { + clean_bomb(); + strike("Incorrect Switches"); + return false; + } + if ((get_button_state() & correct_button_mask) != correct_buttons) { + clean_bomb(); + strike("Incorrect Buttons"); + return false; + } + + return true; +} + +static bool three_second() { + clean_bomb(); + set_module_time(THREE_SECOND_TIME); + start_module_timer(); + + int lcd_number = lcd_number_dist(gen); + char lcd_number_string[9] = {0}; + sprintf(lcd_number_string, "%d", lcd_number); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, lcd_number_string); + + bool was_high = (tone / 3) == 1; + + rng_leds(); + write_leds(); + int red_led_count = 0; + int blue_led_count = 0; + for (int i = 0; i < LED_COUNT; i++) { + if (indicator_led_idxs[i] == 0) { + red_led_count++; + } else if (indicator_led_idxs[i] == 4) { + blue_led_count++; + } + } + + // reverse the ordering of the bits + uint8_t correct_switches = four_bit_flag( + (lcd_number >> 3) & 1, + (lcd_number >> 2) & 1, + (lcd_number >> 1) & 1, + (lcd_number >> 0) & 1 + ); + if (!was_high) { + correct_switches = (~correct_switches) & 0b1111; + } + + uint8_t correct_button_mask = 0b1110; + uint8_t correct_buttons = four_bit_flag( + 0, // green UNCHECKED + was_high, // red + (lcd_number % 2) == 0, // yellow + blue_led_count > red_led_count // blue + ); + + debug_correct_values(correct_buttons, correct_button_mask, correct_switches); + + wait_for_timer(); + + debug_actual_values(get_button_state(), get_switch_state()); + + if (get_switch_state() != correct_switches) { + clean_bomb(); + strike("Incorrect Switches"); + return false; + } + if ((get_button_state() & correct_button_mask) != correct_buttons) { + clean_bomb(); + strike("Incorrect Buttons"); + return false; + } + + return true; +} + +static bool six_second() { + clean_bomb(); + set_module_time(SIX_SECOND_TIME); + start_module_timer(); + + generate_random_lcd_text(); + vTaskDelay(pdMS_TO_TICKS(10)); + lcd_set_cursor(&lcd, 0, 0); + lcd_print(&lcd, random_lcd_text); + + int vowels = 0; + for (int i = 0; i < 20; i++) { + char c = random_lcd_text[i]; + if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') { + vowels++; + } + } + + bool was_high = (tone / 3) == 1; + + bool second_switch_correct_state = (indicator_led_idxs[Led::switch2] == 0) || (indicator_led_idxs[Led::switch2] == 6); + second_switch_correct_state = second_switch_correct_state || was_high; + + rng_leds(); + write_leds(); + + int green_led_count = 0; + int blue_led_count = 0; + for (int i = 0; i < LED_COUNT; i++) { + if (indicator_led_idxs[i] == 4) { + blue_led_count++; + } else if (indicator_led_idxs[i] == 3) { + green_led_count++; + } + } + + int purple_led_on_bottom_count = 0; + for (int i = Led::rfid; i < LED_COUNT; i++) { + if (indicator_led_idxs[i] == 5) { + purple_led_on_bottom_count++; + } + } + + uint8_t correct_switches = four_bit_flag( + vowels > 7, + second_switch_correct_state, + true, + !(purple_led_on_bottom_count > 1) + ); + + uint8_t correct_button_mask = 0b1101; + uint8_t correct_buttons = four_bit_flag( + (!was_high) || (green_led_count >= 2) || indicator_led_idxs[Led::keypad] == 4, // green + 0, // red UNCHECKED + blue_led_count >= 3, // yellow + contains_coconut // blue + ); + + debug_correct_values(correct_buttons, correct_button_mask, correct_switches); + + wait_for_timer(); + + debug_actual_values(get_button_state(), get_switch_state()); + + if (get_switch_state() != correct_switches) { + clean_bomb(); + strike("Incorrect Switches"); + return false; + } + if ((get_button_state() & correct_button_mask) != correct_buttons) { + clean_bomb(); + strike("Incorrect Buttons"); + return false; + } + + return true; +} + diff --git a/main/steps/step3.h b/main/steps/step3.h index 3d5e900..cdb5b60 100644 --- a/main/steps/step3.h +++ b/main/steps/step3.h @@ -1,22 +1,15 @@ #ifndef STEP_3_H #define STEP_3_H -#include "../drivers/bottom_half.h" -#include "../drivers/game_timer.h" -#include "../drivers/char_lcd.h" -#include "../drivers/leds.h" -#include "../drivers/wires.h" -#include "../helper.h" #include -#include -#include -#include -#include -#include -#include - -static const char *STEP3_TAG = "step3"; +#include "../drivers/bottom_half.h" +#include "../drivers/wires.h" +#include "../drivers/speaker.h" +#include "../drivers/leds.h" +#include "../drivers/char_lcd.h" +#include "../drivers/game_timer.h" +#include "../helper.h" void step3(void); -#endif /* STEP_3_H */ \ No newline at end of file +#endif /* STEP_3_H */ diff --git a/main/steps/step4.cpp b/main/steps/step4.cpp index 96e31ae..a6f2340 100644 --- a/main/steps/step4.cpp +++ b/main/steps/step4.cpp @@ -1,401 +1,691 @@ #include "step4.h" -#define ONE_SECOND_TIME 90'000 -#define THREE_SECOND_TIME 90'000 -#define SIX_SECOND_TIME 75'000 - static const char *TAG = "step4"; -static int tone = 0; -static int times = 0; +static lv_obj_t* scr; +static lv_style_t scr_style; +static lv_obj_t* img; -static const char* TONE_FILES[] = { - MOUNT_POINT "/low-1.pcm", - MOUNT_POINT "/low-3.pcm", - MOUNT_POINT "/low-6.pcm", - MOUNT_POINT "/high-1.pcm", - MOUNT_POINT "/high-3.pcm", - MOUNT_POINT "/high-6.pcm", +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 lv_style_t game_over_style; +static lv_obj_t* game_over_label; + +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 const char* LCD_STRINGS[] = { - "something", - "nothing", - "", - "a word", - "somethink", - "what?", - "LCD", - "display", +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}, }; -static int indicator_led_idxs[LED_COUNT] = {0}; +lv_obj_t* piece_imgs[4] = {}; -static bool contains_coconut = false; -static char* COCONUT = "coconut"; -static char lcd_random_char_set[] = "aeiou tnsrhldm"; -static char random_lcd_text[21] = {0}; +TaskHandle_t music_handle; static std::random_device rd; static std::mt19937 gen(rd()); -static std::uniform_int_distribution<> tone_dist(0, 5); -static std::uniform_int_distribution<> color_dist(0, 6); -static std::uniform_int_distribution<> lcd_string_dist(0, 7); -static std::uniform_int_distribution<> lcd_number_dist(0, 15); -static std::uniform_int_distribution<> lcd_rand_char_dist(0, sizeof(lcd_random_char_set)-2); -static std::uniform_int_distribution<> has_coconut_dist(0, 2); -static std::uniform_int_distribution<> coconut_position_dist(0, 13); +static std::uniform_int_distribution<> piece_dist(2, 7); -static uint8_t NEOPIXEL_COLORS[7][3] = { - {20, 0, 0}, // red - {20, 10, 0}, // orange - {20, 20, 0}, // yellow - {0, 20, 0}, // green - {0, 0, 20}, // blue - {20, 0, 20}, // purple - {0, 0, 0}, // off -}; +static void generate_block(void); +static void show_board(void); +static void get_node_locations(void); +static bool check_overlap(void); -static bool one_second(); -static bool three_second(); -static bool six_second(); +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)); + + lv_style_init(&game_over_style); + lv_style_set_text_color(&game_over_style, lv_color_white()); + lv_style_set_bg_color(&game_over_style, lv_color_black()); + lv_style_set_bg_opa(&game_over_style, LV_OPA_100); + lv_style_set_text_align(&game_over_style, LV_TEXT_ALIGN_CENTER); + + game_over_label = lv_label_create(lv_scr_act()); + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_align(game_over_label, LV_ALIGN_CENTER, 0, 0); + lv_obj_add_style(game_over_label, &game_over_style, LV_STATE_DEFAULT); + + // 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) { + game = true; + target_score = required_score; + score = 0; + update_score(); + set_module_time(time); + start_module_timer(); + + clear_board(); + + generate_block(); + show_board(); + + ButtonKey button; + while (get_pressed_button(&button)); + // SwitchKey switch_; + + const TickType_t first_repeat_time = pdMS_TO_TICKS(700); + const TickType_t repeat_time = pdMS_TO_TICKS(100); + TickType_t down_held = 0; + TickType_t last_repeat = 0; + + while(game) { + if (get_pressed_button(&button)) { + switch (button) { + case ButtonKey::b1: + move_left(); + break; + case ButtonKey::b2: + move_right(); + break; + case ButtonKey::b3: + down_held = xTaskGetTickCount(); + last_repeat = 0; + drop(); + break; + case ButtonKey::b4: + rotate_block(); + break; + } + + show_board(); + + if (score >= required_score) { + stop_module_timer(); + return true; + } + } + if (get_released_button(&button)) { + if (button == ButtonKey::b3) { + down_held = 0; + } + } + + if (down_held != 0) { + // check repeat + TickType_t now = xTaskGetTickCount(); + if (now - down_held > first_repeat_time) { + // repeat! + if (now - last_repeat > repeat_time) { + last_repeat = now; + drop(); + 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; +} + +static void complete(void) { + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_label_set_text(game_over_label, "Winner!\nPress any button to continue"); + lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } + vTaskDelay(pdMS_TO_TICKS(500)); + while (get_pressed_button(nullptr)); + while (1) { + if (get_pressed_button(nullptr)) break; + vTaskDelay(pdMS_TO_TICKS(10)); + } + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } +} + +static void fail(void) { + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_label_set_text(game_over_label, "Game Over\nPress any button to continue"); + lv_obj_clear_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } + vTaskDelay(pdMS_TO_TICKS(500)); + while (get_pressed_button(nullptr)); + while (1) { + if (get_pressed_button(nullptr)) break; + vTaskDelay(pdMS_TO_TICKS(10)); + } + if (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdTRUE) { + lv_obj_add_flag(game_over_label, LV_OBJ_FLAG_HIDDEN); + xSemaphoreGive(xGuiSemaphore); + } +} void step4(void) { - StarCodeHandler star_codes[] = { - { - .code = "*1642", - .display_text = "Starting...", - .should_exit = true, - .callback = nullptr, - }, + StarCodeHandler star_code = { + .code = "*3850", + .display_text = "Starting...", + .should_exit = true, + .callback = nullptr, }; - int len = sizeof(star_codes)/sizeof(StarCodeHandler); - do_star_codes(star_codes, len); + do_star_codes(&star_code, 1); + init_screen(); - while (times < 4) { - tone = tone_dist(gen); - // tone = 2; - while (get_pressed_button(nullptr)) vTaskDelay(pdMS_TO_TICKS(10)); + while (!play_game(4*60*1000, 2)) fail(); + complete(); + while (!play_game(4*60*1000, 4)) fail(); + complete(); + while (!play_game(6*60*1000, 8)) fail(); + complete(); - play_raw(MOUNT_POINT "/que.pcm"); - play_raw(TONE_FILES[tone]); + 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] = 18; + 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(); + + // Check overlap without moving + if (check_overlap()) { - bool correct = false; - switch (tone % 3) { - case 0: - correct = one_second(); - break; - case 1: - correct = three_second(); - break; - case 2: - correct = six_second(); - break; + // Check overlap after moving up 1 + piece_location[0]--; + get_node_locations(); + if (check_overlap()) { + + // Check overlap after moving down 1 + piece_location[0]++; + piece_location[0]++; + get_node_locations(); + if (check_overlap()) { + + // Check overlap after moving left 1 + piece_location[0]--; + piece_location[1]--; + get_node_locations(); + if (check_overlap()) { + + // Check overlap after moving right 1 + piece_location[1]++; + piece_location[1]++; + get_node_locations(); + if (check_overlap()) { + piece_location[1]--; + // This is Original Position + + // If Line Piece, check 2 left, 2 right, 2 up and 2 down + + // Check 2 left + if (piece == 1 && piece_rotation == 0) { + piece_location[1]-=2; + get_node_locations(); + if (check_overlap()) { + piece_location[1]+=2; + get_node_locations(); + } + // Check 2 up + } else if (piece == 1 && piece_rotation == 1) { + piece_location[0]+=2; + get_node_locations(); + if (check_overlap()) { + piece_location[0]-=2; + get_node_locations(); + } + // Check 2 right + } else if (piece == 1 && piece_rotation == 2) { + piece_location[1]+=2; + get_node_locations(); + if (check_overlap()) { + piece_location[1]-=2; + get_node_locations(); + } + // Check 2 down + } else if (piece == 1 && piece_rotation == 3) { + piece_location[0]-=2; + get_node_locations(); + if (check_overlap()) { + piece_location[0]+=2; + get_node_locations(); + } + } + } + } + } } - if (correct) { - times++; - clean_bomb(); - play_raw(MOUNT_POINT "/correct.pcm"); - } else { - vTaskDelay(pdMS_TO_TICKS(1500)); + } +} + +// Check if nodes are outside of map or interposed onto placed nodes +static bool check_overlap(void) { + for (int i = 0; i < sizeof(piece_nodes)/sizeof(piece_nodes[0]); i++) { + int* p = piece_nodes[i]; + if (p[0] < 0 || p[1] < 0 || p[1] >= width) { + return true; + } else if (board[p[0]][p[1]] != 0 && board[p[0]][p[1]] != 9) { + return true; } - vTaskDelay(pdMS_TO_TICKS(3000)); } + return false; } -static void generate_random_lcd_text(void) { - for (int i = 0; i < 20; i++) { - int char_idx = lcd_rand_char_dist(gen); - random_lcd_text[i] = lcd_random_char_set[char_idx]; - } - contains_coconut = (has_coconut_dist(gen) == 0); - if (contains_coconut) { - int idx = coconut_position_dist(gen); - for (int i = 0; i < 7; i++) { - random_lcd_text[idx+i] = COCONUT[i]; - // ESP_LOGI(TAG, "Writing idx %d to %c. Is %c", idx+i, COCONUT[i], random_lcd_text[idx+i]); - } - // ESP_LOGI(TAG, "Now: %s", random_lcd_text); - } -} - -/// Sets the leds to random values. -/// -/// This does not flush the leds. -static void rng_leds() { - for (int i = 0; i < LED_COUNT; i++) { - indicator_led_idxs[i] = color_dist(gen); - } -} - -static void write_leds() { - // update all the leds - for (int i = 0; i < LED_COUNT; i++) { - auto colors = NEOPIXEL_COLORS[indicator_led_idxs[i]]; - led_strip_set_pixel(leds, i, colors[0], colors[1], colors[2]); - } - led_strip_refresh(leds); -} - -static uint8_t four_bit_flag(bool b0, bool b1, bool b2, bool b3) { - return - (b0 << 0) | - (b1 << 1) | - (b2 << 2) | - (b3 << 3) - ; -} - -static void print_bin(char* out_str, uint8_t n) { - out_str[0] = ((n & 0b1000) ? '1' : '0'); - out_str[1] = ((n & 0b0100) ? '1' : '0'); - out_str[2] = ((n & 0b0010) ? '1' : '0'); - out_str[3] = ((n & 0b0001) ? '1' : '0'); - out_str[4] = ' '; - out_str[5] = 'i'; - out_str[6] = 'n'; - out_str[7] = ' '; - out_str[8] = 'o'; - out_str[9] = 'r'; - out_str[10] = 'd'; - out_str[11] = 'e'; - out_str[12] = 'r'; - out_str[13] = ':'; - out_str[14] = ' '; - out_str[15] = ((n & 0b0001) ? '1' : '0'); - out_str[16] = ((n & 0b0010) ? '1' : '0'); - out_str[17] = ((n & 0b0100) ? '1' : '0'); - out_str[18] = ((n & 0b1000) ? '1' : '0'); -} - -static void debug_correct_values(uint8_t correct_buttons, uint8_t button_mask, uint8_t correct_switches) { - char buf[20] = {0}; - print_bin(buf, correct_switches); - ESP_LOGI(TAG, "Expected Switch State: 0b%s", buf); - print_bin(buf, correct_buttons); - ESP_LOGI(TAG, "Expected Button State: 0b%s", buf); - print_bin(buf, button_mask); - ESP_LOGI(TAG, "Button Mask: 0b%s", buf); -} - -static void debug_actual_values(uint8_t buttons, uint8_t switch_) { - char buf[20] = {0}; - print_bin(buf, switch_); - ESP_LOGI(TAG, "Actual Switch State: 0b%s", buf); - print_bin(buf, buttons); - ESP_LOGI(TAG, "Actual Button State: 0b%s", buf); - ESP_LOGI(TAG, ""); -} - -static void wait_for_timer(void) { - KeypadKey key; - while (get_module_time() > 0) { - if (get_pressed_keypad(&key) && key == KeypadKey::kd) { - set_module_time(0); +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; } - vTaskDelay(pdMS_TO_TICKS(100)); + } + + 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 bool one_second() { - clean_bomb(); - set_module_time(ONE_SECOND_TIME); - start_module_timer(); +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; + } + } + } +} - rng_leds(); - int speaker_color = indicator_led_idxs[Led::speaker]; - int lcd_string_idx = lcd_string_dist(gen); - bool was_high = (tone / 3) == 1; - write_leds(); +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, LCD_STRINGS[lcd_string_idx]); - - int red_led_count = 0; - int blue_led_count = 0; - for (int i = 0; i < LED_COUNT; i++) { - if (indicator_led_idxs[i] == 0) { - red_led_count++; - } else if (indicator_led_idxs[i] == 4) { - blue_led_count++; - } - } - - uint8_t correct_switches = four_bit_flag( - speaker_color == 0 || speaker_color == 1 || speaker_color == 2, - lcd_string_idx == 0 || lcd_string_idx == 1, - was_high, - !was_high - ); - - uint8_t correct_button_mask = 0b1011; - uint8_t correct_buttons = four_bit_flag( - indicator_led_idxs[Led::char_lcd] != 6, // green - red_led_count > blue_led_count, // red - 0, // yellow UNCHECKED - indicator_led_idxs[Led::rfid] == 4 || indicator_led_idxs[Led::rfid] == 6 // blue - ); - - debug_correct_values(correct_buttons, correct_button_mask, correct_switches); - - wait_for_timer(); - - debug_actual_values(get_button_state(), get_switch_state()); - - if (get_switch_state() != correct_switches) { - clean_bomb(); - strike("Incorrect Switches"); - return false; - } - if ((get_button_state() & correct_button_mask) != correct_buttons) { - clean_bomb(); - strike("Incorrect Buttons"); - return false; - } - - return true; + lcd_print(&lcd, buff); } -static bool three_second() { - clean_bomb(); - set_module_time(THREE_SECOND_TIME); - start_module_timer(); - - int lcd_number = lcd_number_dist(gen); - char lcd_number_string[9] = {0}; - sprintf(lcd_number_string, "%d", lcd_number); - lcd_set_cursor(&lcd, 1, 1); - lcd_print(&lcd, lcd_number_string); - - bool was_high = (tone / 3) == 1; - - rng_leds(); - write_leds(); - int red_led_count = 0; - int blue_led_count = 0; - for (int i = 0; i < LED_COUNT; i++) { - if (indicator_led_idxs[i] == 0) { - red_led_count++; - } else if (indicator_led_idxs[i] == 4) { - blue_led_count++; +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]; } } - - // reverse the ordering of the bits - uint8_t correct_switches = four_bit_flag( - (lcd_number >> 3) & 1, - (lcd_number >> 2) & 1, - (lcd_number >> 1) & 1, - (lcd_number >> 0) & 1 - ); - if (!was_high) { - correct_switches = (~correct_switches) & 0b1111; + for (int w = 0; w < width; w++) { + board[height-1][w] = 0; } + score++; + update_score(); - uint8_t correct_button_mask = 0b1110; - uint8_t correct_buttons = four_bit_flag( - 0, // green UNCHECKED - was_high, // red - (lcd_number % 2) == 0, // yellow - blue_led_count > red_led_count // blue - ); - - debug_correct_values(correct_buttons, correct_button_mask, correct_switches); - - wait_for_timer(); - - debug_actual_values(get_button_state(), get_switch_state()); - - if (get_switch_state() != correct_switches) { - clean_bomb(); - strike("Incorrect Switches"); - return false; - } - if ((get_button_state() & correct_button_mask) != correct_buttons) { - clean_bomb(); - strike("Incorrect Buttons"); - return false; + 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)); } - - return true; } -static bool six_second() { - clean_bomb(); - set_module_time(SIX_SECOND_TIME); - start_module_timer(); - - generate_random_lcd_text(); - vTaskDelay(pdMS_TO_TICKS(10)); - lcd_set_cursor(&lcd, 0, 0); - lcd_print(&lcd, random_lcd_text); - - int vowels = 0; - for (int i = 0; i < 20; i++) { - char c = random_lcd_text[i]; - if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') { - vowels++; +void clear_board(void) { + for (int h = 0; h < height; h++) { + for (int w = 0; w < width; w++) { + board[h][w] = 0; } } - - bool was_high = (tone / 3) == 1; - - bool second_switch_correct_state = (indicator_led_idxs[Led::switch2] == 0) || (indicator_led_idxs[Led::switch2] == 6); - second_switch_correct_state = second_switch_correct_state || was_high; - - rng_leds(); - write_leds(); - - int green_led_count = 0; - int blue_led_count = 0; - for (int i = 0; i < LED_COUNT; i++) { - if (indicator_led_idxs[i] == 4) { - blue_led_count++; - } else if (indicator_led_idxs[i] == 3) { - green_led_count++; - } - } - - int purple_led_on_bottom_count = 0; - for (int i = Led::rfid; i < LED_COUNT; i++) { - if (indicator_led_idxs[i] == 5) { - purple_led_on_bottom_count++; - } - } - - uint8_t correct_switches = four_bit_flag( - vowels > 7, - second_switch_correct_state, - true, - !(purple_led_on_bottom_count > 1) - ); - - uint8_t correct_button_mask = 0b1101; - uint8_t correct_buttons = four_bit_flag( - (!was_high) || (green_led_count >= 2) || indicator_led_idxs[Led::keypad] == 4, // green - 0, // red UNCHECKED - blue_led_count >= 3, // yellow - contains_coconut // blue - ); - - debug_correct_values(correct_buttons, correct_button_mask, correct_switches); - - wait_for_timer(); - - debug_actual_values(get_button_state(), get_switch_state()); - - if (get_switch_state() != correct_switches) { - clean_bomb(); - strike("Incorrect Switches"); - return false; - } - if ((get_button_state() & correct_button_mask) != correct_buttons) { - clean_bomb(); - strike("Incorrect Buttons"); - return false; - } - - return true; } - diff --git a/main/steps/step4.h b/main/steps/step4.h index 358a540..e4a45f5 100644 --- a/main/steps/step4.h +++ b/main/steps/step4.h @@ -2,14 +2,22 @@ #define STEP_4_H #include -#include "../drivers/bottom_half.h" -#include "../drivers/wires.h" +#include "../drivers/tft.h" #include "../drivers/speaker.h" -#include "../drivers/leds.h" -#include "../drivers/char_lcd.h" +#include "../drivers/bottom_half.h" #include "../drivers/game_timer.h" +#include "../drivers/wires.h" +#include "../drivers/char_lcd.h" #include "../helper.h" +// TODO: +// - [ ] set up real game loop +// - [ ] stop music +// - [ ] set up strike on falure +// - [ ] set up module timer + + + void step4(void); -#endif /* STEP_4_H */ +#endif /* STEP_4_H */ \ No newline at end of file diff --git a/main/steps/step5.cpp b/main/steps/step5.cpp index 2ba0d23..6c84d41 100644 --- a/main/steps/step5.cpp +++ b/main/steps/step5.cpp @@ -2,123 +2,958 @@ static const char *TAG = "step5"; -// one: 0b00000110 -// seven: 0b00000111 -static const uint8_t SSEG_NUMS[8] = {0b00111111, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b01111111, 0b01101111}; -static const uint8_t SSEG_MAPS[5][4] = { - {0b0101101, 0b1111010, 0b1000010, 0b1010100}, - {0b01000101, 0b00100100, 0b00110110, 0b01111011}, - {0b00101010, 0b00000010, 0b00010111, 0b00111100}, - {0b00111000, 0b01010010, 0b00101011, 0b00111010}, - {0b01000111, 0b00011001, 0b01111000, 0b00111110} -}; - -static const int INDICATOR_RED[5] = {15, 0, 0, 10, 5}; -static const int INDICATOR_GREEN[5] = {0, 0, 10, 5, 5}; -static const int INDICATOR_BLUE[5] = {0, 10, 0, 0, 5}; - -// random number generators static std::random_device rd; static std::mt19937 gen(rd()); -static std::uniform_int_distribution<> answer_dist(0, 7); -static std::uniform_int_distribution<> map_dist(0, 4); -static std::uniform_int_distribution<> display_dist(0, 3); -static std::uniform_int_distribution<> random_segment_dist(0, 127); +static std::uniform_int_distribution<> puzzle_dist(0, 7); +static std::uniform_int_distribution<> led_picker_dist(0, 20); +static std::uniform_int_distribution<> led_color_dist(0, 5); -static int answer = 0; -static uint8_t answer_sseg = SSEG_NUMS[0]; -static char answer_char = '0'; -static uint8_t display_map[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000}; -static int chosen_map = 0; - -std::map number_map = { - {0, 0}, - {1, 2}, - {2, 3}, - {3, 4}, - {4, 5}, - {5, 6}, - {6, 8}, - {7, 9}, -}; - -static void new_puzzle(void) { - // scramble lights - for (int i = 0; i < 5; i++) { - led_strip_set_pixel(leds, 9, INDICATOR_RED[map_dist(gen)], INDICATOR_GREEN[map_dist(gen)], INDICATOR_BLUE[map_dist(gen)]); - led_strip_refresh(leds); - - uint8_t random_segments[4] = {0, 0, 0, 0}; - for (int i = 0; i < 4; i++) { - random_segments[i] = random_segment_dist(gen); - } - set_module_sseg_raw(random_segments); - vTaskDelay(pdMS_TO_TICKS(100)); +void set_unique_leds(std::vector& input_options, const int num, const int r, const int g, const int b) { + for (int i = 0; i < num; i++) { + std::uniform_int_distribution<> led_option_dist(0, input_options.size() - 1); + int led = led_option_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, input_options[led], r, g, b)); + input_options.erase(input_options.begin() + led); } +} - answer = answer_dist(gen); - answer_sseg = SSEG_NUMS[answer]; - // convert answer to number value to account for missing 1 and 7 - answer = number_map[answer]; - answer_char = '0' + answer; - // ESP_LOGI(TAG, "Answer: %i", answer); +void set_unique_leds_random_color(std::vector& input_options, const int num, const int* r, const int* g, const int* b) { + for (int i = 0; i < num; i++) { + std::uniform_int_distribution<> led_option_dist(0, input_options.size() - 1); + int led = led_option_dist(gen); - chosen_map = map_dist(gen); - for (int i = 0; i < 4; ++i) { - display_map[i] = SSEG_MAPS[chosen_map][i]; + std::uniform_int_distribution<> led_color_dist(0, sizeof(r) - 1); + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, input_options[led], r[color], g[color], b[color])); + input_options.erase(input_options.begin() + led); } - // ESP_LOGI(TAG, "Chosen Map: %i", chosen_map); +} - ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, INDICATOR_RED[chosen_map], INDICATOR_GREEN[chosen_map], INDICATOR_BLUE[chosen_map])); - ESP_ERROR_CHECK(led_strip_refresh(leds)); - - for (int i = 0; i < 8; i++) { - bool bit = (answer_sseg >> i) & 1; - if (bit == 1) { - // choose display and flip bit - int display = display_dist(gen); - display_map[display] ^= (1 << i); - // ESP_LOGI(TAG, "Flipping bit %i on display %i", i, display); - } +std::vector unique_values(std::vector& input_options, int num) { + std::vector output_vec; + for (int i = 0; i < num; i++) { + std::uniform_int_distribution<> option_num_dist(0, input_options.size() - 1); + int option_num = option_num_dist(gen); + output_vec.push_back(input_options[option_num]); + input_options.erase(input_options.begin() + option_num); } + return output_vec; } void step5(void) { - KeypadKey key; - int solved_times = 0; + StarCodeHandler star_codes[] = { + { + .code = "*2648", + .display_text = "Starting...", + .should_exit = true, + .callback = nullptr, + }, + }; + int len = sizeof(star_codes)/sizeof(StarCodeHandler); + do_star_codes(star_codes, len); - new_puzzle(); - int strike_time = xTaskGetTickCount(); - bool striked = false; - while(solved_times < 4) { - // for every bit in the answer- - set_module_sseg_raw(display_map); - if (get_pressed_keypad(&key)) { - lcd_clear(&lcd); - char c = char_of_keypad_key(key); - // ESP_LOGI(TAG, "Pressed: %c", c); - if (c == answer_char) { - play_raw(MOUNT_POINT "/correct.pcm"); - solved_times++; - if (solved_times < 3) { - clean_bomb(); - new_puzzle(); - } else { - uint8_t display_tmp[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000}; - set_module_sseg_raw(display_tmp); - } - } else { - strike_time = xTaskGetTickCount(); - striked = true; - strike("Incorrect Character!"); - } - } + std::vector all_leds; - if (xTaskGetTickCount() - strike_time > pdMS_TO_TICKS(5000)) { - striked = false; - lcd_clear(&lcd); - } - vTaskDelay(pdMS_TO_TICKS(10)); + for (int i = 0; i < 21; i++) { + all_leds.push_back(i); } + const int INDICATOR_RED[6] = {20, 0, 0, 10, 10, 5}; + const int INDICATOR_GREEN[6] = {0, 0, 10, 5, 0, 5}; + const int INDICATOR_BLUE[6] = {0, 10, 0, 0, 5, 5}; + static std::uniform_int_distribution<> led_number_dist(0, 21); + + int last_cycle_tick = xTaskGetTickCount(); + int scrambled_times = 0; + while (scrambled_times < 5) { + if ((xTaskGetTickCount() - last_cycle_tick) > pdMS_TO_TICKS(100)) { + clean_bomb(); + std::vector led_options = all_leds; + set_unique_leds_random_color(led_options, led_number_dist(gen), INDICATOR_RED, INDICATOR_GREEN, INDICATOR_BLUE); + ESP_ERROR_CHECK(led_strip_refresh(leds)); + last_cycle_tick = xTaskGetTickCount(); + scrambled_times++; + } + } + + clean_bomb(); + int solved_puzzles = 0; + while (solved_puzzles < 3) { + lcd_set_cursor(&lcd, 1, 1); + + int puzzle = puzzle_dist(gen); + // int puzzle = 6; + + bool solved_correctly = false; + switch (puzzle) { + case 0: { + lcd_print(&lcd, "Clear"); + set_module_time(15000); + start_module_timer(); + + std::vector indicator_options = all_leds; + + // set green + std::uniform_int_distribution<> green_indicators_dist(1, 15); + uint8_t green_indicators = green_indicators_dist(gen); + set_unique_leds(indicator_options, green_indicators, 0, 10, 0); + + // set non-green + const int NON_GREEN_INDICATOR_RED[3] = {30, 0, 15}; + const int NON_GREEN_INDICATOR_GREEN[3] = {0, 0, 0}; + const int NON_GREEN_INDICATOR_BLUE[3] = {0, 30, 15}; + std::uniform_int_distribution<> non_green_indicators_dist(0, (20 - green_indicators)); + set_unique_leds_random_color(indicator_options, non_green_indicators_dist(gen), NON_GREEN_INDICATOR_RED, NON_GREEN_INDICATOR_GREEN, NON_GREEN_INDICATOR_BLUE); + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + // wait for time + while (1) { + if (get_module_time() <= 0) { + uint8_t state = get_switch_state(); + uint8_t flipped_state = 0; + flipped_state |= (state & 0x01) << 3; + flipped_state |= (state & 0x02) << 1; + flipped_state |= (state & 0x04) >> 1; + flipped_state |= (state & 0x08) >> 3; + + if (flipped_state == green_indicators) { + solved_puzzles++; + } else { + strike("Incorrect Switches"); + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + break; + } + case 1: { + lcd_print(&lcd, "Blank"); + set_module_time(30000); + start_module_timer(); + + std::uniform_int_distribution<> on_indicators_dist(16, 21); + uint8_t indicators_num = on_indicators_dist(gen); + + std::vector indicator_options = all_leds; + const int INDICATOR_RED[6] = {20, 0, 0, 10, 10, 5}; + const int INDICATOR_GREEN[6] = {0, 0, 10, 5, 0, 5}; + const int INDICATOR_BLUE[6] = {0, 10, 0, 0, 5, 5}; + + set_unique_leds_random_color(indicator_options, indicators_num, INDICATOR_RED, INDICATOR_BLUE, INDICATOR_GREEN); + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + // ESP_LOGI(TAG, "puzzle 1 LEDs set (%i leds)", indicators_num); + + if (indicators_num < 18) { + while (1) { + if (get_module_time() <= 0) { + if (get_switch_state() == 0b1111) { + solved_puzzles++; + // ESP_LOGI(TAG, "puzzle 1 solved (switches)!"); + } else { + strike("Switch State Changed"); + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + } else { + uint8_t starting_switch_state = get_switch_state(); + KeypadKey key; + std::string pressed_keys; + while (1) { + if (get_pressed_keypad(&key)) { + pressed_keys += char_of_keypad_key(key); + // ESP_LOGI(TAG, "key %c pressed", char_of_keypad_key(key)); + } + if (get_module_time() <= 0) { + if (starting_switch_state == get_switch_state()) { + if (pressed_keys == "ADCB") { + solved_puzzles++; + solved_correctly = true; + // ESP_LOGI(TAG, "puzzle 1 solved (keypad)!"); + } + } else { + strike("Switches Changed!"); + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + } + + + + break; + } + case 2: { + set_module_time(30000); + start_module_timer(); + + std::uniform_int_distribution<> lit_led_dist(0, 1); + bool rfid_lit = lit_led_dist(gen); + bool lcd_lit = lit_led_dist(gen); + bool speaker_lit = lit_led_dist(gen); + bool keypad_lit = lit_led_dist(gen); + bool tft_lit = lit_led_dist(gen); + + if (rfid_lit) { + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 10, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); + } + if (lcd_lit) { + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 12, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); + } + if (speaker_lit) { + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); + } + if (keypad_lit) { + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 11, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); + } + if (tft_lit) { + int color = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 6, INDICATOR_RED[color], INDICATOR_GREEN[color], INDICATOR_BLUE[color])); + } + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + int green_button_pressed = 0; + // ESP_LOGI(TAG, "green pressed: %i", green_button_pressed); + int blue_button_pressed = 0; + int fingerprint_sensor_pressed = 0; + std::string keypad_string; + + ButtonKey button; + KeypadKey key; + SwitchKey switch1 = s1; + SwitchKey switch2 = s2; + + while (1) { + if (get_pressed_button(&button)) { + uint8_t button_state = get_button_state(); + // ESP_LOGI(TAG, "Button pressed! (%i)", button_state()); + + if ((button_state & 0b1) == 0b1) { + green_button_pressed++; + if ((green_button_pressed > 1) || !rfid_lit) { + strike("Too many times!"); + break; + } + } + if ((button_state & 0b1000) == 0b1000) { + blue_button_pressed++; + if ((blue_button_pressed > 1) || !lcd_lit) { + strike("Too many times!"); + break; + } + } + } + if (get_touch_pressed()) { + fingerprint_sensor_pressed++; + if ((fingerprint_sensor_pressed > 2) || !speaker_lit) { + strike("Too many times!"); + break; + } + } + if (get_pressed_keypad(&key)) { + bool wrong = false; + keypad_string += char_of_keypad_key(key); + switch (keypad_string.length()) { + case 1: { + if (keypad_string != "1") { + strike("Incorrect Keypad!"); + wrong = true; + } + break; + } + case 2: { + if (keypad_string != "12") { + strike("Incorrect Keypad!"); + wrong = true; + } + break; + } + default: { + strike("Incorrect Keypad!"); + wrong = true; + break; + } + } + if (wrong) { + break; + } + } + if (get_flipped_up_switch(&switch1) || get_flipped_up_switch(&switch2)) { + if (!tft_lit) { + strike("Incorrect Switches"); + break; + } + } + if (get_module_time() <= 0) { + bool rfid_correct = !(rfid_lit && (green_button_pressed != 1)); + bool lcd_correct = !(lcd_lit && (blue_button_pressed != 1)); + bool speaker_correct = !(speaker_lit && (fingerprint_sensor_pressed != 2)); + bool keypad_correct = !(keypad_lit && (keypad_string != "12")); + bool tft_correct = !(tft_lit && ((get_switch_state() & 0b11) != 0b11)); + + if (rfid_correct && lcd_correct && speaker_correct && keypad_correct && tft_correct) { + solved_puzzles++; + solved_correctly = true; + } else { + strike("Incorrect state!"); + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + break; + } + case 3: { + lcd_print(&lcd, "Nothing"); + set_module_time(20000); + start_module_timer(); + + const int COLOR_RED[5] = {0, 20, 10, 0, 0}; + const int COLOR_GREEN[5] = {20, 0, 10, 0, 0}; + const int COLOR_BLUE[5] = {0, 0, 0, 20, 0}; + + static std::uniform_int_distribution<> color_dist(0, 4); + + int tft_color = color_dist(gen); + int speaker_color = color_dist(gen); + int s3_color = color_dist(gen); + + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 6, COLOR_RED[tft_color], COLOR_GREEN[tft_color], COLOR_BLUE[tft_color])); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 9, COLOR_RED[speaker_color], COLOR_GREEN[speaker_color], COLOR_BLUE[speaker_color])); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, 14, COLOR_RED[s3_color], COLOR_GREEN[s3_color], COLOR_BLUE[s3_color])); + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + int buttons_pressed = 0; + + ButtonKey button; + + while (1) { + if (get_pressed_button(&button)) { + buttons_pressed++; + uint8_t button_state = get_button_state(); + + if (buttons_pressed == 1) { + if ((button_state >> tft_color) != 0b1) { + strike("Wrong button!"); + break; + } + } else if (buttons_pressed == 2) { + if ((button_state >> speaker_color) != 0b1) { + strike("Wrong button!"); + break; + } + } else if (buttons_pressed == 3) { + if ((button_state >> s3_color) != 0b1) { + strike("Wrong button!"); + } else { + solved_puzzles++; + solved_correctly = true; + } + break; + } + + } + if (get_module_time() <= 0) { + strike("Ran out of time!"); + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + + + break; + } + case 4: { + lcd_print(&lcd, "Blink"); + set_module_time(30000); + start_module_timer(); + + // buttons + const int BUTTON_COLOR_RED[4] = {0, 20, 10, 0}; + const int BUTTON_COLOR_GREEN[4] = {10, 0, 5, 0}; + const int BUTTON_COLOR_BLUE[4] = {0, 0, 0, 10}; + + static std::uniform_int_distribution<> button_color_dist(0, 3); + int button_colors[4] = {button_color_dist(gen), button_color_dist(gen), button_color_dist(gen), button_color_dist(gen)}; + + for (int i = 0; i < 4; i++) { + ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), BUTTON_COLOR_RED[button_colors[i]], BUTTON_COLOR_GREEN[button_colors[i]], BUTTON_COLOR_BLUE[button_colors[i]])); + } + + // switches + const int SWITCH_COLOR_RED[3] = {20, 0, 10}; + const int SWITCH_COLOR_GREEN[3] = {0, 10, 5}; + + static std::uniform_int_distribution<> switch_color_dist(0, 2); + + int switch_colors[4] = {switch_color_dist(gen), switch_color_dist(gen), switch_color_dist(gen), switch_color_dist(gen)}; + + for (int i = 0; i < 4; i++) { + ESP_ERROR_CHECK(led_strip_set_pixel(leds, (16 - i), SWITCH_COLOR_RED[switch_colors[i]], SWITCH_COLOR_GREEN[switch_colors[i]], 0)); + } + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + ButtonKey button; + SwitchKey switch_key; + uint8_t starting_switch_state = get_switch_state(); + + while (1) { + if (get_pressed_button(&button)) { + uint8_t button_state = get_button_state(); + + for (int i = 0; i < 4; i++) { + if (((button_state >> i) & 0b1) == 0b1) { + button_colors[i]++; + if (button_colors[i] > 3) { + button_colors[i] = 0; + } + ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), BUTTON_COLOR_RED[button_colors[i]], BUTTON_COLOR_GREEN[button_colors[i]], BUTTON_COLOR_BLUE[button_colors[i]])); + } + + } + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { + // check switch state + uint8_t switch_state = get_switch_state(); + bool correct = true; + + for (int i = 0; i < 4; i++) { + if (switch_colors[i] == 2) { + if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { + correct = false; + break; + } + } else { + if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { + correct = false; + break; + } + } + } + + if (correct) { + solved_puzzles++; + solved_correctly = true; + break; + } + } + } + if (get_flipped_switch(&switch_key)) { + if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { + // check switch state + uint8_t switch_state = get_switch_state(); + bool correct = true; + + for (int i = 0; i < 4; i++) { + if (switch_colors[i] == 2) { + if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { + correct = false; + break; + } + } else { + if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { + correct = false; + break; + } + } + } + + if (correct) { + solved_puzzles++; + solved_correctly = true; + break; + } + } + } + if (get_module_time() <= 0) { + // check button state + if (button_colors[0] == 0 && button_colors[1] == 1 && button_colors[2] == 2 && button_colors[3] == 3) { + // check switch state + uint8_t switch_state = get_switch_state(); + bool correct = true; + // ESP_LOGI(TAG, "starting switch state: %i, current switch state: %i", starting_switch_state, switch_state); + + + + for (int i = 0; i < 4; i++) { + if (switch_colors[i] == 2) { + // ESP_LOGI(TAG, "color yellow triggered: %i", (((switch_state ^ starting_switch_state) >> i) & 0b1)); + if ((((switch_state ^ starting_switch_state) >> i) & 0b1) != 1) { + correct = false; + break; + } + } else { + // ESP_LOGI(TAG, "color green or red triggered: %i != %i", ((switch_state >> i) & 0b1), (switch_colors[i] & 0b1)); + if (((switch_state >> i) & 0b1) != (switch_colors[i] & 0b1)) { + correct = false; + break; + } + } + } + + if (correct) { + solved_puzzles++; + solved_correctly = true; + } else { + strike("Wrong switch state!"); + } + } else { + strike("Wrong button state!"); + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + + break; + } + case 5: { + lcd_print(&lcd, "Ummm"); + set_module_time(30000); + start_module_timer(); + + std::uniform_int_distribution<> indicator_number_dist(0, 5); + + const int INDICATOR_RED[4] = {0, 20, 10, 10}; + const int INDICATOR_GREEN[4] = {10, 0, 5, 5}; + const int INDICATOR_BLUE[4] = {0, 0, 0, 10}; + + // green, red, yellow, blue + std::array indicator_numbers = {indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen)}; + std::vector indicator_options = all_leds; + + for (int i = 0; i < 4; i++) { + set_unique_leds(indicator_options, indicator_numbers[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); + } + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + std::array buttons_pressed = {0, 0, 0, 0}; + + ButtonKey button; + + while (1) { + if (get_pressed_button(&button)) { + uint8_t button_state = get_button_state(); + + for (int i = 0; i < 4; i++) { + if (((button_state >> i) & 0b1) == 0b1) { + buttons_pressed[i]++; + if (buttons_pressed[i] > indicator_numbers[i]) { + strike("Too many times!"); + break; + } + } + } + } + if (get_module_time() <= 0) { + // check for correct button presses + for (int i = 0; i < 4; i++) { + if (buttons_pressed == indicator_numbers) { + strike("Wrong button state!"); + break; + } + } + + uint8_t switch_state = get_switch_state(); + + // check for correct switch states + for (int i = 0; i < 4; i++) { + if (((switch_state >> i) & 0b1) == (indicator_numbers[i] & 0b1)) { + strike("Wrong switch state!"); + break; + } + } + + solved_puzzles++; + solved_correctly = true; + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + + + break; + } + case 6: { + lcd_print(&lcd, "Plank"); + set_module_time(40000); + start_module_timer(); + + std::uniform_int_distribution<> led_color_dist(0, 5); + std::uniform_int_distribution<> led_off_dist(-1, 3); + + // red, purple, blue, white, green, yellow + const uint8_t COLORS_RED[6] = {20, 10, 0, 5, 0, 10}; + const uint8_t COLORS_GREEN[6] = {0, 0, 0, 5, 10, 5}; + const uint8_t COLORS_BLUE[6] = {0, 10, 10, 5, 0, 0}; + + int button_colors[4]; + bool buttons_cycling[4]; + int led_off = led_off_dist(gen); + + for (int i = 0; i < 4; i++) { + if (led_off != i) { + button_colors[i] = led_color_dist(gen); + ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), COLORS_RED[button_colors[i]], COLORS_GREEN[button_colors[i]], COLORS_BLUE[button_colors[i]])); + buttons_cycling[i] = true; + } else { + button_colors[i] = -1; + buttons_cycling[i] = false; + } + } + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + const uint8_t CORRECT_COLORS[4] = {4, 0, 5, 2}; + TickType_t lastCycleTime = xTaskGetTickCount(); + bool button_turned_on = false; + + ButtonKey button; + + std::uniform_int_distribution<> led_turn_on_dist(0, 3); + while (1) { + if (get_pressed_button(&button)) { + uint8_t button_state = get_button_state(); + + for (int i = 0; i < 4; i++) { + if (((button_state >> i) & 0b1) == 0b1) { + if (button_colors[i] == -1) { + if (led_turn_on_dist(gen) == 0) { + button_turned_on = true; + led_strip_set_pixel(leds, (20 - i), COLORS_RED[CORRECT_COLORS[i]], COLORS_GREEN[CORRECT_COLORS[i]], COLORS_BLUE[CORRECT_COLORS[i]]); + led_strip_refresh(leds); + } + } else if (button_colors[i] != CORRECT_COLORS[i]) { + strike("Wrong time!"); + break; + } else { + buttons_cycling[i] = false; + } + } + } + + bool success = true; + for (int i = 0; i < sizeof(buttons_cycling); i++) { + if ((buttons_cycling[i] == true) || (button_turned_on == false && led_off != -1)) { + success = false; + break; + } + } + if (success) { + solved_puzzles++; + solved_correctly = true; + break; + } + } + if ((xTaskGetTickCount() - lastCycleTime) >= pdMS_TO_TICKS(500)) { + ESP_LOGI(TAG, "Cycling LEDs"); + for (int i = 0; i < 4; i++) { + if (buttons_cycling[i]) { + button_colors[i]++; + if (button_colors[i] > 5) { + button_colors[i] = 0; + } + ESP_ERROR_CHECK(led_strip_set_pixel(leds, (20 - i), COLORS_RED[button_colors[i]], COLORS_GREEN[button_colors[i]], COLORS_BLUE[button_colors[i]])); + } + } + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + lastCycleTime = xTaskGetTickCount(); + } + if (get_module_time() <= 0) { + bool success = true; + for (int i = 0; i < sizeof(buttons_cycling); i++) { + if ((buttons_cycling[i] == true) || (button_turned_on == false && led_off != -1)) { + strike("Ran out of time!"); + success = false; + break; + } + } + if (success) { + solved_puzzles++; + solved_correctly = true; + } + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + break; + } + case 7: { + lcd_print(&lcd, "What"); + set_module_time(40000); + start_module_timer(); + + std::uniform_int_distribution<> math_number_dist(1, 9); + + std::vector math_numbers; + std::vector math_operations; + + std::map operation_map = { + {0, '+'}, + {1, '-'}, + {2, '*'}, + {3, '/'}, + }; + + int expression_answer = -1; + std::string display_expression; + + while (expression_answer < 0) { + math_numbers = {static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen)), static_cast(math_number_dist(gen))}; + std::vector possible_math_operations = {0, 1, 2, 3}; + math_operations = unique_values(possible_math_operations, 3); + + display_expression = std::to_string(static_cast(math_numbers[0])); + for (int i = 0; i < 3; i++) { + display_expression += operation_map[math_operations[i]]; + display_expression += std::to_string(static_cast(math_numbers[i + 1])); + } + + // Solve + for (int j = 0; j < 3; j++) { + bool found = false; + for (int i = 0; i < math_operations.size(); i++) { + if (math_operations[i] == 2) { + // ESP_LOGI(TAG, "i = %i, condensing %f * %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] * math_numbers[i+1])); + math_numbers[i] = math_numbers[i] * math_numbers[i + 1]; + math_numbers.erase(math_numbers.begin() + i + 1); + math_operations.erase(math_operations.begin() + i); + found = true; + break; + } else if (math_operations[i] == 3) { + // ESP_LOGI(TAG, "i = %i, condensing %f / %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] / math_numbers[i+1])); + math_numbers[i] = math_numbers[i] / math_numbers[i + 1]; + math_numbers.erase(math_numbers.begin() + i + 1); + math_operations.erase(math_operations.begin() + i); + found = true; + break; + } + } + if (found) continue; + for (int i = 0; i < math_operations.size(); i++) { + if (math_operations[i] == 0) { + // ESP_LOGI(TAG, "i = %i, condensing %f + %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] + math_numbers[i+1])); + math_numbers[i] = math_numbers[i] + math_numbers[i + 1]; + math_numbers.erase(math_numbers.begin() + i + 1); + math_operations.erase(math_operations.begin() + i); + found = true; + break; + } else if (math_operations[i] == 1) { + // ESP_LOGI(TAG, "i = %i, condensing %f - %f to %f", i, math_numbers[i], math_numbers[i + 1], (math_numbers[i] - math_numbers[i+1])); + math_numbers[i] = math_numbers[i] - math_numbers[i + 1]; + math_numbers.erase(math_numbers.begin() + i + 1); + math_operations.erase(math_operations.begin() + i); + found = true; + break; + } + } + } + expression_answer = static_cast(std::floor(math_numbers[0])); + } + + // display expression + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, display_expression.c_str()); + + // ESP_LOGI(TAG, "Display expression: %s", display_expression.c_str()); + // ESP_LOGI(TAG, "Solved expression answer: %i", static_cast(expression_answer)); + + // set LEDs + + // blue, red, green, yellow + const int INDICATOR_RED[4] = {0, 20, 0, 10}; + const int INDICATOR_GREEN[4] = {0, 0, 10, 5}; + const int INDICATOR_BLUE[4] = {10, 0, 0, 0}; + + std::uniform_int_distribution<> add_sub_indicator_dist(1, 6); + std::uniform_int_distribution<> mult_div_indicator_dist(1, 3); + + int modifier_indicators[4] = {add_sub_indicator_dist(gen), add_sub_indicator_dist(gen), mult_div_indicator_dist(gen), mult_div_indicator_dist(gen)}; + + while ((((expression_answer + (modifier_indicators[0] * 3) - modifier_indicators[1]) * (3 ^ modifier_indicators[2])) / (2 ^ modifier_indicators[3])) < 0) { + modifier_indicators[0] = add_sub_indicator_dist(gen); + modifier_indicators[1] = add_sub_indicator_dist(gen); + modifier_indicators[2] = mult_div_indicator_dist(gen); + modifier_indicators[3] = mult_div_indicator_dist(gen); + } + + expression_answer += modifier_indicators[0] * 3; + expression_answer -= modifier_indicators[1]; + expression_answer *= 3 ^ modifier_indicators[2]; + expression_answer /= 2 ^ modifier_indicators[3]; + + std::vector led_options = all_leds; + for (int i = 0; i < 4; i++) { + set_unique_leds(led_options, modifier_indicators[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); + } + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + std::string answer_string = std::to_string(expression_answer); + std::string entered_string; + + // ESP_LOGI(TAG, "Solved full answer: %s", answer_string.c_str()); + + KeypadKey key; + + while (1) { + if (get_pressed_keypad(&key)) { + if (key == KeypadKey::star) { + // clear + entered_string = ""; + } else if (key == KeypadKey::pound) { + // submit + if (entered_string != answer_string) { + strike("Incorrect answer!"); + } else { + solved_puzzles++; + solved_correctly = true; + } + break; + } else { + entered_string += char_of_keypad_key(key); + } + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, "What"); + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, display_expression.c_str()); + lcd_set_cursor(&lcd, 1, 3); + lcd_print(&lcd, entered_string.c_str()); + } + if (get_module_time() <= 0) { + strike("Ran out of time!"); + break; + } + + + vTaskDelay(pdMS_TO_TICKS(10)); + } + + break; + } + case 8: { + lcd_print(&lcd, "Plink"); + set_module_time(15000); + start_module_timer(); + + std::uniform_int_distribution<> indicator_number_dist(0, 4); + + // ESP_LOGI(TAG, "Green: %i, Red: %i, Yellow: %i, Blue: %i", green_indicators, red_indicators, yellow_indicators, blue_indicators); + + // green, red, yellow, blue, purple + const int INDICATOR_RED[5] = {0, 20, 10, 0, 10}; + const int INDICATOR_GREEN[5] = {10, 0, 5, 0, 0}; + const int INDICATOR_BLUE[5] = {0, 0, 0, 10, 5}; + + int solved_times = 0; + bool failed = false; + while (solved_times < 3 && !failed) { + int indicator_numbers[5] = {indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen), indicator_number_dist(gen)}; + + std::vector led_options = all_leds; + for (int i = 0; i < 5; i++) { + set_unique_leds(led_options, indicator_numbers[i], INDICATOR_RED[i], INDICATOR_GREEN[i], INDICATOR_BLUE[i]); + } + + + ESP_ERROR_CHECK(led_strip_refresh(leds)); + + std::uniform_int_distribution<> answer_color_dist(0, 4); + + std::map color_name_map = { + {0, "Green"}, + {1, "Red"}, + {2, "Yellow"}, + {3, "Blue"}, + {4, "Purple"}, + }; + + int answer_color = answer_color_dist(gen); + + std::string color_string = color_name_map[answer_color]; + std::string answer_num = std::to_string(indicator_numbers[answer_color]); + + // ESP_LOGI(TAG, "color string: %s", color_string.c_str()); + + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, color_string.c_str()); + + std::string entered_string; + + KeypadKey key; + while (1) { + if (get_pressed_keypad(&key)) { + if (key == KeypadKey::star) { + // clear + entered_string = ""; + } else if (key == KeypadKey::pound) { + // submit + if (entered_string != answer_num) { + strike("Incorrect answer!"); + } else { + solved_times++; + } + break; + } else { + entered_string += char_of_keypad_key(key); + } + + lcd_clear(&lcd); + lcd_set_cursor(&lcd, 1, 1); + lcd_print(&lcd, "Plink"); + lcd_set_cursor(&lcd, 1, 2); + lcd_print(&lcd, color_string.c_str()); + lcd_set_cursor(&lcd, 1, 3); + lcd_print(&lcd, entered_string.c_str()); + } + if (get_module_time() <= 0) { + strike("Ran out of time!"); + break; + } + + + vTaskDelay(pdMS_TO_TICKS(10)); + } + + break; + + } + if (!failed) { + solved_puzzles++; + solved_correctly = true; + } + } + + + } + stop_module_timer(); + if (solved_correctly) { + play_raw(MOUNT_POINT "/correct.pcm"); + vTaskDelay(pdMS_TO_TICKS(500)); + solved_correctly = false; + } else { + vTaskDelay(pdMS_TO_TICKS(3000)); + } + clean_bomb(); + } } diff --git a/main/steps/step5.h b/main/steps/step5.h index 9fa48a7..10b1c06 100644 --- a/main/steps/step5.h +++ b/main/steps/step5.h @@ -2,14 +2,18 @@ #define STEP_5_H #include "../drivers/bottom_half.h" -#include "../drivers/wires.h" #include "../drivers/game_timer.h" +#include "../drivers/char_lcd.h" #include "../drivers/leds.h" -#include "../drivers/speaker.h" +#include "../drivers/wires.h" #include "../helper.h" -#include #include +#include +#include #include +#include +#include +#include void step5(void);