Skip to content

Commit 0e0552c

Browse files
committed
2024 day 24: solve part 2
1 parent ce7385c commit 0e0552c

File tree

2 files changed

+422
-35
lines changed

2 files changed

+422
-35
lines changed

2024/src/day24.cpp

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,138 @@
77

88
#include "day24.hpp"
99
#include "lib.hpp"
10+
#include <array> // for array
1011
#include <fstream> // for ifstream
11-
#include <iostream> // for cout
12+
#include <iostream> // for cout, cerr, dec, hex, showbase
1213

1314
int main(int argc, char **argv) {
14-
std::ifstream infile = aoc::parse_args(argc, argv).infile;
15+
auto args = aoc::parse_args(argc, argv);
1516

16-
auto sim = aoc::day24::LogicSim::read(infile);
17-
sim.evaluate();
17+
using namespace aoc::day24;
18+
auto [sim, x, y] = LogicSim::read(args.infile);
19+
sim.evaluate(x, y);
1820

1921
std::cout << sim.z_value() << "\n";
2022

23+
if (args.input_type != aoc::InputType::MAIN) {
24+
return 0;
25+
}
26+
27+
// part 2
28+
// check addition for errors 1 bit at a time
29+
const auto check_addition = [&sim](std::uint64_t x, std::uint64_t y,
30+
bool mark) {
31+
std::uint64_t expected = x + y;
32+
sim.evaluate(x, y);
33+
std::uint64_t z = sim.z_value();
34+
if (z != expected) {
35+
if (mark) {
36+
std::vector<int> bad_bits;
37+
if constexpr (aoc::DEBUG) {
38+
std::cerr << "error in bit ";
39+
}
40+
for (int i = 0; i <= sim.num_bits; ++i) {
41+
if ((z ^ expected) & (1ull << i)) {
42+
bad_bits.push_back(i);
43+
if constexpr (aoc::DEBUG) {
44+
std::cerr << i << ", ";
45+
}
46+
}
47+
}
48+
if constexpr (aoc::DEBUG) {
49+
std::cerr << "calculating " << std::hex << std::showbase
50+
<< x << " + " << y << ": got " << z
51+
<< ", expected " << expected << std::dec << "\n";
52+
}
53+
// mark the first incorrect bit and the bit after that as
54+
// potentially swapped
55+
sim.mark(bad_bits[0], CheckStatus::MAYBE_SWAPPED);
56+
if (bad_bits[0] + 1 <= sim.num_bits) {
57+
sim.mark(bad_bits[0] + 1, CheckStatus::MAYBE_SWAPPED);
58+
}
59+
}
60+
return false;
61+
}
62+
return true;
63+
};
64+
65+
// check entire truth table for the adder for bit i
66+
const auto check_bit = [&sim, &check_addition](int i, bool mark = false) {
67+
if (i >= sim.num_bits) {
68+
// the most-significant bit was tested as the carry out from the
69+
// previous bit
70+
return true;
71+
}
72+
std::vector<std::array<std::uint64_t, 2>> half_adder_inputs = {
73+
{0, 0},
74+
{0, 1ull << i},
75+
{1ull << i, 0},
76+
{1ull << i, 1ull << i},
77+
};
78+
// test each half adder input without and with a carry in, if applicable
79+
std::vector<std::array<std::uint64_t, 2>> carry_inputs{0};
80+
if (i > 0) {
81+
// skip carry in for least-significant bit
82+
carry_inputs.push_back({1ull << (i - 1), 1ull << (i - 1)});
83+
}
84+
85+
std::uint64_t x, y;
86+
for (const auto &carry_input : carry_inputs) {
87+
for (const auto &half_adder_input : half_adder_inputs) {
88+
x = carry_input[0] | half_adder_input[0];
89+
y = carry_input[1] | half_adder_input[1];
90+
if (!check_addition(x, y, mark)) {
91+
return false;
92+
}
93+
}
94+
}
95+
return true;
96+
};
97+
98+
for (int i = 0; i < sim.num_bits; ++i) {
99+
if (!check_bit(i, true)) {
100+
// try swapping all valid pairs of potentially swapped gates
101+
auto swaps = sim.get_swaps();
102+
bool found_swap = false;
103+
for (const auto &swap_hdl : swaps) {
104+
if constexpr (aoc::DEBUG) {
105+
std::cerr << "trying swap: ";
106+
sim.print_swap(std::cerr, swap_hdl);
107+
std::cerr << "\n";
108+
}
109+
sim.swap_outputs(swap_hdl);
110+
bool valid = true;
111+
for (int j = i; j <= i + 2; ++j) {
112+
if (!check_bit(j, false)) {
113+
valid = false;
114+
break;
115+
}
116+
}
117+
if (valid) {
118+
found_swap = true;
119+
break;
120+
} else {
121+
// undo this swap and try the next one
122+
sim.unswap_outputs(swap_hdl);
123+
}
124+
}
125+
if (found_swap) {
126+
if constexpr (aoc::DEBUG) {
127+
std::cerr << "swap successful!\n\n";
128+
}
129+
sim.mark(i, CheckStatus::GOOD);
130+
} else {
131+
assert("no swap found!" && false);
132+
}
133+
// retry the current bit
134+
//--i;
135+
} else {
136+
// mark all inputs as good
137+
sim.mark(i, CheckStatus::GOOD);
138+
}
139+
}
140+
141+
std::cout << sim.format_swapped_gates() << "\n";
142+
21143
return 0;
22144
}

0 commit comments

Comments
 (0)