163 lines
3.3 KiB
C++
163 lines
3.3 KiB
C++
//
|
|
// Created by Matthew Gretton-Dann on 09/12/2022.
|
|
//
|
|
|
|
#include <array>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <cassert>
|
|
|
|
#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<Int> sand_start_{500, 0};
|
|
|
|
[[nodiscard]] auto height() const noexcept -> Int { return static_cast<Int>(map_.size()); }
|
|
[[nodiscard]] auto width() const noexcept -> Int { return width_; }
|
|
|
|
[[nodiscard]] auto at(Pos<Int> 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<Int> 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<Int>{0, 1};
|
|
if (at(pos) == gap_) {
|
|
continue;
|
|
}
|
|
pos += Pos<Int>{-1, 0};
|
|
if (at(pos) == gap_) {
|
|
continue;
|
|
}
|
|
pos += Pos<Int>{2, 0};
|
|
if (at(pos) == gap_) {
|
|
continue;
|
|
}
|
|
add_point(old_pos, sand_);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
auto add_wall(Pos<Int> start, Pos<Int> const& end)
|
|
{
|
|
Pos<Int> 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<std::string> map_;
|
|
Int floor_{0};
|
|
Int width_{0};
|
|
Int min_x_{std::numeric_limits<Int>::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<Int> 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<Int> 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;
|
|
}
|