Add 2021 day 16 puzzles
This commit is contained in:
110
2021/puzzle-16-01.cc
Normal file
110
2021/puzzle-16-01.cc
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using UInt = unsigned long;
|
||||
|
||||
namespace {
|
||||
|
||||
auto bit(std::string const& stream, std::size_t idx) -> UInt
|
||||
{
|
||||
std::string_view vals{"0123456789ABCDEF"};
|
||||
auto val{vals.find(stream[idx / 4])};
|
||||
assert(val != std::string::npos);
|
||||
val = (val >> (3 - (idx % 4))) & 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
auto read_number(std::string const& stream, std::size_t idx, std::size_t length) -> UInt
|
||||
{
|
||||
UInt result{0};
|
||||
while (length-- != 0) {
|
||||
result <<= 1;
|
||||
result |= bit(stream, idx++);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Operator
|
||||
{
|
||||
static auto build(std::string const& stream) -> Operator
|
||||
{
|
||||
auto [result, idx] = build(stream, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto version_sum() const noexcept -> UInt
|
||||
{
|
||||
UInt version{version_};
|
||||
for (auto const& child : children_) {
|
||||
version += child.version_sum();
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
private:
|
||||
static auto build(std::string const& stream, std::size_t idx) -> std::pair<Operator, std::size_t>
|
||||
{
|
||||
UInt version{read_number(stream, idx, 3)};
|
||||
idx += 3;
|
||||
UInt type{read_number(stream, idx, 3)};
|
||||
idx += 3;
|
||||
Operator result{version, type};
|
||||
if (type == 4) {
|
||||
UInt value{0};
|
||||
bool cont{false};
|
||||
do {
|
||||
cont = (bit(stream, idx++) == 1);
|
||||
value <<= 4;
|
||||
value |= read_number(stream, idx, 4);
|
||||
idx += 4;
|
||||
} while (cont);
|
||||
result.value_ = value;
|
||||
}
|
||||
else {
|
||||
bool count_subpackets{bit(stream, idx++) == 1};
|
||||
if (count_subpackets) {
|
||||
UInt count{read_number(stream, idx, 11)};
|
||||
idx += 11;
|
||||
while (count-- != 0) {
|
||||
auto [subpacket, new_idx] = build(stream, idx);
|
||||
result.children_.push_back(subpacket);
|
||||
idx = new_idx;
|
||||
}
|
||||
}
|
||||
else {
|
||||
UInt size{read_number(stream, idx, 15)};
|
||||
idx += 15;
|
||||
auto target_idx{idx + size};
|
||||
while (idx < target_idx) {
|
||||
auto [subpacket, new_idx] = build(stream, idx);
|
||||
result.children_.push_back(subpacket);
|
||||
idx = new_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result, idx};
|
||||
}
|
||||
|
||||
Operator(UInt version, UInt type) : version_(version), type_(type) {}
|
||||
|
||||
UInt version_;
|
||||
UInt type_;
|
||||
UInt value_{0};
|
||||
std::vector<Operator> children_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
auto main() -> int
|
||||
{
|
||||
std::string line;
|
||||
if (!std::getline(std::cin, line)) {
|
||||
std::cerr << "Unable to read line\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto operators{Operator::build(line)};
|
||||
std::cout << "Version sums: " << operators.version_sum() << '\n';
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user