#include #include #include #include #define LINE_MAX_LENGTH 256 #define MAX_QUEUE 256*256 #define cmp(a,b) ((a)[0] == (b)[0] && (a)[1] == (b)[1]) #define abs(a) ((a) < 0 ? -(a) : (a)) typedef enum tile_type { PATH, FOREST, SLOPE_UP, SLOPE_DOWN, SLOPE_LEFT, SLOPE_RIGHT, } tile_type_t; int check_direction(int curr[2], int dir[2], uint8_t **visited, tile_type_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH]); int highest_cost(int curr[2], tile_type_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH], int x, int y, uint8_t **visited, int cost, int finish[2], int ignore_slopes, int walkable); int curr_max = 0; int directions[4][2] = { {0, -1}, {0, 1}, {-1, 0}, {1, 0} }; int main() { char *p, *buf, c; buf = (char *)malloc(LINE_MAX_LENGTH); memset(buf, 0, LINE_MAX_LENGTH); p = buf; tile_type_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH]; int x = 0, y = 0; int walkable = 0; while ((c = getchar()) != EOF) { *p++ = c; if (c == '\n') { p = buf; x = 0; while (*p != '\n') { switch (*p) { case '.': map[x][y] = PATH; walkable++; break; case '#': map[x][y] = FOREST; break; case '^': map[x][y] = SLOPE_UP; walkable++; break; case 'v': map[x][y] = SLOPE_DOWN; walkable++; break; case '<': map[x][y] = SLOPE_LEFT; walkable++; break; case '>': map[x][y] = SLOPE_RIGHT; walkable++; break; } x++; p++; } y++; memset(buf, 0, LINE_MAX_LENGTH); p = buf; } } int start[2], finish[2]; start[1] = 0; finish[1] = y - 1; // Find start and finish for (int i = 0; i < x; i++) { if (map[i][0] == PATH) { start[0] = i; } if (map[i][y - 1] == PATH) { finish[0] = i; } } uint8_t **visited = (uint8_t**)malloc(x * sizeof(uint8_t*)); for (uint8_t i = 0; i < x; i++) { visited[i] = (uint8_t*)malloc(y * sizeof(uint8_t)); memset(visited[i], 0, y * sizeof(uint8_t)); } printf("Part 1: %i\n", highest_cost(start, map, x, y, visited, 0, finish, 0, walkable)); for (uint8_t i = 0; i < x; i++) { memset(visited[i], 0, y * sizeof(uint8_t)); } printf("Part 2: %i\n", highest_cost(start, map, x, y, visited, 0, finish, 1, walkable)); free(buf); for (int i = 0; i < y; i++) { free(visited[i]); } free(visited); } int highest_cost(int curr[2], tile_type_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH], int x, int y, uint8_t **visited, int cost, int finish[2], int ignore_slopes, int walkable) { if (cmp(curr, finish)) { return cost; } // We will never reach the end if ((walkable - cost) < (abs(finish[0] - curr[0]) + abs(finish[1] - curr[1])) || visited[finish[0]][finish[1]-1]) { return -1; } visited[curr[0]][curr[1]] = 1; int *options[4], options_num = 0, *dir, max = 0; if (map[curr[0]][curr[1]] == SLOPE_UP && !ignore_slopes) { dir = directions[0]; if (check_direction(curr, dir, visited, map)) { options[0] = dir; options_num = 1; } } else if (map[curr[0]][curr[1]] == SLOPE_DOWN && !ignore_slopes) { dir = directions[1]; if (check_direction(curr, dir, visited, map)) { options[0] = dir; options_num = 1; } } else if (map[curr[0]][curr[1]] == SLOPE_LEFT && !ignore_slopes) { dir = directions[2]; if (check_direction(curr, dir, visited, map)) { options[0] = dir; options_num = 1; } } else if (map[curr[0]][curr[1]] == SLOPE_RIGHT && !ignore_slopes) { dir = directions[3]; if (check_direction(curr, dir, visited, map)) { options[0] = dir; options_num = 1; } } else { for (int i = 0; i < 4; i++) { int *dir = directions[i]; if (check_direction(curr, dir, visited, map)) { options[options_num] = dir; options_num++; } } } if (options_num == 0) { return -1; } uint8_t ***visited_copies = (uint8_t***)malloc(options_num * sizeof(uint8_t**)); for (uint8_t i = 0; i < options_num - 1; i++) { visited_copies[i] = (uint8_t**)malloc(x * sizeof(uint8_t*)); for (uint8_t j = 0; j < y; j++) { visited_copies[i][j] = (uint8_t*)malloc(y * sizeof(uint8_t)); memcpy(visited_copies[i][j], visited[j], y * sizeof(uint8_t)); } } for (int i = 0; i < options_num; i++) { int next[2]; next[0] = curr[0] + options[i][0]; next[1] = curr[1] + options[i][1]; int c; if (i != options_num - 1) { c = highest_cost(next, map, x, y, visited_copies[i], cost + 1, finish, ignore_slopes, walkable); } else { c = highest_cost(next, map, x, y, visited, cost + 1, finish, ignore_slopes, walkable); } if (c > max) { max = c; } } for (int i = 0; i < options_num - 1; i++) { for (int j = 0; j < y; j++) { free(visited_copies[i][j]); } free(visited_copies[i]); } free(visited_copies); if (max > curr_max) { curr_max = max; printf("Current best: %i\n", curr_max); } return max; } int check_direction(int curr[2], int dir[2], uint8_t **visited, tile_type_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH]) { int next_x = curr[0] + dir[0]; int next_y = curr[1] + dir[1]; if (next_y > 0 && !visited[next_x][next_y] && map[next_x][next_y] != FOREST) { return 1; } return 0; }