From 96f39f019e7387bf97c08d336150b4e9438da1fe Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Wed, 14 Dec 2022 08:59:32 +0000 Subject: [PATCH] Add Puzzles for 2022 day 14 --- 2022/position.h | 60 ++++++++++++++++ 2022/puzzle-14-01.cc | 147 +++++++++++++++++++++++++++++++++++++++ 2022/puzzle-14-02.cc | 161 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 368 insertions(+) create mode 100644 2022/position.h create mode 100644 2022/puzzle-14-01.cc create mode 100644 2022/puzzle-14-02.cc diff --git a/2022/position.h b/2022/position.h new file mode 100644 index 0000000..301bb53 --- /dev/null +++ b/2022/position.h @@ -0,0 +1,60 @@ +// +// Created by Matthew Gretton-Dann on 14/12/2022. +// + +#ifndef ADVENT_OF_CODE_POSITION_H +#define ADVENT_OF_CODE_POSITION_H + +#include + +template +struct Pos +{ + constexpr Pos() noexcept = default; + constexpr Pos(Int x, Int y) noexcept : x_(x), y_(y) {} + constexpr Pos(Pos const&) noexcept = default; + auto constexpr operator=(Pos const&) noexcept -> Pos& = default; + constexpr Pos(Pos&&) noexcept = default; + auto constexpr operator=(Pos&&) noexcept -> Pos& = default; + constexpr ~Pos() noexcept = default; + + [[nodiscard]] auto constexpr x() const noexcept -> Int { return x_; } + auto constexpr x(Int x) noexcept { x_ = x; } + [[nodiscard]] auto constexpr y() const noexcept -> Int { return y_; } + auto constexpr y(Int y) noexcept { y_ = y; } + + auto constexpr operator+=(Pos const& r) noexcept -> Pos& + { + x_ += r.x_; + y_ += r.y_; + return *this; + } + + auto constexpr operator<=>(Pos const& r) const noexcept -> std::strong_ordering + { + auto result{y_ <=> r.y_}; + if (result == std::strong_ordering::equal) { + result = x_ <=> r.x_; + } + return result; + } + + auto constexpr operator==(Pos const& r) const noexcept -> bool + { + return x_ == r.x_ && y_ == r.y_; + } + +private: + Int x_{0}; + Int y_{0}; +}; + +template +auto operator+(Pos const& x, Pos const& y) noexcept -> Pos +{ + auto z{x}; + z += y; + return y; +} + +#endif // ADVENT_OF_CODE_POSITION_H diff --git a/2022/puzzle-14-01.cc b/2022/puzzle-14-01.cc new file mode 100644 index 0000000..a698d51 --- /dev/null +++ b/2022/puzzle-14-01.cc @@ -0,0 +1,147 @@ +// +// Created by Matthew Gretton-Dann on 09/12/2022. +// + +#include +#include +#include +#include +#include + +#include "position.h" + +using Int = std::int64_t; +using UInt = std::uint64_t; + +auto direction(auto x) -> decltype(x) +{ + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +struct Map +{ + static constexpr char gap_ = '.'; + static constexpr char wall_ = '#'; + static constexpr char sand_ = 'o'; + static constexpr Pos sand_start_{500, 0}; + + [[nodiscard]] auto height() const noexcept -> Int { return static_cast(map_.size()); } + [[nodiscard]] auto width() const noexcept -> Int { return width_; } + + [[nodiscard]] auto at(Pos const& p) const noexcept -> char + { + if (p.y() >= height()) { + return gap_; + } + if (p.x() >= map_[p.y()].size()) { + return gap_; + } + return map_[p.y()][p.x()]; + } + + auto add_point(Pos const& p, char val = wall_) + { + auto const x{p.x()}; + auto const y{p.y()}; + if (height() <= p.y()) { + map_.resize(p.y() + 1); + } + if (map_[y].size() < x + 1) { + map_[y].resize(x + 1, gap_); + width_ = std::max(width_, x + 1); + } + map_[y][x] = val; + min_x_ = std::min(min_x_, x); + } + + auto add_sand() -> bool + { + Pos pos{sand_start_}; + while (true) { + Pos const old_pos{pos}; + if (pos.y() >= height()) { + return false; + } + pos += Pos{0, 1}; + if (at(pos) == gap_) { + continue; + } + pos += Pos{-1, 0}; + if (at(pos) == gap_) { + continue; + } + pos += Pos{2, 0}; + if (at(pos) == gap_) { + continue; + } + add_point(old_pos, sand_); + return true; + } + } + + auto add_wall(Pos start, Pos const& end) + { + Pos const delta{direction(end.x() - start.x()), direction(end.y() - start.y())}; + for (; start != end; start += delta) { + add_point(start); + } + add_point(end); + } + + auto dump() const + { + std::cout << "First displayed column: " << min_x_ << '\n'; + for (auto row : map_) { + row.resize(width_, gap_); + std::cout << row.substr(min_x_) << '\n'; + } + } + +private: + std::vector map_; + Int width_{0}; + Int min_x_{std::numeric_limits::max()}; +}; + +auto main() -> int +{ + std::string line; + Map map; + + while (std::getline(std::cin, line)) { + std::size_t pos{0}; + std::size_t l{0}; + Pos start{0, 0}; + start.x(std::stoll(line.substr(pos), &l)); + pos += l + 1; + start.y(std::stoll(line.substr(pos), &l)); + pos += l + 4; + + while (pos < line.size()) { + Pos end{0, 0}; + end.x(std::stoll(line.substr(pos), &l)); + pos += l + 1; + end.y(std::stoll(line.substr(pos), &l)); + pos += l + 4; + map.add_wall(start, end); + start = end; + } + } + + Int sand_pieces{0}; + map.dump(); + while (map.add_sand()) { + map.dump(); + ++sand_pieces; + } + + std::cout << "Number of pieces of sand: " << sand_pieces << '\n'; + + return 0; +} diff --git a/2022/puzzle-14-02.cc b/2022/puzzle-14-02.cc new file mode 100644 index 0000000..cdbc90e --- /dev/null +++ b/2022/puzzle-14-02.cc @@ -0,0 +1,161 @@ +// +// Created by Matthew Gretton-Dann on 09/12/2022. +// + +#include +#include +#include +#include +#include + +#include "position.h" + +using Int = std::int64_t; +using UInt = std::uint64_t; + +auto direction(auto x) -> decltype(x) +{ + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +struct Map +{ + static constexpr char gap_ = '.'; + static constexpr char wall_ = '#'; + static constexpr char sand_ = 'o'; + static constexpr Pos sand_start_{500, 0}; + + [[nodiscard]] auto height() const noexcept -> Int { return static_cast(map_.size()); } + [[nodiscard]] auto width() const noexcept -> Int { return width_; } + + [[nodiscard]] auto at(Pos const& p) const noexcept -> char + { + if (p.y() >= floor_) { + return wall_; + } + if (p.y() >= height()) { + return gap_; + } + if (p.x() >= map_[p.y()].size()) { + return gap_; + } + return map_[p.y()][p.x()]; + } + + auto add_point(Pos const& p, char val = wall_) + { + assert(p.x() >= 0); + assert(p.y() >= 0); + + auto const x{p.x()}; + auto const y{p.y()}; + if (height() <= p.y()) { + map_.resize(p.y() + 1); + } + if (map_[y].size() < x + 1) { + map_[y].resize(x + 1, gap_); + width_ = std::max(width_, x + 1); + } + map_[y][x] = val; + min_x_ = std::min(min_x_, x); + } + + auto add_sand() -> bool + { + Pos pos{sand_start_}; + if (at(pos) != gap_) { + return false; + } + while (true) { + Pos const old_pos{pos}; + + pos += Pos{0, 1}; + if (at(pos) == gap_) { + continue; + } + pos += Pos{-1, 0}; + if (at(pos) == gap_) { + continue; + } + pos += Pos{2, 0}; + if (at(pos) == gap_) { + continue; + } + add_point(old_pos, sand_); + return true; + } + } + + auto add_wall(Pos start, Pos const& end) + { + Pos const delta{direction(end.x() - start.x()), direction(end.y() - start.y())}; + for (; start != end; start += delta) { + add_point(start); + } + add_point(end); + floor_ = std::max(floor_, start.y() + 2); + floor_ = std::max(floor_, end.y() + 2); + } + + auto dump() const + { + std::cout << "First displayed column: " << min_x_ << '\n'; + for (auto row : map_) { + row.resize(width_, gap_); + std::cout << row.substr(min_x_) << '\n'; + } + } + +private: + std::vector map_; + Int floor_{0}; + Int width_{0}; + Int min_x_{std::numeric_limits::max()}; +}; + +auto main() -> int +{ + std::string line; + Map map; + + while (std::getline(std::cin, line)) { + std::size_t pos{0}; + std::size_t l{0}; + Pos start{0, 0}; + start.x(std::stoll(line.substr(pos), &l)); + pos += l + 1; + start.y(std::stoll(line.substr(pos), &l)); + pos += l + 4; + + while (pos < line.size()) { + Pos end{0, 0}; + end.x(std::stoll(line.substr(pos), &l)); + pos += l + 1; + end.y(std::stoll(line.substr(pos), &l)); + pos += l + 4; + map.add_wall(start, end); + start = end; + } + } + + Int sand_pieces{0}; + map.dump(); + std::cout << "Height: " << map.height() << '\n'; + while (map.add_sand()) { + ++sand_pieces; + if (sand_pieces % 10'000 == 0) { + std::cout << "sand_pieces: " << sand_pieces << "\n"; + } + } + + map.dump(); + std::cout << "Number of pieces of sand: " << sand_pieces << '\n'; + + return 0; +}