Skip to content

Commit ab54306

Browse files
committed
day 24 part 1 in progress
1 parent fb4db3d commit ab54306

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

2024/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ create_standard_test(NAME 2024_day20 SOURCES day20.cpp LIBRARIES aoc2024)
3434
create_standard_test(NAME 2024_day21 SOURCES day21.cpp LIBRARIES aoc2024)
3535
create_standard_test(NAME 2024_day22 SOURCES day22.cpp LIBRARIES aoc2024)
3636
create_standard_test(NAME 2024_day23 SOURCES day23.cpp LIBRARIES aoc2024)
37+
create_standard_test(NAME 2024_day24 SOURCES day24.cpp LIBRARIES aoc2024)
3738

3839
################################################################################
3940
# Copy input data

2024/src/day24.cpp

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
#include <iostream>
2+
#include <filesystem>
3+
#include <fstream>
4+
#include <string>
5+
#include <vector>
6+
#include <benchmark/benchmark.h>
7+
#include <format>
8+
#include <aoc/2024/split.h>
9+
10+
enum Gate {
11+
AND,
12+
OR,
13+
XOR
14+
};
15+
16+
std::string gate_to_string(Gate gate) {
17+
switch(gate) {
18+
case Gate::AND:
19+
return "AND";
20+
case Gate::OR:
21+
return "OR";
22+
case Gate::XOR:
23+
return "XOR";
24+
default:
25+
break;
26+
}
27+
return "unknown";
28+
}
29+
30+
struct Operation {
31+
Gate gate;
32+
std::string arg1;
33+
std::string arg2;
34+
std::string target;
35+
};
36+
37+
struct Data {
38+
std::map<std::string, int> gates;
39+
std::vector<Operation> operations;
40+
};
41+
42+
bool has_both_inputs(const Operation& op, const std::map<std::string, int>& gates) {
43+
return gates.at(op.arg1) != -1 && gates.at(op.arg2) != -1;
44+
}
45+
46+
void put_valid_gates_first(std::vector<Operation>& operations, const std::map<std::string, int>& gates, size_t offset = 0) {
47+
std::sort(operations.begin() + offset, operations.end(), [&](const Operation& a, const Operation& b) {
48+
int valid_args_a = 0;
49+
valid_args_a += gates.at(a.arg1) != -1;
50+
valid_args_a += gates.at(a.arg2) != -1;
51+
int valid_args_b = 0;
52+
valid_args_b += gates.at(b.arg1) != -1;
53+
valid_args_b += gates.at(b.arg2) != -1;
54+
return valid_args_a > valid_args_b;
55+
});
56+
}
57+
58+
int64_t form_number(const std::map<std::string, int>& gates) {
59+
int idx = 0;
60+
int64_t result = 0;
61+
for(auto& [gate, value] : gates) {
62+
if (gate[0] == 'z') {
63+
std::cout << std::format(" {} {}\n", gate, value);
64+
result |= value << idx;
65+
++idx;
66+
}
67+
}
68+
return result;
69+
}
70+
71+
int64_t part1(const Data &data)
72+
{
73+
auto operations = data.operations;
74+
auto gates = data.gates;
75+
76+
for(auto& [gate, value] : gates) {
77+
std::cout << gate << " " << value << std::endl;
78+
}
79+
80+
for(auto& op : operations) {
81+
std::cout << std::format("{} {} {} -> {}\n", op.arg1, gate_to_string(op.gate), op.arg2, op.target);
82+
}
83+
std::cout << std::endl;
84+
85+
put_valid_gates_first(operations, gates);
86+
87+
for(auto& op : operations) {
88+
std::cout << std::format("{} {} {} -> {}\n", op.arg1, gate_to_string(op.gate), op.arg2, op.target);
89+
}
90+
std::cout << std::endl;
91+
92+
for(size_t i = 0; i < operations.size(); ++i) {
93+
auto& op = operations[i];
94+
if (has_both_inputs(op, gates)) {
95+
int arg1 = data.gates.at(op.arg1);
96+
int arg2 = data.gates.at(op.arg2);
97+
int result = 0;
98+
switch(op.gate) {
99+
case Gate::AND:
100+
result = arg1 & arg2;
101+
break;
102+
case Gate::OR:
103+
result = arg1 | arg2;
104+
break;
105+
case Gate::XOR:
106+
result = arg1 ^ arg2;
107+
break;
108+
default:
109+
break;
110+
}
111+
gates[op.target] = result;
112+
}
113+
else {
114+
put_valid_gates_first(operations, gates, i);
115+
// --i;
116+
}
117+
}
118+
for(auto& [gate, value] : gates) {
119+
std::cout << gate << " " << value << std::endl;
120+
}
121+
std::cout << std::endl;
122+
return form_number(gates);
123+
}
124+
125+
int part2(const Data &data)
126+
{
127+
return 0;
128+
}
129+
130+
Data parse()
131+
{
132+
std::ifstream file(std::filesystem::path("inputs/day24.txt"));
133+
if (!file.is_open())
134+
{
135+
throw std::runtime_error("file not found");
136+
}
137+
std::string line;
138+
Data data;
139+
140+
bool gates = false;
141+
while (std::getline(file, line))
142+
{
143+
if (line.empty())
144+
{
145+
gates = true;
146+
continue;
147+
}
148+
if (!gates)
149+
{
150+
auto parts = split(line, ": ");
151+
data.gates[parts[0]] = std::stoi(parts[1]);
152+
}
153+
else
154+
{
155+
auto parts = split(line, " ");
156+
Operation op;
157+
op.arg1 = parts[0];
158+
op.arg2 = parts[2];
159+
op.target = parts[4];
160+
if (parts[1] == "AND")
161+
{
162+
op.gate = Gate::AND;
163+
}
164+
else if (parts[1] == "OR")
165+
{
166+
op.gate = Gate::OR;
167+
}
168+
else if (parts[1] == "XOR")
169+
{
170+
op.gate = Gate::XOR;
171+
}
172+
else
173+
{
174+
throw std::runtime_error("invalid gate");
175+
}
176+
if(data.gates.find(op.arg1) == data.gates.end()) {
177+
data.gates[op.arg1] = -1;
178+
}
179+
if(data.gates.find(op.arg2) == data.gates.end()) {
180+
data.gates[op.arg2] = -1;
181+
}
182+
if(data.gates.find(op.target) == data.gates.end()) {
183+
data.gates[op.target] = -1;
184+
}
185+
data.operations.push_back(op);
186+
}
187+
}
188+
189+
return data;
190+
}
191+
192+
class BenchmarkFixture : public benchmark::Fixture
193+
{
194+
public:
195+
static Data data;
196+
};
197+
198+
Data BenchmarkFixture::data = parse();
199+
200+
BENCHMARK_DEFINE_F(BenchmarkFixture, Part1Benchmark)
201+
(benchmark::State &state)
202+
{
203+
for (auto _ : state)
204+
{
205+
auto s = part1(data);
206+
benchmark::DoNotOptimize(s);
207+
}
208+
}
209+
210+
BENCHMARK_DEFINE_F(BenchmarkFixture, Part2Benchmark)
211+
(benchmark::State &state)
212+
{
213+
for (auto _ : state)
214+
{
215+
auto s = part2(data);
216+
benchmark::DoNotOptimize(s);
217+
}
218+
}
219+
220+
BENCHMARK_REGISTER_F(BenchmarkFixture, Part1Benchmark)->Unit(benchmark::kMillisecond);
221+
BENCHMARK_REGISTER_F(BenchmarkFixture, Part2Benchmark)->Unit(benchmark::kMillisecond);
222+
223+
int main(int argc, char **argv)
224+
{
225+
Data data = parse();
226+
227+
int64_t answer1 = 0;
228+
int64_t answer2 = 0;
229+
230+
auto first = part1(data);
231+
std::cout << "Part 1: " << first << std::endl;
232+
233+
auto second = part2(data);
234+
std::cout << "Part 2: " << second << std::endl;
235+
236+
first != answer1 ? throw std::runtime_error("Part 1 incorrect") : nullptr;
237+
second != answer2 ? throw std::runtime_error("Part 2 incorrect") : nullptr;
238+
239+
for (int i = 1; i < argc; ++i) {
240+
if (std::string(argv[i]) == "--benchmark") {
241+
benchmark::Initialize(&argc, argv);
242+
benchmark::RunSpecifiedBenchmarks();
243+
return 0;
244+
}
245+
}
246+
}

0 commit comments

Comments
 (0)