1
+ #include " common_headers.hpp"
2
+
3
+ using Heights = std::vector<size_t >;
4
+
5
+ struct LocksAndKeys final
6
+ {
7
+ size_t lockHeight{7 };
8
+ std::vector<Heights> locks;
9
+ std::vector<Heights> keys;
10
+ };
11
+
12
+
13
+ [[nodiscard]] size_t solveFirstPart (const LocksAndKeys& locksAndKeys)
14
+ {
15
+ size_t count{};
16
+ for (const auto & lock : locksAndKeys.locks ) {
17
+ for (const auto & key : locksAndKeys.keys ) {
18
+ if (lock.size () != key.size ()) {
19
+ throw std::logic_error{" sizes of lock and key differ" };
20
+ }
21
+ bool fit{true };
22
+ for (size_t i = 0 ; i < lock.size (); ++i) {
23
+ fit = fit && (lock[i] + key[i] <= locksAndKeys.lockHeight );
24
+ }
25
+ count += fit;
26
+ }
27
+ }
28
+ return count;
29
+ }
30
+
31
+ [[nodiscard]] size_t parseHeights (const std::vector<std::string>& inputVec, size_t beginInputId, Heights& heights)
32
+ {
33
+ size_t inputId{beginInputId};
34
+ heights.reserve (inputVec[0 ].size ());
35
+ for (size_t column = 0 ; column < inputVec[0 ].size (); ++column) {
36
+ auto row = inputId;
37
+ size_t height{};
38
+ while (row < inputVec.size () && !inputVec[row].empty ()) {
39
+ height += (inputVec[row][column] == ' #' );
40
+ ++row;
41
+ }
42
+ heights.push_back (height);
43
+ }
44
+
45
+ while (inputId < inputVec.size () && !inputVec[inputId].empty ()) ++inputId;
46
+ ++inputId; // < skip empty line
47
+ return inputId;
48
+ }
49
+
50
+ [[nodiscard]] size_t parseLocks (const std::vector<std::string>& inputVec, size_t beginInputId, LocksAndKeys& locksAndKeys)
51
+ {
52
+ size_t inputId{beginInputId};
53
+ while (inputId < inputVec.size () && inputVec[inputId][0 ] == ' #' ) {
54
+ locksAndKeys.locks .emplace_back ();
55
+ inputId = parseHeights (inputVec, inputId, locksAndKeys.locks .back ());
56
+
57
+ if (locksAndKeys.locks .back ().empty ()) {
58
+ locksAndKeys.locks .back ().pop_back ();
59
+ }
60
+ }
61
+ return inputId;
62
+ }
63
+
64
+ [[nodiscard]] size_t parseKeys (const std::vector<std::string>& inputVec, size_t beginInputId, LocksAndKeys& locksAndKeys)
65
+ {
66
+ size_t inputId{beginInputId};
67
+ while (inputId < inputVec.size () && inputVec[inputId][0 ] == ' .' ) {
68
+ locksAndKeys.keys .emplace_back ();
69
+ inputId = parseHeights (inputVec, inputId, locksAndKeys.keys .back ());
70
+
71
+ if (locksAndKeys.keys .back ().empty ()) {
72
+ locksAndKeys.keys .back ().pop_back ();
73
+ }
74
+ }
75
+ return inputId;
76
+ }
77
+
78
+ [[nodiscard]] LocksAndKeys parseInput (const std::vector<std::string>& inputVec)
79
+ {
80
+ LocksAndKeys locksAndKeys;
81
+ size_t inputId{};
82
+ while (inputId < inputVec.size ()) {
83
+ inputId = parseLocks (inputVec, inputId, locksAndKeys);
84
+ inputId = parseKeys (inputVec, inputId, locksAndKeys);
85
+ }
86
+
87
+ return locksAndKeys;
88
+ }
89
+
90
+ void printHelp ()
91
+ {
92
+ std::cerr << " \n Usage:\n "
93
+ << " The program requires 2 args: (part1, part2) and the path to the file."
94
+ << " \n For example, ./day7 part1 data/day7.txt" ;
95
+ }
96
+
97
+ int main (int argc, char * argv[])
98
+ {
99
+ if (argc != 3 ) {
100
+ printHelp ();
101
+ return 1 ;
102
+ }
103
+
104
+ std::string_view task{argv[1 ]};
105
+ if (task != " part1" && task != " part2" ) {
106
+ std::cerr << " \n first arg can be either `part1` or `part2`\n " ;
107
+ printHelp ();
108
+ return 1 ;
109
+ }
110
+
111
+ std::vector<std::string> inputVec;
112
+ readInput (argv[2 ], std::back_inserter (inputVec));
113
+
114
+ auto locksAndKeys = parseInput (inputVec);
115
+
116
+ if (task == " part1" ) {
117
+ std::cout << solveFirstPart (locksAndKeys);
118
+ }
119
+ else {
120
+ // std::cout << solveSecondPart(program);
121
+ }
122
+
123
+ return 0 ;
124
+ }
0 commit comments