#include #include #include #include #include "../../lib/aoc.h" #define MAX_LOOP_LENGTH 8000 typedef enum Direction { RIGHT, UP, LEFT, DOWN } Direction; typedef struct Position { int x; int y; } Position; typedef struct Game { char *map; int width; int height; Position guard; Direction guard_direction; Position guard_start; Direction guard_start_direction; int positions[10000]; int position_count; } Game; Position position_from_index(Game *game, int index) { Position p = { index % game->width, index / game->width }; return p; } int index_from_position(Game *game, Position p) { return p.x + (game->width * p.y); } bool position_inbounds(Game *game, Position p) { return p.x >= 0 && p.y >= 0 && p.x < game->width && p.y < game->height; } bool guard_inbounds(Game *game) { return position_inbounds(game, game -> guard); } bool position_has_obstacle(Game *game, Position p) { return game->map[index_from_position(game, p)] == '#'; } void turn_guard(Game *game) { Direction new_direction; switch (game->guard_direction) { case RIGHT: new_direction = DOWN; break; case UP: new_direction = RIGHT; break; case LEFT: new_direction = UP; break; case DOWN: new_direction = LEFT; break; } game->guard_direction = new_direction; } void move_guard(Game *game, bool deface) { Position target; target.x = game->guard.x; target.y = game->guard.y; switch (game->guard_direction) { case RIGHT: target.x++; break; case UP: target.y--; break; case LEFT: target.x--; break; case DOWN: target.y++; break; } if (position_has_obstacle(game, target)) turn_guard(game); else { int index = index_from_position(game, game->guard); if (deface && game->map[index] == '.') { game->map[index] = 'X'; game->positions[game->position_count++] = index; } game->guard.x = target.x; game->guard.y = target.y; } } int main() { char *dirty_map = aoc_read_input(); Game game; game.map = dirty_map; game.width = strchr(game.map, '\n') - game.map + 1; game.height = strlen(game.map) / game.width; game.position_count = 0; for (int i = 0; i < strlen(game.map); i++) { if (game.map[i] == '^') { game.map[i] = '.'; game.guard = position_from_index(&game, i); game.guard_direction = UP; game.guard_start = game.guard; game.guard_start_direction = game.guard_direction; break; } } char *clean_map = malloc(strlen(dirty_map) + 1); strcpy(clean_map, dirty_map); Game time_travel_game; time_travel_game.map = clean_map; time_travel_game.width = game.width; time_travel_game.height = game.height; time_travel_game.position_count = 0; time_travel_game.guard = game.guard; time_travel_game.guard_direction = game.guard_direction; time_travel_game.guard_start = game.guard; time_travel_game.guard_start_direction = game.guard_direction; while (guard_inbounds(&game)) { move_guard(&game, true); } printf("Part 1: %d\n", game.position_count); int loop_count = 0; for (int i = 0; i < game.position_count; i++) { time_travel_game.map[game.positions[i]] = '#'; int gsx = time_travel_game.guard_start.x; int gsy = time_travel_game.guard_start.y; int gsd = time_travel_game.guard_start_direction; time_travel_game.guard = time_travel_game.guard_start; time_travel_game.guard_direction = time_travel_game.guard_start_direction; int j = 0; while (guard_inbounds(&time_travel_game)) { move_guard(&time_travel_game, false); if (time_travel_game.guard.x == gsx && time_travel_game.guard.y == gsy && time_travel_game.guard_direction == gsd) { loop_count++; break; } j++; if (j % MAX_LOOP_LENGTH == 0) { gsx = time_travel_game.guard.x; gsy = time_travel_game.guard.y; gsd = time_travel_game.guard_direction; } } time_travel_game.map[game.positions[i]] = '.'; } printf("Part 2: %d\n", loop_count); aoc_free(); return 0; }