Skip to content

Commit 14773d8

Browse files
committed
Solve first part of day 18 from AoC 2018.
1 parent 68168c2 commit 14773d8

File tree

6 files changed

+215
-5
lines changed

6 files changed

+215
-5
lines changed

2018/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ buildifier: $(BUILD_FILES)
1717
buildifier $^
1818

1919
buildifier-check: $(BUILD_FILES)
20-
buildifier -lint $^
20+
buildifier -mode check $^
2121

2222
clang-format: $(CPP_FILES)
2323
clang-format -i $^

2018/aoc18/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ cc_library(
235235
srcs = ["day16.cc"],
236236
hdrs = ["day16.h"],
237237
deps = [
238+
"@com_google_absl//absl/strings",
238239
],
239240
)
240241

2018/aoc18/day16.cc

+131-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,135 @@
11
#include "aoc18/day16.h"
22

3+
#include <algorithm>
4+
#include <string>
5+
#include <vector>
6+
7+
#include "absl/strings/numbers.h"
8+
#include "absl/strings/str_split.h"
9+
310
namespace aoc18 {
4-
namespace day16 {} // namespace day16
11+
namespace day16 {
12+
13+
using Opcode = std::function<Registers(Registers, int, int, int)>;
14+
Registers AddR(Registers r, int a, int b, int c) { r[c] = r[a] + r[b]; return r; }
15+
Registers AddI(Registers r, int a, int b, int c) { r[c] = r[a] + b; return r; }
16+
Registers MulR(Registers r, int a, int b, int c) { r[c] = r[a] * r[b]; return r; }
17+
Registers MulI(Registers r, int a, int b, int c) { r[c] = r[a] * b; return r; }
18+
Registers BanR(Registers r, int a, int b, int c) { r[c] = r[a] & r[b]; return r; }
19+
Registers BanI(Registers r, int a, int b, int c) { r[c] = r[a] & b; return r; }
20+
Registers BorR(Registers r, int a, int b, int c) { r[c] = r[a] | r[b]; return r; }
21+
Registers BorI(Registers r, int a, int b, int c) { r[c] = r[a] | b; return r; }
22+
Registers SetR(Registers r, int a, int _, int c) { r[c] = r[a] ; return r; }
23+
Registers SetI(Registers r, int a, int _, int c) { r[c] = a ; return r; }
24+
Registers GtIR(Registers r, int a, int b, int c) { r[c] = a > r[b]; return r; }
25+
Registers GtRI(Registers r, int a, int b, int c) { r[c] = r[a] > b; return r; }
26+
Registers GtRR(Registers r, int a, int b, int c) { r[c] = r[a] > r[b]; return r; }
27+
Registers EqIR(Registers r, int a, int b, int c) { r[c] = a == r[b]; return r; }
28+
Registers EqRI(Registers r, int a, int b, int c) { r[c] = r[a] == b; return r; }
29+
Registers EqRR(Registers r, int a, int b, int c) { r[c] = r[a] == r[b]; return r; }
30+
31+
32+
std::optional<Registers> ParseRegisters(const std::string& line) {
33+
static const std::regex re(R"(^\w+:\s+\[(\d+), (\d+), (\d+), (\d+)\]$)");
34+
std::smatch match;
35+
if (!std::regex_match(line, match, re)) {
36+
return std::nullopt;
37+
}
38+
if (match.size() != 5) {
39+
return std::nullopt;
40+
}
41+
Registers reg;
42+
if (!absl::SimpleAtoi(match[1].str(), &reg[0])) { return std::nullopt; }
43+
if (!absl::SimpleAtoi(match[2].str(), &reg[1])) { return std::nullopt; }
44+
if (!absl::SimpleAtoi(match[3].str(), &reg[2])) { return std::nullopt; }
45+
if (!absl::SimpleAtoi(match[4].str(), &reg[3])) { return std::nullopt; }
46+
return reg;
47+
}
48+
49+
std::optional<Instruction> ParseInstruction(const std::string& line) {
50+
const std::vector<absl::string_view> parts = absl::StrSplit(line, ' ');
51+
if (parts.size() != 4) {
52+
return std::nullopt;
53+
}
54+
Instruction ins;
55+
if (!absl::SimpleAtoi(parts[0], &ins.code)) { return std::nullopt; }
56+
if (!absl::SimpleAtoi(parts[1], &ins.a)) { return std::nullopt; }
57+
if (!absl::SimpleAtoi(parts[2], &ins.b)) { return std::nullopt; }
58+
if (!absl::SimpleAtoi(parts[3], &ins.c)) { return std::nullopt; }
59+
return ins;
60+
}
61+
62+
std::optional<std::vector<Sample>> ParseSamples(const std::vector<std::string>& lines) {
63+
std::vector<Sample> samples;
64+
int idx{0};
65+
while (idx < lines.size()) {
66+
if (lines[idx][0] != 'B') {
67+
// This means we're done parsing the section of the input that deals with
68+
// samples.
69+
break;
70+
}
71+
const auto maybe_before = ParseRegisters(lines[idx]);
72+
if (!maybe_before.has_value()) {
73+
return std::nullopt;
74+
}
75+
const auto maybe_instruction = ParseInstruction(lines[idx + 1]);
76+
if (!maybe_before.has_value()) {
77+
return std::nullopt;
78+
}
79+
const auto maybe_after = ParseRegisters(lines[idx + 2]);
80+
if (!maybe_after.has_value()) {
81+
return std::nullopt;
82+
}
83+
samples.emplace_back(Sample{
84+
.before = maybe_before.value(),
85+
.after = maybe_after.value(),
86+
.instruction = maybe_instruction.value()
87+
});
88+
idx += 4;
89+
}
90+
return samples;
91+
}
92+
93+
int CountPotentialOpcodes(const Sample& sample) {
94+
static const std::vector<Opcode> ops{
95+
AddR,
96+
AddI,
97+
MulR,
98+
MulI,
99+
BanR,
100+
BanI,
101+
BorR,
102+
BorI,
103+
SetR,
104+
SetI,
105+
GtIR,
106+
GtRI,
107+
GtRR,
108+
EqIR,
109+
EqRI,
110+
EqRR
111+
};
112+
return std::count_if(
113+
ops.begin(),
114+
ops.end(),
115+
[&sample](const Opcode& op) {
116+
return op(
117+
sample.before,
118+
sample.instruction.a,
119+
sample.instruction.b,
120+
sample.instruction.c
121+
) == sample.after;
122+
}
123+
);
124+
}
125+
126+
int Part1(const std::vector<Sample>& samples) {
127+
return std::count_if(
128+
samples.begin(),
129+
samples.end(),
130+
[](const Sample& s) { return CountPotentialOpcodes(s) >= 3; }
131+
);
132+
}
133+
134+
} // namespace day16
5135
} // namespace aoc18

2018/aoc18/day16.h

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,37 @@
11
#ifndef AOC18_DAY16_H_
22
#define AOC18_DAY16_H_
33

4+
#include <array>
5+
#include <functional>
6+
#include <memory>
7+
#include <optional>
8+
#include <regex>
9+
#include <string>
10+
#include <vector>
11+
412
namespace aoc18 {
5-
namespace day16 {} // namespace day16
13+
namespace day16 {
14+
15+
using Registers = std::array<int, 4>;
16+
17+
struct Instruction {
18+
int code;
19+
int a;
20+
int b;
21+
int c;
22+
};
23+
24+
struct Sample {
25+
Registers before;
26+
Registers after;
27+
Instruction instruction;
28+
};
29+
30+
std::optional<std::vector<Sample>> ParseSamples(const std::vector<std::string>& lines);
31+
32+
int Part1(const std::vector<Sample>& samples);
33+
34+
} // namespace day16
635
} // namespace aoc18
736

837
#endif // AOC18_DAY16_H_

2018/aoc18/day16_main.cc

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
#include "aoc18/day16.h"
22

3-
int main(int argc, char* argv[]) {}
3+
#include <iostream>
4+
#include <string>
5+
#include <vector>
6+
7+
int main(int argc, char* argv[]) {
8+
std::vector<std::string> lines;
9+
std::string line;
10+
while (std::getline(std::cin, line)) {
11+
lines.push_back(line);
12+
}
13+
14+
const auto maybe_samples = aoc18::day16::ParseSamples(lines);
15+
if (!maybe_samples.has_value()) {
16+
std::cerr << "unable to parse samples" << std::endl;
17+
return 1;
18+
}
19+
std::cout << "Part 1: " << aoc18::day16::Part1(maybe_samples.value()) << std::endl;
20+
}

2018/aoc18/day16_test.cc

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,40 @@
11
#include "aoc18/day16.h"
22

3+
#include <array>
4+
35
#include "gtest/gtest.h"
46

5-
TEST(Part1, WorksForExample) {}
7+
static const std::vector<std::string> kExampleLines{
8+
"Before: [3, 2, 1, 1]",
9+
"9 2 1 2",
10+
"After: [3, 2, 2, 1]",
11+
"This is something else"
12+
};
13+
14+
TEST(Part1, CanParseSample) {
15+
const auto maybe_samples = aoc18::day16::ParseSamples(kExampleLines);
16+
EXPECT_TRUE(maybe_samples.has_value());
17+
EXPECT_EQ(1, maybe_samples.value().size());
18+
19+
const aoc18::day16::Sample& sample = maybe_samples.value()[0];
20+
21+
aoc18::day16::Registers expected_before{3, 2, 1, 1};
22+
EXPECT_EQ(expected_before, sample.before);
23+
24+
aoc18::day16::Instruction expected_instruction{9, 2, 1, 2};
25+
EXPECT_EQ(expected_instruction.code, sample.instruction.code);
26+
EXPECT_EQ(expected_instruction.a, sample.instruction.a);
27+
EXPECT_EQ(expected_instruction.b, sample.instruction.b);
28+
EXPECT_EQ(expected_instruction.c, sample.instruction.c);
29+
30+
aoc18::day16::Registers expected_after{3, 2, 2, 1};
31+
EXPECT_EQ(expected_after, sample.after);
32+
}
33+
34+
TEST(Part1, WorksForExample) {
35+
const auto maybe_samples = aoc18::day16::ParseSamples(kExampleLines);
36+
ASSERT_TRUE(maybe_samples.has_value());
37+
EXPECT_EQ(1, aoc18::day16::Part1(maybe_samples.value()));
38+
}
639

740
TEST(Part2, WorksForExample) {}

0 commit comments

Comments
 (0)