Add wires solver
This commit is contained in:
parent
be7c1bc20e
commit
8b41f98659
@ -1,5 +1,7 @@
|
|||||||
idf_component_register(SRCS "main.cpp" "drivers/TM1640/TM16xx.cpp" "drivers/TM1640/TM1640.cpp" "drivers/bottom_half.cpp"
|
idf_component_register(SRCS "main.cpp"
|
||||||
INCLUDE_DIRS "")
|
INCLUDE_DIRS ".")
|
||||||
|
|
||||||
|
add_subdirectory(drivers)
|
||||||
|
add_subdirectory(steps)
|
||||||
|
|
||||||
set(EXTRA_COMPONENT_DIRS components)
|
set(EXTRA_COMPONENT_DIRS components)
|
||||||
7
main/drivers/CMakeLists.txt
Normal file
7
main/drivers/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
set(SOURCES
|
||||||
|
"TM1640/TM16xx.cpp"
|
||||||
|
"TM1640/TM1640.cpp"
|
||||||
|
"bottom_half.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${COMPONENT_LIB} PRIVATE ${SOURCES})
|
||||||
@ -17,6 +17,16 @@ static uint8_t touch_released;
|
|||||||
/// read buffer
|
/// read buffer
|
||||||
static uint8_t read_buf[8];
|
static uint8_t read_buf[8];
|
||||||
|
|
||||||
|
void clear_all_pressed_released(void) {
|
||||||
|
keypad_pressed = 0;
|
||||||
|
button_pressed = 0;
|
||||||
|
touch_pressed = 0;
|
||||||
|
|
||||||
|
keypad_released = 0;
|
||||||
|
button_released = 0;
|
||||||
|
touch_released = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool _take_key(KeypadKey* kp, uint16_t* keypad_bitfield) {
|
static bool _take_key(KeypadKey* kp, uint16_t* keypad_bitfield) {
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
int bit_selector = (1 << i);
|
int bit_selector = (1 << i);
|
||||||
@ -76,6 +86,66 @@ char char_of_keypad_key(KeypadKey kp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _take_button(ButtonKey* button, uint16_t* button_bitfield) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int bit_selector = (1 << (i+8));
|
||||||
|
if ((*button_bitfield) & bit_selector) {
|
||||||
|
*button = (ButtonKey) i;
|
||||||
|
// clear bit
|
||||||
|
*button_bitfield &= ~bit_selector;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool _take_switch(SwitchKey* switch_, uint16_t* button_bitfield) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int bit_selector = (1 << i);
|
||||||
|
if ((*button_bitfield) & bit_selector) {
|
||||||
|
*switch_ = (SwitchKey) i;
|
||||||
|
// clear bit
|
||||||
|
*button_bitfield &= ~bit_selector;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_pressed_button(ButtonKey* button) {
|
||||||
|
return _take_button(button, &button_pressed);
|
||||||
|
}
|
||||||
|
bool get_released_button(ButtonKey* button) {
|
||||||
|
return _take_button(button, &button_released);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_button_state() {
|
||||||
|
return (uint8_t)((button_state >> 8) & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_flipped_up_switch(SwitchKey* switch_) {
|
||||||
|
return _take_switch(switch_, &button_released);
|
||||||
|
}
|
||||||
|
bool get_flipped_down_switch(SwitchKey* switch_) {
|
||||||
|
return _take_switch(switch_, &button_released);
|
||||||
|
}
|
||||||
|
bool get_flipped_switch(SwitchKey* switch_) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int bit_selector = (1 << (i+4));
|
||||||
|
if (button_pressed & bit_selector || button_released & bit_selector) {
|
||||||
|
*switch_ = (SwitchKey) i;
|
||||||
|
// clear bit
|
||||||
|
button_pressed &= ~bit_selector;
|
||||||
|
button_released &= ~bit_selector;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_switch_state(uint8_t* switch_flags) {
|
||||||
|
return (uint8_t)(button_state && 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
static void poll_bottom_task(void *arg);
|
static void poll_bottom_task(void *arg);
|
||||||
|
|
||||||
// static void IRAM_ATTR gpio_isr_handler(void* arg)
|
// static void IRAM_ATTR gpio_isr_handler(void* arg)
|
||||||
@ -144,6 +214,7 @@ static void receive_button(void) {
|
|||||||
read_buf[1] = 0;
|
read_buf[1] = 0;
|
||||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, ®, 1, read_buf, 2, (100 / portTICK_PERIOD_MS)));
|
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, ®, 1, read_buf, 2, (100 / portTICK_PERIOD_MS)));
|
||||||
uint16_t new_button_state = read_buf[0] | (read_buf[1] << 8);
|
uint16_t new_button_state = read_buf[0] | (read_buf[1] << 8);
|
||||||
|
ESP_LOGI("jjj", "New Button State: %d", new_button_state);
|
||||||
|
|
||||||
uint16_t just_pressed = new_button_state & ~button_state;
|
uint16_t just_pressed = new_button_state & ~button_state;
|
||||||
button_pressed |= just_pressed;
|
button_pressed |= just_pressed;
|
||||||
|
|||||||
@ -31,10 +31,35 @@ typedef enum {
|
|||||||
kd = 15,
|
kd = 15,
|
||||||
} KeypadKey;
|
} KeypadKey;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
b1 = 0,
|
||||||
|
b2 = 1,
|
||||||
|
b3 = 2,
|
||||||
|
b4 = 3,
|
||||||
|
} ButtonKey;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
s1 = 0,
|
||||||
|
s2 = 1,
|
||||||
|
s3 = 2,
|
||||||
|
s4 = 3,
|
||||||
|
} SwitchKey;
|
||||||
|
|
||||||
|
void clear_all_pressed_released(void);
|
||||||
|
|
||||||
bool get_pressed_keypad(KeypadKey* kp);
|
bool get_pressed_keypad(KeypadKey* kp);
|
||||||
bool get_released_keypad(KeypadKey* kp);
|
bool get_released_keypad(KeypadKey* kp);
|
||||||
char char_of_keypad_key(KeypadKey kp);
|
char char_of_keypad_key(KeypadKey kp);
|
||||||
|
|
||||||
|
bool get_pressed_button(ButtonKey* button);
|
||||||
|
bool get_released_button(ButtonKey* button);
|
||||||
|
uint8_t get_button_state();
|
||||||
|
|
||||||
|
bool get_flipped_up_switch(SwitchKey* switch_);
|
||||||
|
bool get_flipped_down_switch(SwitchKey* switch_);
|
||||||
|
bool get_flipped_switch(SwitchKey* switch_);
|
||||||
|
uint8_t get_switch_state(uint8_t* switch_flags);
|
||||||
|
|
||||||
static void poll_bottom_task(void *arg);
|
static void poll_bottom_task(void *arg);
|
||||||
|
|
||||||
void init_bottom_half();
|
void init_bottom_half();
|
||||||
|
|||||||
@ -15,6 +15,11 @@
|
|||||||
|
|
||||||
#include "steps/step0.hpp"
|
#include "steps/step0.hpp"
|
||||||
#include "steps/step1.hpp"
|
#include "steps/step1.hpp"
|
||||||
|
#include "steps/step2.hpp"
|
||||||
|
#include "steps/step3.hpp"
|
||||||
|
#include "steps/step4.hpp"
|
||||||
|
#include "steps/step5.hpp"
|
||||||
|
#include "steps/step6.hpp"
|
||||||
|
|
||||||
#define WIRES_ADDR 125
|
#define WIRES_ADDR 125
|
||||||
#define WIRES_REG_WIRES
|
#define WIRES_REG_WIRES
|
||||||
@ -38,6 +43,11 @@ extern "C" void app_main(void) {
|
|||||||
|
|
||||||
step0();
|
step0();
|
||||||
step1();
|
step1();
|
||||||
|
step2();
|
||||||
|
step3();
|
||||||
|
step4();
|
||||||
|
step5();
|
||||||
|
step6();
|
||||||
|
|
||||||
// create_demo_ui();
|
// create_demo_ui();
|
||||||
|
|
||||||
|
|||||||
5
main/steps/CMakeLists.txt
Normal file
5
main/steps/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
set(SOURCES
|
||||||
|
"wires_puzzle.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${COMPONENT_LIB} PRIVATE ${SOURCES})
|
||||||
93
main/steps/setup_wires.hpp
Normal file
93
main/steps/setup_wires.hpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#ifndef SETUP_WIRES_HPP
|
||||||
|
#define SETUP_WIRES_HPP
|
||||||
|
|
||||||
|
#include "../drivers/bottom_half.h"
|
||||||
|
#include "../drivers/char_lcd.hpp"
|
||||||
|
#include "wires_puzzle.h"
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
void setup_wires(void) {
|
||||||
|
clear_all_pressed_released();
|
||||||
|
lcd_clear(&lcd);
|
||||||
|
|
||||||
|
WiresColor wires[NUM_WIRES];
|
||||||
|
load_wires_from_sd_card(wires);
|
||||||
|
|
||||||
|
bool cut[NUM_WIRES];
|
||||||
|
solve_wires(wires, cut);
|
||||||
|
|
||||||
|
lcd_set_cursor(&lcd, 1, 1);
|
||||||
|
char wires_string[NUM_WIRES+1] = {0};
|
||||||
|
wires_to_string(wires, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
|
||||||
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
|
cut_to_string(cut, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
lcd_set_cursor(&lcd, 1, 1);
|
||||||
|
|
||||||
|
int editing_idx = 0;
|
||||||
|
|
||||||
|
KeypadKey key;
|
||||||
|
ButtonKey button;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
while (get_pressed_keypad(&key)) {
|
||||||
|
if (key == KeypadKey::k1) {
|
||||||
|
generate_new_wires(wires);
|
||||||
|
save_wires_to_sd_card(wires);
|
||||||
|
bool cut[NUM_WIRES];
|
||||||
|
solve_wires(wires, cut);
|
||||||
|
|
||||||
|
lcd_set_cursor(&lcd, 1, 1);
|
||||||
|
char wires_string[NUM_WIRES+1] = {0};
|
||||||
|
wires_to_string(wires, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
|
||||||
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
|
cut_to_string(cut, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
lcd_set_cursor(&lcd, editing_idx+1, 1);
|
||||||
|
} else if (key == KeypadKey::pound) {
|
||||||
|
lcd_no_cursor(&lcd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (get_pressed_button(&button)) {
|
||||||
|
ESP_LOGI("setup_wires", "Button press: %d", (int)button);
|
||||||
|
if (button == ButtonKey::b1) {
|
||||||
|
// left
|
||||||
|
editing_idx = editing_idx - 1;
|
||||||
|
if (editing_idx < 0) editing_idx = 0;
|
||||||
|
} else if (button == ButtonKey::b4) {
|
||||||
|
// right
|
||||||
|
editing_idx = editing_idx + 1;
|
||||||
|
if (editing_idx >= NUM_WIRES) editing_idx = NUM_WIRES-1;
|
||||||
|
} else if (button == ButtonKey::b2) {
|
||||||
|
// down
|
||||||
|
wires[editing_idx] = (WiresColor)(((int)(wires[editing_idx]) + (NUM_COLORS-1)) % NUM_COLORS);
|
||||||
|
} else if (button == ButtonKey::b3) {
|
||||||
|
// up
|
||||||
|
wires[editing_idx] = (WiresColor)(((int)(wires[editing_idx]) + 1) % NUM_COLORS);
|
||||||
|
}
|
||||||
|
save_wires_to_sd_card(wires);
|
||||||
|
lcd_set_cursor(&lcd, 1, 1);
|
||||||
|
char wires_string[NUM_WIRES+1] = {0};
|
||||||
|
wires_to_string(wires, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
|
||||||
|
bool cut[NUM_WIRES];
|
||||||
|
solve_wires(wires, cut);
|
||||||
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
|
cut_to_string(cut, wires_string);
|
||||||
|
lcd_print(&lcd, wires_string);
|
||||||
|
|
||||||
|
lcd_set_cursor(&lcd, editing_idx+1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SETUP_WIRES_HPP */
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include "../drivers/bottom_half.h"
|
#include "../drivers/bottom_half.h"
|
||||||
#include "../drivers/char_lcd.hpp"
|
#include "../drivers/char_lcd.hpp"
|
||||||
#include "../drivers/wires.hpp"
|
#include "../drivers/wires.hpp"
|
||||||
|
#include "setup_wires.hpp"
|
||||||
|
|
||||||
static const char *STEP0_TAG = "step0";
|
static const char *STEP0_TAG = "step0";
|
||||||
|
|
||||||
@ -26,16 +27,24 @@ void step0(void) {
|
|||||||
current_idx = 1;
|
current_idx = 1;
|
||||||
} else if (key == KeypadKey::pound) {
|
} else if (key == KeypadKey::pound) {
|
||||||
// submit
|
// submit
|
||||||
if (strcmp(current, "*9819") == 0) {
|
if (current[0] == '\0') {
|
||||||
|
// do nothing
|
||||||
|
} else if (strcmp(current, "*9819") == 0) {
|
||||||
lcd_set_cursor(&lcd, 1, 2);
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
lcd_print(&lcd, "Diffusal Initated");
|
lcd_print(&lcd, "Diffusal Initated");
|
||||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
lcd_clear(&lcd);
|
lcd_clear(&lcd);
|
||||||
return;
|
return;
|
||||||
|
} else if (strcmp(current, "*59861") == 0) {
|
||||||
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
|
lcd_print(&lcd, "Set Up Wires");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
setup_wires();
|
||||||
} else {
|
} else {
|
||||||
lcd_set_cursor(&lcd, 1, 2);
|
lcd_set_cursor(&lcd, 1, 2);
|
||||||
lcd_print(&lcd, "Invalid Star Code");
|
lcd_print(&lcd, "Invalid Star Code");
|
||||||
strike("Invalid Star Code");
|
strike("Invalid Star Code");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear
|
// clear
|
||||||
@ -43,8 +52,6 @@ void step0(void) {
|
|||||||
current[i] = 0;
|
current[i] = 0;
|
||||||
}
|
}
|
||||||
current_idx = 0;
|
current_idx = 0;
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
||||||
} else {
|
} else {
|
||||||
// out of room. skip
|
// out of room. skip
|
||||||
if (current_idx >= STRING_MAX_LEN) break;
|
if (current_idx >= STRING_MAX_LEN) break;
|
||||||
@ -60,10 +67,6 @@ void step0(void) {
|
|||||||
lcd_set_cursor(&lcd, 1, 1);
|
lcd_set_cursor(&lcd, 1, 1);
|
||||||
lcd_print(&lcd, current);
|
lcd_print(&lcd, current);
|
||||||
}
|
}
|
||||||
while (get_released_keypad(&key)) {
|
|
||||||
char c = char_of_keypad_key(key);
|
|
||||||
// ESP_LOGI(STEP0_TAG, "Released: %c", c);
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
}
|
}
|
||||||
|
|||||||
347
main/steps/wires_puzzle.cpp
Normal file
347
main/steps/wires_puzzle.cpp
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
#include "wires_puzzle.h"
|
||||||
|
|
||||||
|
const static char* WIRES_FILE_PATH = "/sdcard/wires.txt";
|
||||||
|
const static char* TAG = "wires_puzzle";
|
||||||
|
|
||||||
|
static int color_name_len[NUM_COLORS] = {
|
||||||
|
3, // red
|
||||||
|
6, // yellow
|
||||||
|
5, // green
|
||||||
|
4, // blue
|
||||||
|
5, // black
|
||||||
|
5, // white
|
||||||
|
};
|
||||||
|
|
||||||
|
static int max(int n0, int n1, int n2, int n3, int n4, int n5);
|
||||||
|
|
||||||
|
void wires_to_string(WiresColor* wires, char* out_wires_string) {
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
switch (wires[i]) {
|
||||||
|
case WiresColor::red:
|
||||||
|
out_wires_string[i] = 'r';
|
||||||
|
break;
|
||||||
|
case WiresColor::yellow:
|
||||||
|
out_wires_string[i] = 'y';
|
||||||
|
break;
|
||||||
|
case WiresColor::green:
|
||||||
|
out_wires_string[i] = 'g';
|
||||||
|
break;
|
||||||
|
case WiresColor::blue:
|
||||||
|
out_wires_string[i] = 'u';
|
||||||
|
break;
|
||||||
|
case WiresColor::black:
|
||||||
|
out_wires_string[i] = 'b';
|
||||||
|
break;
|
||||||
|
case WiresColor::white:
|
||||||
|
out_wires_string[i] = 'w';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void cut_to_string(bool* cut, char* out_cut_string) {
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
if (cut[i]) {
|
||||||
|
out_cut_string[i] = 'c';
|
||||||
|
} else {
|
||||||
|
out_cut_string[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_to_wires(char* wires_string, WiresColor* out_wires) {
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
switch (wires_string[i]) {
|
||||||
|
case 'r':
|
||||||
|
out_wires[i] = WiresColor::red;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
out_wires[i] = WiresColor::yellow;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
out_wires[i] = WiresColor::green;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
out_wires[i] = WiresColor::blue;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
out_wires[i] = WiresColor::black;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
out_wires[i] = WiresColor::white;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_wires_to_sd_card(WiresColor* wires) {
|
||||||
|
FILE* f = fopen(WIRES_FILE_PATH, "w");
|
||||||
|
if (f == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Failed to open wires file to write");
|
||||||
|
}
|
||||||
|
char wires_string[NUM_WIRES+1] = {0};
|
||||||
|
wires_to_string(wires, wires_string);
|
||||||
|
fprintf(f, wires_string);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_wires_from_sd_card(WiresColor* out_wires) {
|
||||||
|
FILE* f = fopen(WIRES_FILE_PATH, "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
ESP_LOGW(TAG, "Failed to read wires file. Generating new wires");
|
||||||
|
generate_new_wires(out_wires);
|
||||||
|
save_wires_to_sd_card(out_wires);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char wires_string[NUM_WIRES+1] = {0};
|
||||||
|
fgets(wires_string, sizeof(wires_string), f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
string_to_wires(wires_string, out_wires);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Fills the array with 6 random WiresColors.
|
||||||
|
/// @param wires and array of len >= 6 to be populated with random colors
|
||||||
|
void generate_new_wires(WiresColor* wires) {
|
||||||
|
for (int w = 0; w < NUM_WIRES; w++) {
|
||||||
|
// roughly evenly distributed
|
||||||
|
uint32_t rand = esp_random() % NUM_COLORS;
|
||||||
|
wires[w] = (WiresColor)(rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cuts[NUM_WIRES] = {0};
|
||||||
|
solve_wires(wires, cuts);
|
||||||
|
int num_cuts = 0;
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
if (cuts[i]) num_cuts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// regenerate if there are less than 3 cuts.
|
||||||
|
if (num_cuts < 3) {
|
||||||
|
return generate_new_wires(wires);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void solve_wires(WiresColor* wires, bool* out_cut) {
|
||||||
|
// by default, don't cut any wires
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
out_cut[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all positions of all wire colors
|
||||||
|
int red_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int red_pos_len = 0;
|
||||||
|
int yellow_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int yellow_pos_len = 0;
|
||||||
|
int green_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int green_pos_len = 0;
|
||||||
|
int blue_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int blue_pos_len = 0;
|
||||||
|
int black_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int black_pos_len = 0;
|
||||||
|
int white_pos[NUM_WIRES + 1] = {0};
|
||||||
|
int white_pos_len = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
if (wires[i] == WiresColor::red) {
|
||||||
|
red_pos[red_pos_len++] = i;
|
||||||
|
} else if (wires[i] == WiresColor::yellow) {
|
||||||
|
yellow_pos[yellow_pos_len++] = i;
|
||||||
|
} else if (wires[i] == WiresColor::green) {
|
||||||
|
green_pos[green_pos_len++] = i;
|
||||||
|
} else if (wires[i] == WiresColor::blue) {
|
||||||
|
blue_pos[blue_pos_len++] = i;
|
||||||
|
} else if (wires[i] == WiresColor::black) {
|
||||||
|
black_pos[black_pos_len++] = i;
|
||||||
|
} else if (wires[i] == WiresColor::white) {
|
||||||
|
white_pos[white_pos_len++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int* list_pos[NUM_COLORS] = {
|
||||||
|
red_pos,
|
||||||
|
yellow_pos,
|
||||||
|
green_pos,
|
||||||
|
blue_pos,
|
||||||
|
black_pos,
|
||||||
|
white_pos
|
||||||
|
};
|
||||||
|
int list_pos_len[NUM_COLORS] = {
|
||||||
|
red_pos_len,
|
||||||
|
yellow_pos_len,
|
||||||
|
green_pos_len,
|
||||||
|
blue_pos_len,
|
||||||
|
black_pos_len,
|
||||||
|
white_pos_len
|
||||||
|
};
|
||||||
|
|
||||||
|
// CUT CHECKS
|
||||||
|
|
||||||
|
// cut the second wire of all most common colors
|
||||||
|
int max_len = max(red_pos_len, yellow_pos_len, green_pos_len, blue_pos_len, black_pos_len, white_pos_len);
|
||||||
|
if (max_len >= 2) {
|
||||||
|
for (int i = 0; i < NUM_COLORS; i++) {
|
||||||
|
if (list_pos_len[i] == max_len) {
|
||||||
|
int idx = list_pos[i][1];
|
||||||
|
out_cut[idx] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut the first wire if it is green or white
|
||||||
|
if (wires[0] == WiresColor::green || wires[0] == WiresColor::white) out_cut[0] = true;
|
||||||
|
|
||||||
|
// cut blue wires in even positions (odd indexes)
|
||||||
|
for (int i = 1; i < NUM_WIRES; i += 2) {
|
||||||
|
if (wires[i] == WiresColor::blue) out_cut[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut black and yellow wires next to black and yellow wires
|
||||||
|
for (int i = 0; i < NUM_WIRES-1; i++) {
|
||||||
|
if (
|
||||||
|
(wires[i] == WiresColor::yellow || wires[i] == WiresColor::black) &&
|
||||||
|
(wires[i+1] == WiresColor::yellow || wires[i+1] == WiresColor::black)
|
||||||
|
) {
|
||||||
|
out_cut[i] = true;
|
||||||
|
out_cut[1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut the last green wire next to a yellow or white wire
|
||||||
|
for (int green_idx = green_pos_len-1; green_idx >= 0; green_idx--) {
|
||||||
|
int pos = green_pos[green_idx];
|
||||||
|
if (
|
||||||
|
wires[pos-1] == WiresColor::yellow ||
|
||||||
|
wires[pos-1] == WiresColor::white ||
|
||||||
|
wires[pos+1] == WiresColor::yellow ||
|
||||||
|
wires[pos+1] == WiresColor::white
|
||||||
|
) {
|
||||||
|
out_cut[pos] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut all white wires if there is a red wire in the 5th position
|
||||||
|
if (wires[4] == WiresColor::red) {
|
||||||
|
for (int white_idx = 0; white_idx < white_pos_len; white_idx++) {
|
||||||
|
out_cut[white_pos[white_idx]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut the first black wire if there are more white wires than green wires
|
||||||
|
if (white_pos_len > green_pos_len && black_pos_len > 0) {
|
||||||
|
out_cut[black_pos[0]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut all wires in an alternating pattern of 2 colors at least 4 wires long
|
||||||
|
for (int i = 0; i < NUM_WIRES-3; i++) {
|
||||||
|
if (
|
||||||
|
wires[i] == wires[i+2] &&
|
||||||
|
wires[i+1] == wires[i+3] &&
|
||||||
|
wires[i] == wires[i+1]
|
||||||
|
) {
|
||||||
|
out_cut[i] = true;
|
||||||
|
out_cut[i+1] = true;
|
||||||
|
out_cut[i+2] = true;
|
||||||
|
out_cut[i+3] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut any wires if their position matches the number of letters in the color's name
|
||||||
|
for (int i = 0; i < NUM_WIRES; i++) {
|
||||||
|
if (color_name_len[i] == i+1) {
|
||||||
|
out_cut[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut all red wires if there are no more than 2 wires of the same color
|
||||||
|
if (max_len <= 2) {
|
||||||
|
for (int i = 0; i < red_pos_len; i++) {
|
||||||
|
out_cut[red_pos[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut the last wire if it is the same color as the first wire
|
||||||
|
if (wires[0] == wires[NUM_WIRES-1]) {
|
||||||
|
out_cut[NUM_WIRES-1] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut any wire adjacent to both a yellow and blue wire
|
||||||
|
for (int i = 0; i < NUM_WIRES-2; i++) {
|
||||||
|
if (
|
||||||
|
(wires[i] == WiresColor::yellow && wires[i+2] == WiresColor::blue) ||
|
||||||
|
(wires[i] == WiresColor::blue && wires[i+2] == WiresColor::white)
|
||||||
|
) {
|
||||||
|
out_cut[i+1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NEVER CUT
|
||||||
|
|
||||||
|
// never cut blue wires next to red or green wires
|
||||||
|
for (int i = 0; i < blue_pos_len; i++) {
|
||||||
|
int pos = blue_pos[i];
|
||||||
|
if (
|
||||||
|
wires[pos-1] == WiresColor::red ||
|
||||||
|
wires[pos-1] == WiresColor::green ||
|
||||||
|
wires[pos+1] == WiresColor::red ||
|
||||||
|
wires[pos+1] == WiresColor::green
|
||||||
|
) {
|
||||||
|
out_cut[pos] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut white wires if there is at least one red, black and green wire
|
||||||
|
if (red_pos_len > 0 && green_pos_len > 0 && black_pos_len > 0) {
|
||||||
|
for (int i = 0; i < white_pos_len; i++) {
|
||||||
|
out_cut[white_pos[i]] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut red or black wires in the 4th or 7th positions
|
||||||
|
if (wires[3] == WiresColor::red || wires[3] == WiresColor::black) {
|
||||||
|
out_cut[3] = false;
|
||||||
|
}
|
||||||
|
if (wires[6] == WiresColor::red || wires[6] == WiresColor::black) {
|
||||||
|
out_cut[6] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut wires that have the same color on both sides of it
|
||||||
|
for (int i = 0; i < NUM_WIRES-2; i++) {
|
||||||
|
if (wires[i] == wires[i+2]) {
|
||||||
|
out_cut[i+1] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut a wire in the 1st, 2nd, or 3rd position if it is the same color as the wire in the 4th position.
|
||||||
|
if (wires[0] == wires[3]) {
|
||||||
|
out_cut[0] = false;
|
||||||
|
}
|
||||||
|
if (wires[1] == wires[3]) {
|
||||||
|
out_cut[1] = false;
|
||||||
|
}
|
||||||
|
if (wires[2] == wires[3]) {
|
||||||
|
out_cut[2] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut a blue or green wire in the 8th postion
|
||||||
|
if (wires[7] == WiresColor::blue || wires[7] == WiresColor::green) {
|
||||||
|
out_cut[7] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// never cut a wire in the 5th position if there are no yellow wires
|
||||||
|
if (yellow_pos_len == 0) {
|
||||||
|
out_cut[4] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max(int n0, int n1, int n2, int n3, int n4, int n5) {
|
||||||
|
int max = n0;
|
||||||
|
|
||||||
|
if (n1 > max) max = n1;
|
||||||
|
if (n2 > max) max = n2;
|
||||||
|
if (n3 > max) max = n3;
|
||||||
|
if (n4 > max) max = n4;
|
||||||
|
if (n5 > max) max = n5;
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
40
main/steps/wires_puzzle.h
Normal file
40
main/steps/wires_puzzle.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef WIRES_PUZZLE_H
|
||||||
|
#define WIRES_PUZZLE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <esp_random.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_vfs_fat.h"
|
||||||
|
|
||||||
|
#define NUM_COLORS 6
|
||||||
|
#define NUM_WIRES 8
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
red = 0,
|
||||||
|
yellow = 1,
|
||||||
|
green = 2,
|
||||||
|
blue = 3,
|
||||||
|
black = 4,
|
||||||
|
white = 5,
|
||||||
|
} WiresColor;
|
||||||
|
|
||||||
|
void solve_wires(WiresColor* wires, bool* out_cut);
|
||||||
|
void generate_new_wires(WiresColor* wires);
|
||||||
|
|
||||||
|
void cut_to_string(bool* cut, char* out_cut_string);
|
||||||
|
void wires_to_string(WiresColor* wires, char* out_wires_string);
|
||||||
|
void string_to_wires(char* wires_string, WiresColor* out_wires);
|
||||||
|
|
||||||
|
void save_wires_to_sd_card(WiresColor* wires);
|
||||||
|
void load_wires_from_sd_card(WiresColor* out_wires);
|
||||||
|
|
||||||
|
/// @brief Fills the array with 6 random WiresColors.
|
||||||
|
/// @param wires the array of len >= 6 to be populated with random colors
|
||||||
|
void generate_new_wires(WiresColor* wires);
|
||||||
|
|
||||||
|
/// @brief Solves the wires puzzle, setting `out_cut` according to which wires are cut.
|
||||||
|
/// @param wires the array of len >= 6 as input to the solver
|
||||||
|
/// @param out_cut the output array of len >= 6 for which wires to cut
|
||||||
|
void solve_wires(WiresColor* wires, bool* out_cut);
|
||||||
|
|
||||||
|
#endif /* WIRES_PUZZLE_H */
|
||||||
Loading…
Reference in New Issue
Block a user