Skip to content

Commit e1434d7

Browse files
committed
day 16, needs a lot of cleanup
1 parent cf04f60 commit e1434d7

File tree

4 files changed

+174
-6
lines changed

4 files changed

+174
-6
lines changed

16/Makefile

Lines changed: 0 additions & 1 deletion
This file was deleted.

16/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
PARTOBJS = part1.o part2.o
2+
include ../Makefile.inc

16/solve.cc renamed to 16/part1.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct Point {
1919
struct Cell {
2020
char c; // can kill this when done debugging.
2121
unsigned wall:1;
22+
std::bitset<4> visited;
2223
Int costs[4] = { MAX, MAX, MAX, MAX };
2324
Cell(char c) : c(c), wall(c == '#') {}
2425
};
@@ -36,6 +37,7 @@ constexpr Direction rotate(Direction d) noexcept {
3637
return Direction((d + 1) % 4);
3738
}
3839

40+
[[maybe_unused]]
3941
std::ostream & operator << (std::ostream &os, Direction d) {
4042
switch (d) {
4143
case NORTH: return os << "NORTH";
@@ -68,12 +70,12 @@ struct Part {
6870
auto head = Q.begin();
6971
auto item = *head;
7072
Q.erase(head);
71-
at(item.pos).costs[item.d] = item.cost; // we now have the shortest path to this item.
72-
std::cout << "cost to row=" << item.pos.row << ", col=" << item.pos.col << " in direction " << item.d << " is " << item.cost <<"\n";
73+
at(item.pos).visited[item.d] = true; // we now have the shortest path to this item.
74+
//std::cout << "cost to row=" << item.pos.row << ", col=" << item.pos.col << " in direction " << item.d << " is " << item.cost <<"\n";
7375

7476
auto try_add = [&](Point p, Direction d, Int c) {
7577
auto &cell = at(p);
76-
if (!cell.wall && cell.costs[d] == MAX) {
78+
if (!cell.wall && !cell.visited[d] && cell.costs[d] > c) {
7779
Q.insert({.cost=c, .d=d, .pos=p });
7880
}
7981
};
@@ -85,7 +87,7 @@ struct Part {
8587
d = rotate(d);
8688
try_add(item.pos, d, item.cost + 2000);
8789
d = rotate(d);
88-
try_add(item.pos, d, item.cost + 2000);
90+
try_add(item.pos, d, item.cost + 1000);
8991
assert(!Q.empty());
9092
}
9193
return Q.begin()->cost;
@@ -115,7 +117,7 @@ struct Part {
115117

116118
struct Part1 : Part {
117119
Part1(std::istream &is) noexcept : Part(is) { }
118-
Int solve(std::ostream &os) {
120+
Int solve(std::ostream &) {
119121
return dijkstra();
120122
}
121123
};

16/part2.cc

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#include "aoc.h"
2+
3+
namespace {
4+
5+
enum Direction { NORTH, EAST, SOUTH, WEST };
6+
7+
using Scalar = unsigned;
8+
using Int = unsigned long;
9+
constexpr unsigned long MAX = std::numeric_limits<unsigned long>::max();
10+
11+
struct Point {
12+
Scalar row{}, col{};
13+
Point operator+ (const Point &rhs) const noexcept {
14+
return { uint8_t(row + rhs.row), uint8_t(col + rhs.col) };
15+
}
16+
auto operator <=> (const Point &rhs) const = default;
17+
};
18+
19+
struct Cell {
20+
char c; // can kill this when done debugging.
21+
unsigned wall:1;
22+
Int costs[4] = { MAX, MAX, MAX, MAX };
23+
Cell(char c) : c(c), wall(c == '#') {}
24+
};
25+
26+
constexpr Point velocity(Direction d) noexcept {
27+
switch (d) {
28+
case NORTH: return {Scalar(-1), 0};
29+
case SOUTH: return {1, 0};
30+
case EAST: return {0, 1};
31+
case WEST: return {0, Scalar(-1)};
32+
default: __builtin_unreachable();
33+
}
34+
}
35+
constexpr Direction rotate(Direction d) noexcept {
36+
return Direction((d + 1) % 4);
37+
}
38+
39+
[[maybe_unused]]
40+
std::ostream & operator << (std::ostream &os, Direction d) {
41+
switch (d) {
42+
case NORTH: return os << "NORTH";
43+
case SOUTH: return os << "SOUTH";
44+
case EAST: return os << "EAST";
45+
case WEST: return os << "WEST";
46+
default: __builtin_unreachable();
47+
}
48+
}
49+
50+
struct Key {
51+
Point pos;
52+
Direction d;
53+
auto operator <=> (const Key &rhs) const = default;
54+
};
55+
56+
struct Node {
57+
unsigned long cost { MAX };
58+
Key key;
59+
auto operator <=> (const Node &rhs) const = default;
60+
};
61+
62+
struct Part2 {
63+
std::vector<std::vector<Cell>> map;
64+
std::vector<std::vector<std::array<std::vector<Key>, 4>>> paths;
65+
Point s, e;
66+
67+
Cell & at(Point p) {
68+
return map[p.row][p.col];
69+
}
70+
71+
void visit(Key k, std::set<Point> &best_points) {
72+
best_points.insert(k.pos);
73+
if (k.pos != s) {
74+
for (auto &k2 : paths[k.pos.row][k.pos.col][k.d])
75+
visit(k2, best_points);
76+
}
77+
}
78+
79+
Int dijkstra() {
80+
std::set<Node> Q;
81+
Q.insert({.cost=0, .key={.pos = s, .d=EAST}});
82+
while (!Q.empty()) {
83+
auto head = Q.begin();
84+
auto item = *head;
85+
Q.erase(head);
86+
87+
auto try_add = [&](Key to, Int c, Key prev) {
88+
auto &cell = at(to.pos);
89+
if (!cell.wall) {
90+
if (cell.costs[to.d] == c) {
91+
paths[to.pos.row][to.pos.col][to.d].push_back(prev);
92+
} else if (cell.costs[to.d] > c) {
93+
paths[to.pos.row][to.pos.col][to.d].clear();
94+
paths[to.pos.row][to.pos.col][to.d].push_back(prev);
95+
Q.insert({.cost=c, .key=to});
96+
cell.costs[to.d] = c;
97+
}
98+
}
99+
};
100+
101+
Direction d = item.key.d;
102+
try_add(Key{item.key.pos + velocity(d), d}, item.cost + 1, item.key);
103+
d = rotate(d);
104+
try_add({item.key.pos, d}, item.cost + 1000, item.key);
105+
d = rotate(d);
106+
try_add({item.key.pos, d}, item.cost + 2000, item.key);
107+
d = rotate(d);
108+
try_add({item.key.pos, d}, item.cost + 1000, item.key);
109+
}
110+
auto ecell = at(e);
111+
auto ebest = *std::min_element( ecell.costs, ecell.costs + 4 );
112+
std::set<Point> best_points;
113+
114+
for (auto dir : { NORTH, SOUTH, EAST, WEST })
115+
if (ecell.costs[dir] == ebest)
116+
visit({e, dir}, best_points);
117+
return best_points.size();
118+
}
119+
120+
Part2(std::istream &is) noexcept {
121+
unsigned row = 0;
122+
for (std::string line; getline(is, line); ) {
123+
map.emplace_back();
124+
paths.emplace_back();
125+
unsigned col = 0;
126+
for (auto c : line) {
127+
map.back().emplace_back(c);
128+
paths.back().emplace_back();
129+
switch (c) {
130+
case 'S':
131+
s = { row, col };
132+
break;
133+
case 'E':
134+
e = { row, col };
135+
break;
136+
}
137+
++col;
138+
}
139+
++row;
140+
}
141+
}
142+
Int solve(std::ostream &) {
143+
return dijkstra();
144+
}
145+
};
146+
147+
148+
aoc::Case part2{"part2", [](std::istream &is, std::ostream &os) { os << Part2(is).solve(os); } };
149+
150+
}

16/small.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
###############
2+
#.......#....E#
3+
#.#.###.#.###.#
4+
#.....#.#...#.#
5+
#.###.#####.#.#
6+
#.#.#.......#.#
7+
#.#.#####.###.#
8+
#...........#.#
9+
###.#.#####.#.#
10+
#...#.....#.#.#
11+
#.#.#.###.#.#.#
12+
#.....#...#.#.#
13+
#.###.#.#.#.#.#
14+
#S..#.....#...#
15+
###############

0 commit comments

Comments
 (0)