2
2
namespace {
3
3
4
4
using Scalar = int ;
5
- using Cost = unsigned short ;
5
+ using Cost = int ;
6
+ template <typename T> using Vec = std::vector<T>;
6
7
7
8
struct Cell {
8
- static constexpr Cost MAXCOST = std::numeric_limits<Cost>::max() - 1 ;
9
- static constexpr Cost WALL = std::numeric_limits<Cost>::max();
9
+ static constexpr Cost MAXCOST = std::numeric_limits<Cost>::max();
10
+ static constexpr Cost WALL = - 1 ; // less than any other cost, so looks visited.
10
11
Cost cost;
11
12
Cell ( char c ) : cost{ c == ' #' ? WALL :MAXCOST} {}
12
- bool wall () const { return cost == WALL; }
13
13
};
14
14
15
15
struct Point {
16
- Scalar row{}, col{};
17
- Point operator + (const Point &rhs) const noexcept { return { Scalar (row + rhs.row ), Scalar (col + rhs.col ) }; }
16
+ Scalar row_, col_;
17
+ Point operator + (const Point &rhs) const noexcept {
18
+ return { Scalar (row () + rhs.row ()), Scalar (col () + rhs.col ()) }; }
18
19
auto operator <=> (const Point &) const = default ;
19
- unsigned mag () const { return abs (row) + abs (col); }
20
+ int mag () const { return abs (row ()) + abs (col ()); }
21
+ Scalar row () const { return row_; }
22
+ Scalar col () const { return col_; }
20
23
};
21
24
22
25
enum Direction { NORTH, EAST, SOUTH, WEST };
23
26
constexpr Point velocities[] = { {Scalar (-1 ), 0 }, {0 , 1 }, {1 , 0 }, {0 , Scalar (-1 )} };
24
27
25
28
struct Maze {
26
- std::vector <Cell> cells;
29
+ Vec <Cell> cells;
27
30
Scalar cols{}, rows{};
28
31
Point START, END;
29
- bool contains (Point p) { return p.row >= 0 && p.row < rows && p.col >= 0 && p.col < cols; }
30
- Cell &at (Point p) { return cells[p.row * cols + p.col ]; }
31
- const Cell &at (Point p) const { return cells[p.row * cols + p.col ]; }
32
+ bool contains (Point p) { return p.row () >= 0 && p.row () < rows && p.col () >= 0 && p.col () < cols; }
33
+ Cell &at (Point p) { return cells[p.row () * cols + p.col () ]; }
34
+ const Cell &at (Point p) const { return cells[p.row () * cols + p.col () ]; }
32
35
// our maze has a single direction, so we just have to find the first
33
- std::vector<Point> pathfind () {
34
- std::vector<Point> path;
36
+ template < typename V>
37
+ void pathfind (V & path) {
35
38
path.push_back (START);
36
39
at (START).cost = 0 ;
37
40
for (size_t pos = 0 ; path[pos] != END; ++pos) {
@@ -42,15 +45,15 @@ struct Maze {
42
45
if (!contains (to))
43
46
continue ;
44
47
auto &cell = at (to);
45
- if (cell.wall () || cell. cost <= existing.cost + 1 )
48
+ if (cell.cost <= existing.cost + 1 )
46
49
continue ;
47
50
cell.cost = existing.cost + 1 ;
48
51
path.push_back (to);
49
52
}
50
53
assert (path.size () > pos);
51
54
}
52
- return path;
53
55
}
56
+ Maze (const Maze &) = delete ;
54
57
Maze (std::istream &is) noexcept {
55
58
cells.reserve (141 * 141 );
56
59
rows = 0 ;
@@ -70,31 +73,29 @@ struct Maze {
70
73
}
71
74
};
72
75
73
- void solve (std::istream &is, std::ostream &os, int maxdistance, int threshold) {
76
+ template <int maxdistance, int threshold>
77
+ void solve (std::istream &is, std::ostream &os) {
74
78
Maze maze (is);
75
- std::vector<Point> path = maze.pathfind ();
76
-
77
- unsigned long total = 0 ;
78
-
79
+ Vec<Point> path;
80
+ maze.pathfind (path);
81
+ int total = 0 ;
79
82
for (const auto &start : path) {
80
- for (int rowdelta = -maxdistance; rowdelta <= maxdistance; ++rowdelta) {
81
- for (int coldelta = -maxdistance + abs (rowdelta); coldelta <= maxdistance - abs (rowdelta); ++coldelta) {
83
+ int minrowd = std::max (-maxdistance, -start.row ());
84
+ int maxrowd = std::min (maxdistance, maze.rows - start.row () - 1 );
85
+ const Cell &startcell = maze.at (start);
86
+ for (int rowdelta = minrowd; rowdelta <= maxrowd; ++rowdelta) {
87
+ int mincold = std::max ( -maxdistance + abs (rowdelta), -start.col ());
88
+ int maxcold = std::min ( maxdistance - abs (rowdelta), maze.cols - start.col () - 1 );
89
+ for (int coldelta = mincold; coldelta <= maxcold; ++coldelta) {
82
90
Point delta = {rowdelta, coldelta};
83
- Point end = start + delta;
84
- if (!maze.contains (end))
85
- continue ;
86
- const Cell &startcell = maze.at (start);
87
- const Cell &endcell = maze.at (end);
88
- if (!endcell.wall () && endcell.cost > startcell.cost + delta.mag () &&
89
- endcell.cost - startcell.cost - delta.mag () >= threshold)
91
+ if (maze.at (start + delta).cost - startcell.cost - delta.mag () >= threshold)
90
92
total++;
91
93
}
92
94
}
93
95
}
94
96
os << " \n " << total;
95
97
}
96
98
97
- aoc::Case P1{" part1" , [](auto &is, auto &os) { solve (is, os, 2 , 100 ); }};
98
- aoc::Case P2{" part2" , [](auto &is, auto &os) { solve (is, os, 20 , 100 ); }};
99
- aoc::Case EG{" eg" , [](auto &is, auto &os) { solve (is, os, 20 , 50 ); }};
99
+ aoc::Case P1{" part1" , [](auto &is, auto &os) { solve<2 ,100 >(is, os); }};
100
+ aoc::Case P2{" part2" , [](auto &is, auto &os) { solve<20 ,100 >(is, os); }};
100
101
}
0 commit comments