169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdbool.h>
 | |
| 
 | |
| #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;
 | |
| }
 |