Skip to content

Commit b771c8e

Browse files
committed
Solve Day 15 Part 2
1 parent 44034ad commit b771c8e

File tree

2 files changed

+103
-17
lines changed

2 files changed

+103
-17
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@
9090
"unordered_set": "cpp",
9191
"ranges": "cpp",
9292
"shared_mutex": "cpp",
93-
"list": "cpp"
93+
"list": "cpp",
94+
"map": "cpp"
9495
},
9596
"cmake.configureOnOpen": true,
9697
"cmake.buildDirectory": "${workspaceFolder}/build/${buildType}"

day-15/day-15.cpp

Lines changed: 101 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,43 @@
1-
#include <unordered_map>
1+
#include <array>
2+
#include <numeric>
23
#include "../aocio/aocio.hpp"
34

45
/*
56
Problem: https://adventofcode.com/2023/day/15
67
78
Solutions:
89
- Part 1: 512283
9-
- Part 2:
10+
- Part 2: 215827
1011
Notes:
11-
12+
- Part 2: Naive solution, but it still runs instantly.
1213
*/
1314

1415
bool is_ascii(char c)
1516
{
1617
return c >= 0 && c <= 127;
1718
}
1819

19-
size_t hash(std::string_view s)
20+
uint8_t hash(std::string_view s)
2021
{
21-
size_t h = 0;
22+
uint8_t h = 0;
2223
for (char c : s) {
2324
if (!is_ascii(c)) {
2425
throw "hash: not an ASCII-character";
2526
}
26-
h += (uint8_t)c;
27-
h *= 17;
28-
h = h % 256;
27+
// ((h + c) * 17) % 256 <=> ((h + c) % 256 * 17 % 256) % 256 <=> ((h + c) % 256 * 17) % 256
28+
h = (uint8_t)(h + (uint8_t)c);
29+
h = (uint8_t)(h * 17);
2930
}
3031
return h;
3132
}
3233

33-
size_t part_one(const std::vector<std::string>& lines)
34+
int part_one(const std::vector<std::string>& lines)
3435
{
35-
size_t total_hash = 0;
36+
int total_hash = 0;
3637
std::string_view line = lines.at(0);
3738
size_t start_idx = 0;
38-
do {
39+
40+
while (start_idx < line.size()) {
3941
size_t end_idx = line.find(",", start_idx);
4042
if (end_idx == std::string::npos) {
4143
end_idx = line.size();
@@ -44,14 +46,97 @@ size_t part_one(const std::vector<std::string>& lines)
4446
std::string_view word = line.substr(start_idx, end_idx - start_idx);
4547
total_hash += hash(word);
4648
start_idx = end_idx + 1;
47-
} while (start_idx < line.size());
49+
}
4850

4951
return total_hash;
5052
}
5153

52-
size_t part_two(const std::vector<std::string>& lines)
54+
struct Lens {
55+
std::string lbl;
56+
int focal_len;
57+
};
58+
59+
inline bool operator==(const Lens& lens, std::string_view lbl) {
60+
return lens.lbl == lbl;
61+
}
62+
63+
inline bool operator==(std::string_view lbl, const Lens& lens) {
64+
return lens == lbl;
65+
}
66+
67+
struct Box
68+
{
69+
std::vector<Lens> lenses;
70+
uint8_t idx;
71+
72+
void insert_or_update_lens(const std::string& lbl, int focal_len)
73+
{
74+
if (auto lens = std::find(lenses.begin(), lenses.end(), lbl); lens != lenses.end()) {
75+
lens->focal_len = focal_len;
76+
} else {
77+
lenses.push_back(Lens{lbl, focal_len});
78+
}
79+
}
80+
81+
void remove_lens(const std::string& lbl)
82+
{
83+
if (auto lens = std::find(lenses.begin(), lenses.end(), lbl); lens != lenses.end()) {
84+
lenses.erase(lens);
85+
}
86+
}
87+
88+
int calc_focusing_power() const
89+
{
90+
int total = 0, slot_num = 1;
91+
for (const Lens& lens : lenses) {
92+
int focusing_pwr = (idx + 1) * slot_num++ * lens.focal_len;
93+
total += focusing_pwr;
94+
}
95+
return total;
96+
}
97+
};
98+
99+
int part_two(const std::vector<std::string>& lines)
53100
{
54-
return 0;
101+
std::array<Box, 256> boxes;
102+
for (size_t i = 0; i < boxes.size(); ++i) {
103+
boxes.at(i).idx = (uint8_t)i;
104+
}
105+
106+
std::string_view line = lines.at(0);
107+
size_t start_idx = 0;
108+
109+
while (start_idx < line.size()) {
110+
size_t end_idx = line.find(",", start_idx);
111+
if (end_idx == std::string::npos) {
112+
end_idx = line.size();
113+
}
114+
assert(end_idx >= start_idx);
115+
const std::string_view word = line.substr(start_idx, end_idx - start_idx);
116+
117+
size_t cmd_idx = word.find_first_of("-=");
118+
if (cmd_idx == std::string::npos) {
119+
throw "Missing command";
120+
}
121+
const char cmd = word.at(cmd_idx);
122+
123+
const std::string lens_lbl = std::string{word.substr(0, cmd_idx)};
124+
Box &box = boxes.at(hash(lens_lbl));
125+
126+
if (cmd == '-') {
127+
box.remove_lens(lens_lbl);
128+
} else if (cmd == '=') {
129+
const std::string focal_len_str = std::string{word.substr(cmd_idx + 1, word.size())};
130+
int focal_len = aocio::parse_num(focal_len_str);
131+
box.insert_or_update_lens(lens_lbl, focal_len);
132+
} else {
133+
throw "Invalid command";
134+
}
135+
136+
start_idx = end_idx + 1;
137+
}
138+
139+
return std::accumulate(boxes.begin(), boxes.end(), 0, [](int total, const Box& box) {return total + box.calc_focusing_power();});
55140
}
56141

57142
int main()
@@ -65,9 +150,9 @@ int main()
65150
return EXIT_FAILURE;
66151
}
67152
try {
68-
size_t p1 = part_one(lines);
153+
int p1 = part_one(lines);
69154
std::cout << "Part 1: " << p1 << "\n";
70-
size_t p2 = part_two(lines);
155+
int p2 = part_two(lines);
71156
std::cout << "Part 2: " << p2 << "\n";
72157
} catch (const char* err) {
73158
std::cerr << "Error: " << err << "\n";

0 commit comments

Comments
 (0)