#ifndef MAZE32_GAME_H #define MAZE32_GAME_H #include "maze32_maze.h" #include #include #ifdef __cplusplus extern "C" { #endif #define MAZE32_GAME_PLAYER_COUNT 2U #define MAZE32_GAME_BREAKTHROUGH_HITS 5U #define MAZE32_GAME_BREAKTHROUGH_TIMEOUT_MS 3000U #define MAZE32_GAME_COMMAND_CAPACITY 16U #define MAZE32_GAME_KEY_COUNT 2U #define MAZE32_GAME_NO_KEY UINT8_MAX #define MAZE32_GAME_VISION_MOVES 10U #define MAZE32_GAME_DRAW_WINDOW_MS 200U #define MAZE32_GAME_RECONNECT_TIMEOUT_MS 60000U #define MAZE32_GAME_MAX_ARTIFACTS (2U * MAZE32_MAZE_MAX_ARTIFACT_PAIRS) #define MAZE32_GAME_MAX_OBJECTS \ (6U + 2U * MAZE32_MAZE_MAX_LANDMARK_PAIRS + 2U * MAZE32_MAZE_MAX_ARTIFACT_PAIRS) #define MAZE32_GAME_VIEW_CELLS_PER_CHUNK 12U #define MAZE32_GAME_OBSERVER_FIRST_CHUNK_CELLS 5U #define MAZE32_GAME_VIEW_OBJECTS_PER_CHUNK 6U #define MAZE32_GAME_VIEW_CHUNK_BYTES 512U #define MAZE32_GAME_MAX_TRAIL_EDGES (2U * MAZE32_MAZE_MAX_CELLS) #define MAZE32_GAME_TRAIL_BYTES ((MAZE32_GAME_MAX_TRAIL_EDGES + 3U) / 4U) #define MAZE32_GAME_RAM_BUDGET_BYTES (40U * 1024U) #define MAZE32_GAME_RUNTIME_BUDGET_MS 50U typedef enum { MAZE32_GAME_PHASE_COUNTDOWN = 0, MAZE32_GAME_PHASE_ACTIVE, MAZE32_GAME_PHASE_FINISH_PENDING, MAZE32_GAME_PHASE_PAUSED, MAZE32_GAME_PHASE_FINISHED, } maze32_game_phase_t; typedef enum { MAZE32_GAME_ROLE_PLAYER_ONE = 0, MAZE32_GAME_ROLE_PLAYER_TWO, MAZE32_GAME_ROLE_OBSERVER, } maze32_game_role_t; typedef enum { MAZE32_GAME_DIRECTION_NORTH = 0, MAZE32_GAME_DIRECTION_EAST, MAZE32_GAME_DIRECTION_SOUTH, MAZE32_GAME_DIRECTION_WEST, } maze32_game_direction_t; typedef enum { MAZE32_GAME_COMMAND_MOVE = 0, MAZE32_GAME_COMMAND_DROP_KEY, } maze32_game_command_type_t; typedef enum { MAZE32_GAME_FINAL_NONE = 0, MAZE32_GAME_FINAL_PLAYER_ONE, MAZE32_GAME_FINAL_PLAYER_TWO, MAZE32_GAME_FINAL_DRAW, } maze32_game_final_result_t; typedef enum { MAZE32_GAME_COMPASS_NONE = 0, MAZE32_GAME_COMPASS_NORTH, MAZE32_GAME_COMPASS_NORTH_EAST, MAZE32_GAME_COMPASS_EAST, MAZE32_GAME_COMPASS_SOUTH_EAST, MAZE32_GAME_COMPASS_SOUTH, MAZE32_GAME_COMPASS_SOUTH_WEST, MAZE32_GAME_COMPASS_WEST, MAZE32_GAME_COMPASS_NORTH_WEST, } maze32_game_compass_direction_t; typedef enum { MAZE32_GAME_RESULT_ACCEPTED = 0, MAZE32_GAME_RESULT_INVALID_ARGUMENT, MAZE32_GAME_RESULT_QUEUE_FULL, MAZE32_GAME_RESULT_QUEUE_EMPTY, MAZE32_GAME_RESULT_READ_ONLY, MAZE32_GAME_RESULT_PREMATURE, MAZE32_GAME_RESULT_RATE_LIMITED, MAZE32_GAME_RESULT_BLOCKED, MAZE32_GAME_RESULT_BUFFER_TOO_SMALL, MAZE32_GAME_RESULT_NO_KEY, MAZE32_GAME_RESULT_PLAYER_EXITED, MAZE32_GAME_RESULT_MATCH_FINISHED, } maze32_game_result_t; typedef struct { uint32_t movement_cooldown_ms; } maze32_game_config_t; typedef struct { maze32_cell_t position; uint64_t last_move_ms; uint32_t accepted_moves; uint8_t carried_key; uint8_t vision_moves_remaining; maze32_game_compass_direction_t compass_hint; uint8_t has_moved; uint8_t exited; uint8_t connected; uint64_t reconnect_deadline_ms; maze32_cell_t perseverance_cell; maze32_game_direction_t perseverance_direction; uint64_t perseverance_last_impact_ms; uint8_t perseverance_hits; } maze32_game_player_t; typedef enum { MAZE32_GAME_KEY_GROUND = 0, MAZE32_GAME_KEY_CARRIED, } maze32_game_key_location_t; typedef struct { maze32_game_key_location_t location; maze32_cell_t ground_position; uint8_t carrier; } maze32_game_key_t; typedef struct { uint8_t open; } maze32_game_exit_t; typedef struct { uint32_t command_sequence; maze32_game_command_type_t type; maze32_game_role_t role; maze32_game_direction_t direction; uint64_t submitted_ms; } maze32_game_command_t; typedef struct { maze32_game_result_t result; uint32_t command_sequence; uint32_t state_sequence; uint32_t meeting_sequence; uint8_t meeting; uint8_t moved; uint8_t dropped_key; uint8_t picked_key; uint8_t returned_keys; uint8_t activated_artifact; uint8_t opened_exit; uint8_t outward_exit; uint8_t breakthrough_hits; uint8_t breakthrough_opened; uint8_t finished; uint8_t key; uint8_t artifact; maze32_game_compass_direction_t compass_hint; maze32_game_final_result_t final_result; } maze32_game_command_result_t; typedef struct { const maze32_maze_t* maze; maze32_game_config_t config; maze32_game_phase_t phase; maze32_game_player_t players[MAZE32_GAME_PLAYER_COUNT]; maze32_game_key_t keys[MAZE32_GAME_KEY_COUNT]; maze32_game_exit_t exits[MAZE32_GAME_PLAYER_COUNT]; uint8_t consumed_artifacts[MAZE32_GAME_MAX_ARTIFACTS]; uint8_t opened_passages[MAZE32_MAZE_MAX_CELLS]; uint8_t trail_owners[MAZE32_GAME_TRAIL_BYTES]; maze32_game_command_t commands[MAZE32_GAME_COMMAND_CAPACITY]; uint8_t command_head; uint8_t command_count; uint32_t next_command_sequence; uint32_t state_sequence; uint32_t meeting_sequence; maze32_game_final_result_t final_result; uint8_t first_exited_player; uint8_t has_exit_time[MAZE32_GAME_PLAYER_COUNT]; uint64_t exit_times_ms[MAZE32_GAME_PLAYER_COUNT]; maze32_game_phase_t phase_before_pause; uint64_t paused_started_ms; } maze32_game_t; typedef enum { MAZE32_VIEW_OBJECT_KEY = 0, MAZE32_VIEW_OBJECT_EXIT, MAZE32_VIEW_OBJECT_COMPASS, MAZE32_VIEW_OBJECT_LANDMARK, MAZE32_VIEW_OBJECT_VISION_ARTIFACT, } maze32_view_object_kind_t; typedef struct { uint16_t cell_index; uint8_t passages; uint8_t opened_passages; uint8_t trail_east; uint8_t trail_south; } maze32_view_cell_t; typedef struct { uint16_t cell_index; maze32_view_object_kind_t kind; uint8_t owner; uint8_t variant; } maze32_view_object_t; typedef struct { maze32_game_role_t role; maze32_game_phase_t phase; uint32_t state_sequence; uint32_t meeting_sequence; maze32_game_final_result_t final_result; uint16_t width; uint16_t height; uint16_t self_cell_index; uint16_t opponent_cell_index; uint16_t observer_player_cell_indices[MAZE32_GAME_PLAYER_COUNT]; uint16_t cell_count; uint8_t self_carried_key; uint8_t self_vision_moves_remaining; maze32_game_compass_direction_t self_compass_hint; uint8_t self_exit_open; uint8_t self_exited; uint8_t opponent_carried_key; uint8_t observer_carried_keys[MAZE32_GAME_PLAYER_COUNT]; uint8_t observer_vision_moves_remaining[MAZE32_GAME_PLAYER_COUNT]; maze32_game_compass_direction_t observer_compass_hints[MAZE32_GAME_PLAYER_COUNT]; uint8_t observer_exited[MAZE32_GAME_PLAYER_COUNT]; uint8_t observer_connected[MAZE32_GAME_PLAYER_COUNT]; uint8_t observer_exit_open[MAZE32_GAME_PLAYER_COUNT]; uint8_t observer_has_exit_time[MAZE32_GAME_PLAYER_COUNT]; uint64_t observer_exit_times_ms[MAZE32_GAME_PLAYER_COUNT]; uint8_t object_count; uint8_t opponent_visible; maze32_view_cell_t cells[MAZE32_MAZE_MAX_CELLS]; maze32_view_object_t objects[MAZE32_GAME_MAX_OBJECTS]; } maze32_view_t; maze32_game_config_t maze32_game_default_config(void); maze32_game_result_t maze32_game_init(maze32_game_t* game, const maze32_maze_t* maze, const maze32_game_config_t* config); void maze32_game_set_phase(maze32_game_t* game, maze32_game_phase_t phase); maze32_game_result_t maze32_game_enqueue_move(maze32_game_t* game, maze32_game_role_t role, maze32_game_direction_t direction, uint64_t submitted_ms, uint32_t* command_sequence); maze32_game_result_t maze32_game_enqueue_drop_key(maze32_game_t* game, maze32_game_role_t role, uint64_t submitted_ms, uint32_t* command_sequence); maze32_game_command_result_t maze32_game_process_next(maze32_game_t* game); int maze32_game_advance_time(maze32_game_t* game, uint64_t now_ms); maze32_game_result_t maze32_game_set_player_connected(maze32_game_t* game, uint8_t player_index, int connected, uint64_t now_ms); uint8_t maze32_game_player_view_radius(const maze32_game_t* game, uint8_t player_index); maze32_game_result_t maze32_game_project_view(const maze32_game_t* game, maze32_game_role_t role, maze32_view_t* view); size_t maze32_game_view_chunk_count(const maze32_view_t* view); maze32_game_result_t maze32_game_serialize_view_chunk(const maze32_view_t* view, size_t chunk_index, char* output, size_t output_size, size_t* written); const char* maze32_game_result_name(maze32_game_result_t result); #ifdef __cplusplus } #endif #endif