From 239e12e89d4fedcb1a949aeeaaad7204feab5fdf Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Sun, 17 Dec 2023 11:00:47 +0000 Subject: [PATCH] 2023 Day 17 --- 2023/puzzle-17-01.cc | 179 +++++++++++++++++++++++++++++++++++++++++++ 2023/puzzle-17-02.cc | 176 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 2023/puzzle-17-01.cc create mode 100644 2023/puzzle-17-02.cc diff --git a/2023/puzzle-17-01.cc b/2023/puzzle-17-01.cc new file mode 100644 index 0000000..622253f --- /dev/null +++ b/2023/puzzle-17-01.cc @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using Int = std::int64_t; +using UInt = std::uint64_t; + +enum class Dir { horiz, vert }; + +struct Location +{ + Location(UInt const x, UInt const y, Dir const dir) noexcept + : x_(x), y_(y), dir_(dir) + { + } + + [[nodiscard]] auto x() const noexcept -> UInt { return x_; } + [[nodiscard]] auto y() const noexcept -> UInt { return y_; } + [[nodiscard]] auto dir() const noexcept -> Dir { return dir_; } + + [[nodiscard]] auto operator<=>(Location const& rhs) const noexcept -> std::strong_ordering + { + if (x_ < rhs.x_) { return std::strong_ordering::less; } + if (x_ == rhs.x_ && y_ < rhs.y_) { return std::strong_ordering::less; } + if (x_ == rhs.x_ && y_ == rhs.y_ && dir_ == rhs.dir_) { return std::strong_ordering::equal; } + if (x_ == rhs.x_ && y_ == rhs.y_ && dir_ == Dir::horiz) { return std::strong_ordering::less; } + return std::strong_ordering::greater; + } + +private: + UInt x_; + UInt y_; + Dir dir_; +}; + +auto operator<<(std::ostream& os, Location const& loc) -> std::ostream& +{ + return os << '(' << loc.x() << ", " << loc.y() << ", " << (loc.dir() == Dir::horiz ? '-' : '|') << + ')'; +} + +struct Grid +{ + void push_line(std::string const& line) { grid_.push_back(line); } + + [[nodiscard]] auto find_route() -> UInt + { + reset_state(); + add_location(Location{0, 0, Dir::horiz}, 0); + add_location(Location{0, 0, Dir::vert}, 0); + + while (!work_list_.empty()) { + auto it = work_list_.begin(); + std::cout << it->first << ": "; + for (auto const& loc : it->second) { + if (visited(loc)) { continue; } + + std::cout << loc << ", "; + visit(loc); + + if (loc.x() == grid_[loc.y()].size() - 1 && loc.y() == grid_.size() - 1) { + // Reached the end return the cost. + std::cout << '\n'; + return it->first; + } + + if (loc.dir() == Dir::horiz) { add_vert_locations(loc.x(), loc.y(), it->first); } + else { add_horiz_locations(loc.x(), loc.y(), it->first); } + } + work_list_.erase(it); + std::cout << "\n"; + } + + std::abort(); + } + +private: + void reset_state() + { + horiz_visited_.clear(); + vert_visited_.clear(); + work_list_.clear(); + + horiz_visited_.resize(grid_.size() * grid_[0].size(), false); + vert_visited_.resize(grid_.size() * grid_[0].size(), false); + } + + [[nodiscard]] auto visited(Location const& loc) const noexcept -> bool + { + if (loc.dir() == Dir::horiz) { + return horiz_visited_[loc.x() * grid_.size() + loc.y()]; + } + + return vert_visited_[loc.x() * grid_.size() + loc.y()]; + } + + void visit(Location const& loc) noexcept + { + if (loc.dir() == Dir::horiz) { + horiz_visited_[loc.x() * grid_.size() + loc.y()] = true; + } + else { + vert_visited_[loc.x() * grid_.size() + loc.y()] = true; + } + } + + void add_location(Location const& loc, UInt cost) + { + if (visited(loc)) { return; } + if (!work_list_.empty() && work_list_.begin()->first > cost) { std::abort(); } + auto [it, success] = work_list_.insert({cost, std::vector{}}); + it->second.push_back(loc); + } + + void add_horiz_locations(UInt const x, UInt const y, UInt const cost) + { + UInt dcost{0}; + for (UInt dx = 1; dx < 4; ++dx) { + if (x < dx) { break; } + dcost += grid_cost(x - dx, y); + add_location(Location(x - dx, y, Dir::horiz), cost + dcost); + } + + dcost = 0; + for (UInt dx = 1; dx < 4; ++dx) { + if (x + dx >= grid_[y].size()) { break; } + dcost += grid_cost(x + dx, y); + add_location(Location(x + dx, y, Dir::horiz), cost + dcost); + } + } + + void add_vert_locations(UInt const x, UInt const y, UInt const cost) + { + for (UInt dcost{0}, dy{1}; dy < 4; ++dy) { + if (y < dy) { break; } + dcost += grid_cost(x, y - dy); + add_location(Location(x, y - dy, Dir::vert), cost + dcost); + } + + for (UInt dcost{0}, dy{1}; dy < 4; ++dy) { + if (y + dy >= grid_.size()) { break; } + dcost += grid_cost(x, y + dy); + add_location(Location(x, y + dy, Dir::vert), cost + dcost); + } + } + + [[nodiscard]] auto grid_cost(UInt x, UInt y) const noexcept -> UInt + { + return grid_[y][x] - '0'; + } + + std::vector grid_; + std::vector horiz_visited_; + std::vector vert_visited_; + std::map> work_list_; +}; + +auto main() -> int try { + std::string line; + Grid grid; + + while (std::getline(std::cin, line)) { + grid.push_line(line); + } + + UInt const cost = grid.find_route(); + std::cout << "Total: " << cost << '\n'; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +} diff --git a/2023/puzzle-17-02.cc b/2023/puzzle-17-02.cc new file mode 100644 index 0000000..db35a87 --- /dev/null +++ b/2023/puzzle-17-02.cc @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include + +using Int = std::int64_t; +using UInt = std::uint64_t; + +enum class Dir { horiz, vert }; + +constexpr UInt dir_min{4}; +constexpr UInt dir_max{11}; + +struct Location +{ + Location(UInt const x, UInt const y, Dir const dir) noexcept + : x_(x), y_(y), dir_(dir) + { + } + + [[nodiscard]] auto x() const noexcept -> UInt { return x_; } + [[nodiscard]] auto y() const noexcept -> UInt { return y_; } + [[nodiscard]] auto dir() const noexcept -> Dir { return dir_; } + +private: + UInt x_; + UInt y_; + Dir dir_; +}; + +auto operator<<(std::ostream& os, Location const& loc) -> std::ostream& +{ + return os << '(' << loc.x() << ", " << loc.y() << ", " << (loc.dir() == Dir::horiz ? '-' : '|') << + ')'; +} + +struct Grid +{ + void push_line(std::string const& line) { grid_.push_back(line); } + + [[nodiscard]] auto find_route() -> UInt + { + reset_state(); + add_location(Location{0, 0, Dir::horiz}, 0); + add_location(Location{0, 0, Dir::vert}, 0); + + while (!work_list_.empty()) { + auto it = work_list_.begin(); + std::cout << it->first << ": "; + for (auto const& loc : it->second) { + if (visited(loc)) { continue; } + + std::cout << loc << ", "; + visit(loc); + + if (loc.x() == grid_[loc.y()].size() - 1 && loc.y() == grid_.size() - 1) { + // Reached the end return the cost. + std::cout << '\n'; + return it->first; + } + + if (loc.dir() == Dir::horiz) { add_vert_locations(loc.x(), loc.y(), it->first); } + else { add_horiz_locations(loc.x(), loc.y(), it->first); } + } + work_list_.erase(it); + std::cout << "\n"; + } + + std::abort(); + } + +private: + void reset_state() + { + horiz_visited_.clear(); + vert_visited_.clear(); + work_list_.clear(); + + horiz_visited_.resize(grid_.size() * grid_[0].size(), false); + vert_visited_.resize(grid_.size() * grid_[0].size(), false); + } + + [[nodiscard]] auto visited(Location const& loc) const noexcept -> bool + { + if (loc.dir() == Dir::horiz) { + return horiz_visited_[loc.x() * grid_.size() + loc.y()]; + } + + return vert_visited_[loc.x() * grid_.size() + loc.y()]; + } + + void visit(Location const& loc) noexcept + { + if (loc.dir() == Dir::horiz) { + horiz_visited_[loc.x() * grid_.size() + loc.y()] = true; + } + else { + vert_visited_[loc.x() * grid_.size() + loc.y()] = true; + } + } + + void add_location(Location const& loc, UInt cost) + { + if (visited(loc)) { return; } + auto [it, success] = work_list_.insert({cost, std::vector{}}); + it->second.push_back(loc); + } + + void add_horiz_locations(UInt const x, UInt const y, UInt const cost) + { + for (UInt dcost{0}, dx{1}; dx < dir_max; ++dx) { + if (x < dx) { break; } + dcost += grid_cost(x - dx, y); + if (dx >= dir_min) { + add_location(Location(x - dx, y, Dir::horiz), cost + dcost); + } + } + + for (UInt dcost{0}, dx{1}; dx < dir_max; ++dx) { + if (x + dx >= grid_[y].size()) { break; } + dcost += grid_cost(x + dx, y); + if (dx >= dir_min) { + add_location(Location(x + dx, y, Dir::horiz), cost + dcost); + } + } + } + + void add_vert_locations(UInt const x, UInt const y, UInt const cost) + { + for (UInt dcost{0}, dy{1}; dy < dir_max; ++dy) { + if (y < dy) { break; } + dcost += grid_cost(x, y - dy); + if (dy >= dir_min) { + add_location(Location(x, y - dy, Dir::vert), cost + dcost); + } + } + + for (UInt dcost{0}, dy{1}; dy < dir_max; ++dy) { + if (y + dy >= grid_.size()) { break; } + dcost += grid_cost(x, y + dy); + if (dy >= dir_min) { + add_location(Location(x, y + dy, Dir::vert), cost + dcost); + } + } + } + + [[nodiscard]] auto grid_cost(UInt const x, UInt const y) const noexcept -> UInt + { + return grid_[y][x] - '0'; + } + + std::vector grid_; + std::vector horiz_visited_; + std::vector vert_visited_; + std::map> work_list_; +}; + +auto main() -> int try { + std::string line; + Grid grid; + + while (std::getline(std::cin, line)) { + grid.push_line(line); + } + + UInt const cost = grid.find_route(); + std::cout << "Total: " << cost << '\n'; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +}