From 9e23269d53b1e2e3c5c7eecbd7c785820d4b90ff Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Sat, 18 Dec 2021 16:29:46 +0000 Subject: [PATCH] Add 2021 day 18 puzzles --- 2021/puzzle-18-01.cc | 170 +++++++++++++++++++++++++++++++++++++++ 2021/puzzle-18-02.cc | 186 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 356 insertions(+) create mode 100644 2021/puzzle-18-01.cc create mode 100644 2021/puzzle-18-02.cc diff --git a/2021/puzzle-18-01.cc b/2021/puzzle-18-01.cc new file mode 100644 index 0000000..1601de4 --- /dev/null +++ b/2021/puzzle-18-01.cc @@ -0,0 +1,170 @@ +#include +#include +#include + +using UInt = unsigned long; + +struct Item +{ + UInt value_; + unsigned depth_; +}; +using Items = std::vector; + +auto print1(Items::const_iterator begin, Items::const_iterator end, unsigned current_depth) + -> Items::const_iterator +{ + if (begin == end) { + return begin; + } + + if (begin->depth_ == current_depth) { + std::cout << begin->value_; + ++begin; + return begin; + } + + std::cout << '['; + begin = print1(begin, end, current_depth + 1); + std::cout << ','; + begin = print1(begin, end, current_depth + 1); + std::cout << ']'; + return begin; +} + +void print(std::vector const& items) +{ + print1(items.begin(), items.end(), 0); + std::cout << '\n'; +} + +void reduce(std::vector& items) +{ + /* We do all the explosions followed by all the splits until done. */ + std::size_t size{0}; + while (size != items.size()) { + auto it{items.begin()}; + /* Iterate over everything doing as many explosions as we can. */ + while (it != items.end()) { + /* Explode */ + if (it->depth_ > 4) { + assert(it->depth_ == 5); + assert((it + 1)->depth_ == 5); + if (it != items.begin()) { + (it - 1)->value_ += it->value_; + } + if (it + 2 != items.end()) { + (it + 2)->value_ += (it + 1)->value_; + } + it->value_ = 0; + it->depth_ -= 1; + ++it; + it = items.erase(it); + } + else { + ++it; + } + } + + /* Note the size of items here - we only need to go around again if splitting increases the + * size. */ + size = items.size(); + + /* Ok we've had no explosions so lets try to do a split. */ + it = items.begin(); + while (it != items.end()) { + if (it->value_ > 9) { + auto value{it->value_}; + auto depth{it->depth_ + 1}; + it = items.insert(it, {value / 2, depth}); + value -= it->value_; + ++it; + it->value_ = value; + it->depth_ = depth; + /* For this one we need to go back round the loop completely. */ + it = items.end(); + } + else { + ++it; + } + } + } +} + +void append(Items& items, std::string const& str) +{ + unsigned current_depth{0}; + for (auto c : str) { + switch (c) { + case '[': + ++current_depth; + break; + case ']': + assert(current_depth != 0); + --current_depth; + break; + case ',': + continue; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + items.push_back({static_cast(c - '0'), current_depth}); + break; + default: + std::cerr << "Can't interpret " << c << '\n'; + std::exit(1); + } + } +} + +auto magnitude1(Items::const_iterator begin, Items::const_iterator end, unsigned current_depth) + -> std::pair +{ + if (begin == end) { + return {end, 0}; + } + + if (begin->depth_ == current_depth) { + auto value = begin->value_; + ++begin; + return {begin, value}; + } + + auto [lhs_it, lhs] = magnitude1(begin, end, current_depth + 1); + auto [rhs_it, rhs] = magnitude1(lhs_it, end, current_depth + 1); + return {rhs_it, 3 * lhs + 2 * rhs}; +} + +auto magnitude(Items const& items) -> UInt +{ + return magnitude1(items.begin(), items.end(), 0).second; +} + +auto main() -> int +{ + std::string line; + std::vector items; + if (!std::getline(std::cin, line)) { + std::cout << "Unable to read first line."; + } + append(items, line); + while (std::getline(std::cin, line) && !line.empty()) { + append(items, line); + + /* Deepen everything one. */ + for (auto& item : items) { + ++(item.depth_); + } + + reduce(items); + } + + std::cout << "Magnitude: " << magnitude(items) << '\n'; +} diff --git a/2021/puzzle-18-02.cc b/2021/puzzle-18-02.cc new file mode 100644 index 0000000..2ab0c9d --- /dev/null +++ b/2021/puzzle-18-02.cc @@ -0,0 +1,186 @@ +#include +#include +#include + +using UInt = unsigned long; + +struct Item +{ + UInt value_; + unsigned depth_; +}; +using Items = std::vector; + +auto print1(Items::const_iterator begin, Items::const_iterator end, unsigned current_depth) + -> Items::const_iterator +{ + if (begin == end) { + return begin; + } + + if (begin->depth_ == current_depth) { + std::cout << begin->value_; + ++begin; + return begin; + } + + std::cout << '['; + begin = print1(begin, end, current_depth + 1); + std::cout << ','; + begin = print1(begin, end, current_depth + 1); + std::cout << ']'; + return begin; +} + +void print(std::vector const& items) +{ + print1(items.begin(), items.end(), 0); + std::cout << '\n'; +} + +void reduce(std::vector& items) +{ + /* We do all the explosions followed by all the splits until done. */ + std::size_t size{0}; + while (size != items.size()) { + auto it{items.begin()}; + /* Iterate over everything doing as many explosions as we can. */ + while (it != items.end()) { + /* Explode */ + if (it->depth_ > 4) { + assert(it->depth_ == 5); + assert((it + 1)->depth_ == 5); + if (it != items.begin()) { + (it - 1)->value_ += it->value_; + } + if (it + 2 != items.end()) { + (it + 2)->value_ += (it + 1)->value_; + } + it->value_ = 0; + it->depth_ -= 1; + ++it; + it = items.erase(it); + } + else { + ++it; + } + } + + /* Note the size of items here - we only need to go around again if splitting increases the + * size. */ + size = items.size(); + + /* Ok we've had no explosions so lets try to do a split. */ + it = items.begin(); + while (it != items.end()) { + if (it->value_ > 9) { + auto value{it->value_}; + auto depth{it->depth_ + 1}; + it = items.insert(it, {value / 2, depth}); + value -= it->value_; + ++it; + it->value_ = value; + it->depth_ = depth; + /* For this one we need to go back round the loop completely. */ + it = items.end(); + } + else { + ++it; + } + } + } +} + +void append(Items& items, std::string const& str) +{ + unsigned current_depth{0}; + for (auto c : str) { + switch (c) { + case '[': + ++current_depth; + break; + case ']': + assert(current_depth != 0); + --current_depth; + break; + case ',': + continue; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + items.push_back({static_cast(c - '0'), current_depth}); + break; + default: + std::cerr << "Can't interpret " << c << '\n'; + std::exit(1); + } + } +} + +auto magnitude1(Items::const_iterator begin, Items::const_iterator end, unsigned current_depth) + -> std::pair +{ + if (begin == end) { + return {end, 0}; + } + + if (begin->depth_ == current_depth) { + auto value = begin->value_; + ++begin; + return {begin, value}; + } + + auto [lhs_it, lhs] = magnitude1(begin, end, current_depth + 1); + auto [rhs_it, rhs] = magnitude1(lhs_it, end, current_depth + 1); + return {rhs_it, 3 * lhs + 2 * rhs}; +} + +auto magnitude(Items const& items) -> UInt +{ + return magnitude1(items.begin(), items.end(), 0).second; +} + +auto add(Items const& lhs, Items const& rhs) +{ + Items result; + auto inserter{std::back_inserter(result)}; + std::transform(lhs.begin(), lhs.end(), inserter, [](Item const& item) { + return Item{item.value_, item.depth_ + 1}; + }); + std::transform(rhs.begin(), rhs.end(), inserter, [](Item const& item) { + return Item{item.value_, item.depth_ + 1}; + }); + reduce(result); + return result; +} + +auto main() -> int +{ + std::string line; + std::vector item_list; + while (std::getline(std::cin, line) && !line.empty()) { + Items items; + append(items, line); + item_list.push_back(items); + } + + UInt max_magnitude{0}; + for (auto const& lhs : item_list) { + for (auto const& rhs : item_list) { + auto result{add(lhs, rhs)}; + auto mag{magnitude(result)}; + if (mag > max_magnitude) { + max_magnitude = mag; + } + } + } + + std::cout << "Max Magnitude: " << max_magnitude << '\n'; +}