1
+ #include " common.h"
2
+
3
+ namespace {
4
+ struct Packet ;
5
+ using Packets = std::vector<Packet>;
6
+ struct Packet {
7
+ std::variant<int , Packets> d;
8
+ };
9
+
10
+ Packet _parse (const std::string &str, size_t &begin) {
11
+ Packets pkts{};
12
+ while (str[begin] != ' ]' ) {
13
+ if (str[begin] == ' [' ) {
14
+ pkts.emplace_back (_parse (str, ++begin));
15
+ } else if (str[begin] == ' ,' ) {
16
+ ++begin;
17
+ } else {
18
+ int i;
19
+ std::istringstream ss{str};
20
+ ss.seekg (begin, std::ios_base::beg);
21
+ ss >> i;
22
+ pkts.emplace_back (i);
23
+ begin = ss.tellg ();
24
+ }
25
+ }
26
+ ++begin;
27
+ return Packet{pkts};
28
+ }
29
+
30
+ Packet parse (const std::string &str) {
31
+ size_t s{1 };
32
+ return _parse (str, s);
33
+ }
34
+
35
+ int compare (const Packet &p1, const Packet &p2) {
36
+ if (std::holds_alternative<Packets>(p1.d ) &&
37
+ std::holds_alternative<Packets>(p2.d )) {
38
+ const auto &pkts1 = std::get<Packets>(p1.d );
39
+ const auto &pkts2 = std::get<Packets>(p2.d );
40
+ size_t i{0 }, j{0 };
41
+ for (; i < pkts1.size () && j < pkts2.size (); ++i, ++j) {
42
+ if (int r{}; (r = compare (pkts1[i], pkts2[j])) != 0 )
43
+ return r;
44
+ }
45
+ return compare (Packet{static_cast <int >(pkts1.size () - i)},
46
+ Packet{static_cast <int >(pkts2.size () - j)});
47
+ } else if (std::holds_alternative<Packets>(p1.d )) {
48
+ return compare (p1, Packet{Packets{p2}});
49
+ } else if (std::holds_alternative<Packets>(p2.d )) {
50
+ return compare (Packet{Packets{p1}}, p2);
51
+ }
52
+ ASSERT_EXPR (std::holds_alternative<int >(p1.d ), " p1 not int" );
53
+ ASSERT_EXPR (std::holds_alternative<int >(p2.d ), " p2 not int" );
54
+ return (std::get<int >(p1.d ) < std::get<int >(p2.d )) -
55
+ (std::get<int >(p2.d ) < std::get<int >(p1.d ));
56
+ }
57
+
58
+ long p1 (const auto &input) {
59
+ long res{0 };
60
+ for (size_t i{0 }; i < input.size (); i += 3 ) {
61
+ const auto &pkt1 = parse (input[i]);
62
+ const auto &pkt2 = parse (input[i + 1 ]);
63
+ res += (compare (pkt1, pkt2) > 0 ) ? ((i / 3 ) + 1 ) : 0 ;
64
+ }
65
+ return res;
66
+ }
67
+
68
+ long p2 (auto input) {
69
+ input.emplace_back (" [[2]]" );
70
+ input.emplace_back (" [[6]]" );
71
+ auto comparer = [](std::string &a, std::string &b) {
72
+ const auto &p1 = parse (a);
73
+ const auto &p2 = parse (b);
74
+ return compare (p1, p2) > 0 ;
75
+ };
76
+ std::vector<std::string> pkts;
77
+ std::ranges::for_each (
78
+ input | std::ranges::views::filter (
79
+ [](const std::string &s) { return !s.empty (); }),
80
+ [&pkts](const auto &pkt) { pkts.emplace_back (pkt); });
81
+ std::ranges::sort (
82
+ pkts,
83
+ comparer); // one cannot simply sort the ouput of `views::filter` because
84
+ // the `ranges::sort` requires a random access iterator whereas
85
+ // the `filter` only produces a forward iterator
86
+ size_t i = (std::ranges::find (pkts, " [[2]]" ) - pkts.begin ()) + 1 ;
87
+ size_t j = (std::ranges::find (pkts, " [[6]]" ) - pkts.begin ()) + 1 ;
88
+ return i * j;
89
+ }
90
+ } // namespace
91
+
92
+ int main () {
93
+ const auto &input = gb::advent2021::readIn ();
94
+ gb::advent2021::writeOut (std::to_string (p1 (input)));
95
+ gb::advent2021::writeOut (std::to_string (p2 (input)));
96
+ }
0 commit comments