feat(maze): add deterministic symmetric maze generation

This commit is contained in:
2026-09-04 02:43:16 +03:00
parent 996bda9567
commit 5d780def9d
11 changed files with 1263 additions and 7 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
idf_component_register(
SRCS "main.c"
REQUIRES esp_event esp_netif maze32_config maze32_network maze32_platform maze32_web
REQUIRES esp_event esp_netif esp_timer heap maze32_config maze32_maze maze32_network maze32_platform maze32_web
)
+58
View File
@@ -1,9 +1,12 @@
#include "esp_app_desc.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_heap_caps.h"
#include "esp_littlefs.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_timer.h"
#include <inttypes.h>
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
#include "esp_system.h"
#include <string.h>
@@ -12,6 +15,7 @@
#include "freertos/task.h"
#include "maze32_config_store.h"
#include "maze32_health.h"
#include "maze32_maze.h"
#include "maze32_network.h"
#include "maze32_web.h"
@@ -21,6 +25,53 @@ static httpd_handle_t web_server;
static maze32_network_t network;
static maze32_gateway_t gateway;
#ifdef MAZE32_MILESTONE_005_DEVICE_TEST
static maze32_maze_t device_test_maze;
static maze32_maze_workspace_t device_test_workspace;
static esp_err_t run_maze_device_test(void) {
maze32_maze_config_t config = maze32_maze_default_config();
maze32_maze_report_t report;
size_t free_before = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int64_t started_us = esp_timer_get_time();
maze32_maze_result_t result = maze32_maze_generate(&device_test_maze, &device_test_workspace,
&config, UINT32_C(0x5a320005), &report);
uint64_t elapsed_us = (uint64_t)(esp_timer_get_time() - started_us);
size_t free_after = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t fixed_bytes = sizeof(device_test_maze) + sizeof(device_test_workspace);
ESP_LOGI(TAG, "M005 maze: result=%s, seed=%" PRIu32 ", attempts=%u, hash=%016" PRIx64,
maze32_maze_result_name(result), device_test_maze.requested_seed, report.attempts,
maze32_maze_hash(&device_test_maze));
ESP_LOGI(TAG,
"M005 topology: cells=%u, reachable=%u, edges=%u, cycles=%u, crossings=%u, "
"dead_ends=%u, branches=%u",
(unsigned int)(config.width * config.height), report.metrics.reachable_cells,
report.metrics.passage_edges, report.metrics.cycle_count,
report.metrics.cross_half_connections, report.metrics.dead_end_count,
report.metrics.branching_cells);
ESP_LOGI(TAG,
"M005 fairness: start_key=%u/%u, key_exit=%u/%u, start_exit=%u/%u, "
"compass=%u/%u, landmarks=%" PRIu32 "/%" PRIu32 ", artifacts=%" PRIu32 "/%" PRIu32,
report.metrics.start_to_key[0], report.metrics.start_to_key[1],
report.metrics.key_to_exit[0], report.metrics.key_to_exit[1],
report.metrics.start_to_exit[0], report.metrics.start_to_exit[1],
report.metrics.start_to_compass[0], report.metrics.start_to_compass[1],
report.metrics.landmark_distance_total[0], report.metrics.landmark_distance_total[1],
report.metrics.artifact_distance_total[0], report.metrics.artifact_distance_total[1]);
ESP_LOGI(TAG, "M005 budget: fixed=%u/%u bytes, runtime=%" PRIu64 "/%u ms, heap_delta=%d",
(unsigned int)fixed_bytes, (unsigned int)MAZE32_MAZE_RAM_BUDGET_BYTES,
elapsed_us / 1000U, (unsigned int)MAZE32_MAZE_RUNTIME_BUDGET_MS,
(int)(free_before - free_after));
if (result != MAZE32_MAZE_OK || fixed_bytes > MAZE32_MAZE_RAM_BUDGET_BYTES ||
elapsed_us > (uint64_t)MAZE32_MAZE_RUNTIME_BUDGET_MS * 1000U || free_before != free_after) {
ESP_LOGE(TAG, "M005 physical maze test failed");
return ESP_FAIL;
}
ESP_LOGI(TAG, "M005 physical maze test: PASS");
return ESP_OK;
}
#endif
#ifdef MAZE32_MILESTONE_003_DEVICE_TEST
static int device_test_has_persisted_credentials;
@@ -101,6 +152,13 @@ void app_main(void) {
const esp_app_desc_t* application = esp_app_get_description();
maze32_health_init(&health, application->version);
#ifdef MAZE32_MILESTONE_005_DEVICE_TEST
if (run_maze_device_test() != ESP_OK) {
maze32_health_set(&health, MAZE32_HEALTH_ERROR, (int)ESP_FAIL);
return;
}
#endif
vTaskDelay(pdMS_TO_TICKS(1500));
ESP_LOGI(TAG, "maze32 firmware version %s starting", application->version);