From 0a041cd3984e4ec58eabc1fd51e4b81e5b33f80a Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Wed, 15 Dec 2021 10:20:08 +0000 Subject: [PATCH] Add 2021 day 15 puzzles --- 2021/puzzle-15-01.cc | 81 ++++++++++++++++++++++++++++++++++++ 2021/puzzle-15-02.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 2021/puzzle-15-01.cc create mode 100644 2021/puzzle-15-02.cc diff --git a/2021/puzzle-15-01.cc b/2021/puzzle-15-01.cc new file mode 100644 index 0000000..d6dc444 --- /dev/null +++ b/2021/puzzle-15-01.cc @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +using UInt = unsigned int; + +struct Cost +{ + constexpr explicit Cost(UInt entry_cost) : entry_cost_(entry_cost) {} + + [[nodiscard]] constexpr auto entry_cost() const noexcept -> UInt { return entry_cost_; } + [[nodiscard]] constexpr auto total_cost() const noexcept -> UInt { return total_cost_; } + [[nodiscard]] constexpr auto visited() const noexcept -> bool { return visited_; } + + constexpr void total_cost(UInt total_cost) noexcept { total_cost_ = total_cost; } + constexpr void update_total_cost(UInt v) noexcept + { + total_cost_ = std::min(entry_cost_ + v, total_cost_); + } + constexpr void visit() noexcept { visited_ = true; } + +private: + UInt entry_cost_; + UInt total_cost_{std::numeric_limits::max()}; + bool visited_{false}; +}; + +using CostVector = std::vector; + +auto main() -> int +{ + std::string line; + CostVector costs; + UInt width{0}; + while (std::getline(std::cin, line) && !line.empty()) { + if (width == 0) { + width = line.size(); + } + else { + assert(width == line.size()); + } + for (auto c : line) { + costs.emplace_back(c - '0'); + } + } + + costs[0].total_cost(0); + + while (true) { + /* Note that the comparison below makes deliberate use of unsigned wrap-round. */ + auto it{costs.begin()}; + UInt cost{std::numeric_limits::max()}; + for (auto it2{costs.begin()}; it2 != costs.end(); ++it2) { + if (!it2->visited() && it2->total_cost() < cost) { + cost = it2->total_cost(); + it = it2; + } + } + it->visit(); + auto current_cost{it->total_cost()}; + auto idx{std::distance(costs.begin(), it)}; + if (idx == costs.size() - 1) { + std::cout << "Total cost: " << current_cost; + return 0; + } + if (idx % width != 0) { + costs.at(idx - 1).update_total_cost(current_cost); + } + if ((idx + 1) % width != 0) { + costs.at(idx + 1).update_total_cost(current_cost); + } + if (idx > width) { + costs.at(idx - width).update_total_cost(current_cost); + } + if (idx + width < costs.size()) { + costs.at(idx + width).update_total_cost(current_cost); + } + } +} diff --git a/2021/puzzle-15-02.cc b/2021/puzzle-15-02.cc new file mode 100644 index 0000000..9604a47 --- /dev/null +++ b/2021/puzzle-15-02.cc @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +using UInt = unsigned int; + +struct Cost +{ + constexpr explicit Cost(UInt entry_cost) : entry_cost_(entry_cost) {} + + [[nodiscard]] constexpr auto entry_cost() const noexcept -> UInt { return entry_cost_; } + [[nodiscard]] constexpr auto total_cost() const noexcept -> UInt { return total_cost_; } + [[nodiscard]] constexpr auto visited() const noexcept -> bool { return visited_; } + + constexpr void total_cost(UInt total_cost) noexcept { total_cost_ = total_cost; } + constexpr void update_total_cost(UInt v) noexcept + { + total_cost_ = std::min(entry_cost_ + v, total_cost_); + } + constexpr void visit() noexcept { visited_ = true; } + +private: + UInt entry_cost_; + UInt total_cost_{std::numeric_limits::max()}; + bool visited_{false}; +}; + +using CostVector = std::vector; + +auto main() -> int +{ + std::string line; + CostVector costs; + UInt width{0}; + while (std::getline(std::cin, line) && !line.empty()) { + if (width == 0) { + width = line.size(); + } + else { + assert(width == line.size()); + } + for (unsigned i{0}; i < 5; ++i) { + for (auto c : line) { + UInt cost{c - '0' + i}; + if (cost > 9) { + cost -= 9; + } + costs.emplace_back(cost); + } + } + } + auto initial_size{costs.size()}; + auto target_size{initial_size * 5}; + for (auto i{initial_size}; i < target_size; ++i) { + auto cost{costs[i - initial_size].entry_cost() + 1}; + if (cost > 9) { + cost -= 9; + } + costs.emplace_back(cost); + } + + costs[0].total_cost(0); + width *= 5; + + while (true) { + /* Note that the comparison below makes deliberate use of unsigned wrap-round. */ + auto it{costs.begin()}; + UInt cost{std::numeric_limits::max()}; + for (auto it2{costs.begin()}; it2 != costs.end(); ++it2) { + if (!it2->visited() && it2->total_cost() < cost) { + cost = it2->total_cost(); + it = it2; + } + } + it->visit(); + auto current_cost{it->total_cost()}; + auto idx{std::distance(costs.begin(), it)}; + if (idx == costs.size() - 1) { + std::cout << "Total cost: " << current_cost; + return 0; + } + if (idx % width != 0) { + costs[idx - 1].update_total_cost(current_cost); + } + if ((idx + 1) % width != 0) { + costs[idx + 1].update_total_cost(current_cost); + } + if (idx > width) { + costs[idx - width].update_total_cost(current_cost); + } + if (idx + width < costs.size()) { + costs[idx + width].update_total_cost(current_cost); + } + } +}