aboutsummaryrefslogtreecommitdiff
path: root/2024/16/day16b.cpp
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-12-16 09:33:38 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2024-12-16 09:33:38 +0100
commit5a725f1b9e8cfbad2c31d9c220061e413adbbf8e (patch)
tree70119de6d0fa800851ed25f53e02b0474c8fa0cb /2024/16/day16b.cpp
parent9ecea0012b98f42debd536dc863b4ef2501eb859 (diff)
downloadaoc-5a725f1b9e8cfbad2c31d9c220061e413adbbf8e.tar.gz
aoc-5a725f1b9e8cfbad2c31d9c220061e413adbbf8e.zip
Day 16 2024
Diffstat (limited to '2024/16/day16b.cpp')
-rw-r--r--2024/16/day16b.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/2024/16/day16b.cpp b/2024/16/day16b.cpp
new file mode 100644
index 0000000..a3e128d
--- /dev/null
+++ b/2024/16/day16b.cpp
@@ -0,0 +1,219 @@
1/*
2This solution is bad, it runs in 45 minutes or so. Baiscally I find the
3distances between all pairs of valid (position, direction) pairs; a position p
4is on a valid shortest path if and only if for any direction d in {>, <, v, ^}
5the distance from (S, >) to (p, d) plus the distance from (p, d) to E is
6equal to the shortest path distance.
7
8I tried to do smarter things but I kept making mistakes. This one is
9inefficient, but it has the advantage of requiring minimal changes from part 1.
10*/
11
12#include <algorithm>
13#include <cstdint>
14#include <iostream>
15#include <queue>
16#include <string>
17#include <string_view>
18#include <vector>
19#include <set>
20using namespace std;
21
22#define INF 999999999
23
24class Direction {
25public:
26 int U, R;
27
28 Direction(char c) :
29 U{c == 'v' ? 1 : (c == '^' ? -1 : 0)},
30 R{c == '>' ? 1 : (c == '<' ? -1 : 0)} {}
31
32 Direction(const int i, const int j) : U{i}, R{j} {}
33
34 Direction turnright() const {
35 return turn(-1, 0);
36 }
37
38 Direction turnleft() const {
39 return turn(1, 0);
40 }
41
42 bool operator<(const Direction& d) const { // For set<Direction>
43 return this->U < d.U || (this->U == d.U && this->R < d.R);
44 }
45
46 int index() const {
47 if (U == 1 && R == 0) return 0;
48 if (U == -1 && R == 0) return 1;
49 if (U == 0 && R == 1) return 2;
50 if (U == 0 && R == -1) return 3;
51 return -1;
52 }
53private:
54 Direction turn(int64_t sin, int64_t cos) const {
55 return Direction(cos * U - sin * R, sin * U + cos * R);
56 }
57};
58
59class Position {
60public:
61 int64_t i, j;
62
63 Position() : Position(0, 0) {}
64
65 Position(int64_t a, int64_t b) : i{a}, j{b} {}
66
67 Position step(const Direction d) const {
68 return Position(i+d.U, j+d.R);
69 }
70};
71
72const Direction all_directions[] = {
73 Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
74};
75
76class Qelem {
77public:
78 int64_t distance;
79 Position p;
80 Direction d;
81
82 Qelem(int dis, Position pp, Direction dd) :
83 distance{dis}, p{pp}, d{dd} {}
84
85 bool operator<(const Qelem& other) const {
86 return distance > other.distance;
87 }
88};
89
90class Board {
91public:
92 int64_t N, M;
93
94 Board(const vector<string>& lines) :
95 N{static_cast<int64_t>(lines.size())},
96 M{static_cast<int64_t>(lines[0].size())},
97 cells(M*N), visited(4*M*N)
98 {
99 for (int64_t i = 0; i < N; i++)
100 for (int64_t j = 0; j < M; j++)
101 cells[M*i+j] = lines[i][j];
102 }
103
104 char& operator[](const Position p) {
105 if (const auto c = coord(p); c == -1)
106 return out_of_bound;
107 else
108 return cells[c];
109 }
110
111 Position find_S() {
112 for (Position p(0, 0); p.i < N; p.i++)
113 for (p.j = 0; p.j < M; p.j++)
114 if ((*this)[p] == 'S')
115 return p;
116 return Position(-1, -1);
117 }
118
119 int shortest_path(Position p, Direction d, vector<int>& shortest, bool save) {
120 clear_visited();
121 if (save)
122 for (int i = 0; i < 4*M*N; i++)
123 shortest[i] = INF;
124
125 priority_queue<Qelem> q;
126
127 q.push(Qelem(0, p, d));
128
129 while (!q.empty()) {
130 auto e = q.top();
131 q.pop();
132
133 if ((*this)[e.p] == 'E')
134 return e.distance;
135
136 if (is_visited(e.p, e.d) || (*this)[e.p] == '#')
137 continue;
138 set_visited(e.p, e.d);
139
140 if (save)
141 shortest[4*coord(e.p) + e.d.index()] = e.distance;
142
143 q.push(Qelem(e.distance+1000, e.p, e.d.turnright()));
144 q.push(Qelem(e.distance+1000, e.p, e.d.turnleft()));
145 q.push(Qelem(e.distance+1, e.p.step(e.d), e.d));
146 }
147 return 999999999;
148 }
149
150 void print() {
151 for (Position p(0, 0); p.i < N; p.i++) {
152 for (p.j = 0; p.j < M; p.j++)
153 cout << (*this)[p];
154 cout << endl;
155 }
156 }
157
158 int64_t coord(const Position p) const {
159 auto [i, j] = p;
160 return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j;
161 }
162private:
163 char out_of_bound = '$';
164
165 vector<char> cells;
166 vector<bool> visited;
167
168 void clear_visited() {
169 for (int64_t i = 0; i < 4*M*N; i++)
170 visited[i] = false;
171 }
172
173 bool is_visited(const Position p, const Direction d) {
174 if (const auto c = coord(p); c == -1)
175 return false;
176 else
177 return visited[4*c + d.index()];
178 }
179
180 void set_visited(const Position p, const Direction d) {
181 if (const auto c = coord(p); c != -1)
182 visited[4*c + d.index()] = true;
183 }
184};
185
186int main() {
187 string line;
188 vector<string> lines;
189
190 while (getline(cin, line))
191 lines.push_back(line);
192
193 Board board(lines);
194
195 vector<int> v(4*board.N*board.M);
196 int sh = board.shortest_path(board.find_S(), Direction('>'), v, true);
197
198 int count = 0;
199 for (Position p(0, 0); p.i < board.N; p.i++) {
200 for (p.j = 0; p.j < board.M; p.j++) {
201 cout << "Checking intermediate position "
202 << p.i << ", " << p.j << endl;
203 if (board[p] == '#') continue;
204 for (auto d : all_directions) {
205 int i = 4*board.coord(p) + d.index();
206 if (v[i] == INF) continue;
207 int ssh = board.shortest_path(p, d, v, false);
208 if (ssh + v[i] == sh) {
209 count++;
210 break;
211 }
212 }
213 }
214 }
215
216 cout << count+1 << endl;
217
218 return 0;
219}

Generated with cgit - Back to sebastiano.tronto.net