1
+ #include " common.h"
2
+
3
+ namespace {
4
+ #define NOT_FOUND -1
5
+ using Pos = std::complex<size_t >;
6
+ using Heading = std::complex<long >;
7
+
8
+ long solve (const auto &input, Pos st, Pos end) {
9
+ size_t m = input.size (), n = input[0 ].size ();
10
+
11
+ auto hasher = [](const Pos &k) -> std::size_t {
12
+ return std::hash<long >()(k.real ()) ^ std::hash<long >()(k.imag ());
13
+ };
14
+ auto within_bounds = [&m, &n](const Heading &v) -> bool {
15
+ return v.imag () >= 0 && v.real () >= 0 && v.imag () < static_cast <long >(n) &&
16
+ v.real () < static_cast <long >(m);
17
+ };
18
+ auto within_height = [&input](const Pos &u, const Heading &v) -> bool {
19
+ return (input[v.real ()][v.imag ()] - input[u.real ()][u.imag ()] <= 1 );
20
+ };
21
+ std::array<Heading, 4 > dirs = {Heading{-1 , 0 }, Heading{1 , 0 }, Heading{0 , -1 },
22
+ Heading{0 , 1 }};
23
+ std::deque<std::tuple<Pos, long >> frontier{{st, 0 }};
24
+ std::unordered_set<Pos, decltype (hasher)> visited{st};
25
+ long res{NOT_FOUND};
26
+ while (frontier.size () > 0 && res == NOT_FOUND) {
27
+ const auto &[u, d] = frontier.front ();
28
+ if (u == end) {
29
+ res = d;
30
+ continue ;
31
+ }
32
+ for (const auto &dir : dirs) {
33
+ Heading v = dir + static_cast <Heading>(u);
34
+ if (!visited.contains (static_cast <Pos>(v)) && within_bounds (v) &&
35
+ within_height (u, v)) {
36
+ frontier.push_back ({v, d + 1 });
37
+ visited.emplace (v);
38
+ }
39
+ }
40
+ frontier.pop_front ();
41
+ }
42
+ return res;
43
+ }
44
+
45
+ long p1 (auto input) {
46
+ Pos st{}, end{};
47
+ for (size_t i{0 }; const auto &line : input) {
48
+ if (size_t j{0 }; (j = line.find (" S" )) != std::string::npos)
49
+ st = Pos{i, j};
50
+ if (size_t j{0 }; (j = line.find (" E" )) != std::string::npos)
51
+ end = Pos{i, j};
52
+ ++i;
53
+ }
54
+ input[st.real ()][st.imag ()] = ' a' ;
55
+ input[end.real ()][end.imag ()] = ' z' ;
56
+
57
+ const auto res = solve (input, st, end);
58
+ ASSERT_EXPR (res != NOT_FOUND, " Failed to find solution" );
59
+ return res;
60
+ }
61
+
62
+ long p2 (auto input) {
63
+ size_t m = input.size (), n = input[0 ].size ();
64
+
65
+ std::vector<Pos> strts{};
66
+ Pos end{};
67
+ for (size_t i{0 }; i < m; ++i) {
68
+ for (size_t j{0 }; j < n; ++j) {
69
+ if (input[i][j] == ' a' || input[i][j] == ' S' ) {
70
+ strts.emplace_back (Pos{i, j});
71
+ input[i][j] = ' a' ;
72
+ }
73
+ if (input[i][j] == ' E' ) {
74
+ end = Pos{i, j};
75
+ input[i][j] = ' z' ;
76
+ }
77
+ }
78
+ }
79
+
80
+ std::vector<long > res{};
81
+ for (const auto &st : strts) {
82
+ const auto t = solve (input, st, end);
83
+ if (t != NOT_FOUND)
84
+ res.emplace_back (t);
85
+ }
86
+ ASSERT_EXPR (res.size () != 0 , " Failed to find solution" );
87
+ return std::ranges::min (res);
88
+ }
89
+ } // namespace
90
+
91
+ int main () {
92
+ const auto &input = gb::advent2021::readIn ();
93
+ gb::advent2021::writeOut (std::to_string (p1 (input)));
94
+ gb::advent2021::writeOut (std::to_string (p2 (input)));
95
+ }
0 commit comments