220 lines
6.2 KiB
C
220 lines
6.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#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;
|
|
}
|