aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2024/16/Makefile24
-rw-r--r--2024/16/day16a.cpp180
-rw-r--r--2024/16/day16b.cpp219
-rw-r--r--2024/template.cpp1
4 files changed, 424 insertions, 0 deletions
diff --git a/2024/16/Makefile b/2024/16/Makefile
new file mode 100644
index 0000000..8d9b7c0
--- /dev/null
+++ b/2024/16/Makefile
@@ -0,0 +1,24 @@
1CC=g++ -std=c++20 -g -Wall
2
3a:
4 ${CC} -o a.out day16a.cpp
5
6b:
7 ${CC} -o b.out day16b.cpp
8
9clean:
10 rm -f a b
11
12atest: a
13 ./a.out
14
15btest: b
16 ./b.out
17
18arun: a
19 ./a.out < input
20
21brun: b
22 ./b.out < input
23
24.PHONY: a b clean atest btest arun brun
diff --git a/2024/16/day16a.cpp b/2024/16/day16a.cpp
new file mode 100644
index 0000000..28e852c
--- /dev/null
+++ b/2024/16/day16a.cpp
@@ -0,0 +1,180 @@
1#include <algorithm>
2#include <cstdint>
3#include <iostream>
4#include <queue>
5#include <string>
6#include <string_view>
7#include <vector>
8#include <set>
9using namespace std;
10
11class Direction {
12public:
13 int U, R;
14
15 Direction(char c) :
16 U{c == 'v' ? 1 : (c == '^' ? -1 : 0)},
17 R{c == '>' ? 1 : (c == '<' ? -1 : 0)} {}
18
19 Direction(const int i, const int j) : U{i}, R{j} {}
20
21 Direction turnright() const {
22 return turn(-1, 0);
23 }
24
25 Direction turnleft() const {
26 return turn(1, 0);
27 }
28
29 bool operator<(const Direction& d) const { // For set<Direction>
30 return this->U < d.U || (this->U == d.U && this->R < d.R);
31 }
32
33 int index() const {
34 if (U == 1 && R == 0) return 0;
35 if (U == -1 && R == 0) return 1;
36 if (U == 0 && R == 1) return 2;
37 if (U == 0 && R == -1) return 3;
38 return -1;
39 }
40private:
41 Direction turn(int64_t sin, int64_t cos) const {
42 return Direction(cos * U - sin * R, sin * U + cos * R);
43 }
44};
45
46class Position {
47public:
48 int64_t i, j;
49
50 Position() : Position(0, 0) {}
51
52 Position(int64_t a, int64_t b) : i{a}, j{b} {}
53
54 Position step(const Direction d) const {
55 return Position(i+d.U, j+d.R);
56 }
57};
58
59const Direction all_directions[] = {
60 Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
61};
62
63class Qelem {
64public:
65 int64_t distance;
66 Position p;
67 Direction d;
68
69 Qelem(int dis, Position pp, Direction dd) :
70 distance{dis}, p{pp}, d{dd} {}
71
72 bool operator<(const Qelem& other) const {
73 return distance > other.distance;
74 }
75};
76
77class Board {
78public:
79 int64_t N, M;
80
81 Board(const vector<string>& lines) :
82 N{static_cast<int64_t>(lines.size())},
83 M{static_cast<int64_t>(lines[0].size())},
84 cells(M*N), visited(4*M*N)
85 {
86 for (int64_t i = 0; i < N; i++)
87 for (int64_t j = 0; j < M; j++)
88 cells[M*i+j] = lines[i][j];
89 }
90
91 char& operator[](const Position p) {
92 if (const auto c = coord(p); c == -1)
93 return out_of_bound;
94 else
95 return cells[c];
96 }
97
98 Position find_S() {
99 for (Position p(0, 0); p.i < N; p.i++)
100 for (p.j = 0; p.j < M; p.j++)
101 if ((*this)[p] == 'S')
102 return p;
103 return Position(-1, -1);
104 }
105
106 int shortest_path(Position p, Direction d) {
107 clear_visited();
108 priority_queue<Qelem> q;
109
110 q.push(Qelem(0, p, d));
111
112 while (!q.empty()) {
113 auto e = q.top();
114 q.pop();
115
116 if ((*this)[e.p] == 'E')
117 return e.distance;
118
119 if (is_visited(e.p, e.d) || (*this)[e.p] == '#')
120 continue;
121 set_visited(e.p, e.d);
122
123 q.push(Qelem(e.distance+1000, e.p, e.d.turnright()));
124 q.push(Qelem(e.distance+1000, e.p, e.d.turnleft()));
125 q.push(Qelem(e.distance+1, e.p.step(e.d), e.d));
126 }
127 return 999999999;
128 }
129
130 void print() {
131 for (Position p(0, 0); p.i < N; p.i++) {
132 for (p.j = 0; p.j < M; p.j++)
133 cout << (*this)[p];
134 cout << endl;
135 }
136 }
137private:
138 char out_of_bound = '$';
139
140 vector<char> cells;
141 vector<bool> visited;
142
143 int64_t coord(const Position p) const {
144 auto [i, j] = p;
145 return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j;
146 }
147
148 void clear_visited() {
149 for (int64_t i = 0; i < 4*M*N; i++)
150 visited[i] = false;
151 }
152
153 bool is_visited(const Position p, const Direction d) {
154 if (const auto c = coord(p); c == -1)
155 return false;
156 else
157 return visited[4*c + d.index()];
158 }
159
160 void set_visited(const Position p, const Direction d) {
161 if (const auto c = coord(p); c != -1)
162 visited[4*c + d.index()] = true;
163 }
164};
165
166int main() {
167 string line;
168 vector<string> lines;
169
170 while (getline(cin, line))
171 lines.push_back(line);
172
173 Board board(lines);
174 Direction d('>');
175 Position p = board.find_S();
176
177 cout << board.shortest_path(p, d) << endl;
178
179 return 0;
180}
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}
diff --git a/2024/template.cpp b/2024/template.cpp
index e3fadb3..86077cc 100644
--- a/2024/template.cpp
+++ b/2024/template.cpp
@@ -2,6 +2,7 @@
2#include <cstdint> 2#include <cstdint>
3#include <iostream> 3#include <iostream>
4#include <map> 4#include <map>
5#include <queue>
5#include <ranges> 6#include <ranges>
6#include <set> 7#include <set>
7#include <sstream> 8#include <sstream>

Generated with cgit - Back to sebastiano.tronto.net