-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path23-A-Long-Walk.cpp
More file actions
144 lines (114 loc) · 4.21 KB
/
23-A-Long-Walk.cpp
File metadata and controls
144 lines (114 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (C) 2024 Joe Baker (JoeBlakeB)
// Advent of Code 2023 - Day 23: A Long Walk
// Usage:
// scripts/cppRun.sh 2023/23-A-Long-Walk.cpp < 2023/inputs/23.txt
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "../Utils/Grid.cpp"
using namespace std;
struct NextCoordinate { int distance; bool uphill; };
typedef unordered_map<Coordinate, unordered_map<Coordinate, NextCoordinate>> Graph;
Graph buildGraph(const CharGrid& textForest, Coordinate start, Coordinate end) {
Graph graph;
queue<pair<Coordinate, Direction>> queue;
queue.push({start, DOWN});
unordered_set<Coordinate> visited;
while (!queue.empty()) {
auto [nodeStart, direction] = queue.front();
queue.pop();
Coordinate current = nodeStart(direction);
int distance = 0;
bool uphill = false;
// Get to the end of this path
char validNeighborsCount = 1;
while (validNeighborsCount == 1) {
distance++;
validNeighborsCount = 0;
Direction nextStepDirection = direction;
if ((textForest[current] == '>' && direction == LEFT) ||
(textForest[current] == 'v' && direction == UP)) {
uphill = true;
}
for (short i = 0; i < 4; i++) {
if ((i - direction + 2) % 4 == 0) {
continue;
}
char neighborValue = textForest[current(Direction(i))];
if (neighborValue == '#') {
continue;
}
validNeighborsCount++;
nextStepDirection = Direction(i);
}
if (validNeighborsCount == 1) {
current = current(nextStepDirection);
if (current == end) {
distance += direction != nextStepDirection;
break;
}
direction = nextStepDirection;
}
}
bool alreadyReachedJunction = visited.find(current) != visited.end();
// Add the junction to the graph
graph[nodeStart][current] = {distance, uphill};
// Add the next paths to the queue
if (!alreadyReachedJunction && current != end) {
visited.insert(current);
for (short i = 0; i < 4; i++) {
char neighborValue = textForest[current(Direction(i))];
if (neighborValue == '#') {
continue;
}
queue.push({current, Direction(i)});
}
}
}
return graph;
}
template<bool allowedUphill>
int findLongestDistance(const Graph& graph, Coordinate start, Coordinate end) {
unsigned int longestDistance = 0;
stack<tuple<Coordinate, vector<Coordinate>, unsigned int>> stack;
stack.push({start, {start}, 0});
while (!stack.empty()) {
auto [current, path, distance] = stack.top();
stack.pop();
for (auto [neighbor, nextCoordinate] : graph.at(current)) {
if (find(path.begin(), path.end(), neighbor) != path.end()) {
continue;
}
unsigned int newDistance = distance + nextCoordinate.distance;
if (neighbor == end) {
if (newDistance > longestDistance) {
longestDistance = newDistance;
}
continue;
}
if constexpr (!allowedUphill) {
if (nextCoordinate.uphill) {
continue;
}
}
vector<Coordinate> newPath = path;
newPath.push_back(neighbor);
stack.push({neighbor, newPath, newDistance});
}
}
return longestDistance;
}
int main() {
CharGrid textForest = {cin};
Coordinate start = {1, 0};
Coordinate end = {textForest.height - 2, textForest.width - 1};
Graph forestGraph = buildGraph(textForest, start, end);
cout << "Longest Downhill Hike: " << findLongestDistance<false>(forestGraph, start, end) << endl;
cout << "Longest Climbing Hike: " << findLongestDistance<true>(forestGraph, start, end) << endl;
return 0;
}