Add 2021 day 19 puzzles
This commit is contained in:
203
2021/puzzle-19-01.cc
Normal file
203
2021/puzzle-19-01.cc
Normal file
@@ -0,0 +1,203 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using Int = long;
|
||||
struct Coord
|
||||
{
|
||||
constexpr Coord(Int x, Int y, Int z) noexcept : x_(x), y_(y), z_(z) {}
|
||||
|
||||
explicit Coord(std::string const& s)
|
||||
{
|
||||
std::size_t idx{0};
|
||||
x_ = std::stol(s, &idx);
|
||||
assert(idx < s.size() && s[idx] == ',');
|
||||
++idx;
|
||||
std::size_t end{0};
|
||||
y_ = std::stol(s.substr(idx), &end);
|
||||
idx += end;
|
||||
assert(idx < s.size() && s[idx] == ',');
|
||||
++idx;
|
||||
z_ = std::stol(s.substr(idx));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto x() const noexcept -> Int { return x_; }
|
||||
[[nodiscard]] auto y() const noexcept -> Int { return y_; }
|
||||
[[nodiscard]] auto z() const noexcept -> Int { return z_; }
|
||||
|
||||
auto operator+=(Coord const& c) -> Coord
|
||||
{
|
||||
x_ += c.x_;
|
||||
y_ += c.y_;
|
||||
z_ += c.z_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator-=(Coord const& c) -> Coord
|
||||
{
|
||||
x_ -= c.x_;
|
||||
y_ -= c.y_;
|
||||
z_ -= c.z_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator<(Coord const& c) const -> bool
|
||||
{
|
||||
return x_ < c.x_ || (x_ == c.x_ && y_ < c.y_) || (x_ == c.x_ && y_ < c.y_ && z_ < c.z_);
|
||||
}
|
||||
|
||||
private:
|
||||
Int x_{0};
|
||||
Int y_{0};
|
||||
Int z_{0};
|
||||
};
|
||||
|
||||
auto operator<<(std::ostream& os, Coord const& c) -> std::ostream&
|
||||
{
|
||||
os << "[" << c.x() << ", " << c.y() << ", " << c.z() << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
auto operator+(Coord const& lhs, Coord const& rhs) -> Coord
|
||||
{
|
||||
auto result(lhs);
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto operator-(Coord const& lhs, Coord const& rhs) -> Coord
|
||||
{
|
||||
auto result(lhs);
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto operator-(Coord const& lhs) -> Coord { return {-lhs.x(), -lhs.y(), -lhs.z()}; }
|
||||
|
||||
using CoordVector = std::vector<Coord>;
|
||||
using CoordSet = std::set<Coord>;
|
||||
using Transform = std::array<Coord, 3>;
|
||||
|
||||
auto operator<<(std::ostream& os, Transform const& t) -> std::ostream&
|
||||
{
|
||||
os << "[[" << t[0].x() << ' ' << t[0].y() << ' ' << t[0].z() << ']';
|
||||
os << '[' << t[1].x() << ' ' << t[1].y() << ' ' << t[1].z() << ']';
|
||||
os << '[' << t[2].x() << ' ' << t[2].y() << ' ' << t[2].z() << "]]";
|
||||
return os;
|
||||
}
|
||||
|
||||
auto transform(Coord const& c, Transform const& t) -> Coord
|
||||
{
|
||||
return {c.x() * t[0].x() + c.y() * t[0].y() + c.z() * t[0].z(),
|
||||
c.x() * t[1].x() + c.y() * t[1].y() + c.z() * t[1].z(),
|
||||
c.x() * t[2].x() + c.y() * t[2].y() + c.z() * t[2].z()};
|
||||
}
|
||||
|
||||
constexpr Coord x{1, 0, 0};
|
||||
constexpr Coord y{0, 1, 0};
|
||||
constexpr Coord z{0, 0, 1};
|
||||
|
||||
Transform const transforms[24] = {{-z, -y, -x}, {-z, -x, y}, {-z, x, -y}, {-z, y, x}, {-y, -z, x},
|
||||
{-y, -x, -z}, {-y, x, z}, {-y, z, -x}, {-x, -z, -y}, {-x, -y, z},
|
||||
{-x, y, -z}, {-x, z, y}, {x, -z, y}, {x, -y, -z}, {x, y, z},
|
||||
{x, z, -y}, {y, -z, -x}, {y, -x, z}, {y, x, -z}, {y, z, x},
|
||||
{z, -y, x}, {z, -x, -y}, {z, x, y}, {z, y, -x}};
|
||||
|
||||
struct Scanner
|
||||
{
|
||||
void absolute_position(Coord const& c) { absolute_position_ = c; }
|
||||
[[nodiscard]] auto absolute_position() const -> Coord const& { return absolute_position_; }
|
||||
[[nodiscard]] auto located() const -> bool { return located_; }
|
||||
void locate() { located_ = true; }
|
||||
|
||||
[[nodiscard]] auto probes_begin() const { return probes_.begin(); }
|
||||
[[nodiscard]] auto probes_end() const { return probes_.end(); }
|
||||
[[nodiscard]] auto probes_begin() { return probes_.begin(); }
|
||||
[[nodiscard]] auto probes_end() { return probes_.end(); }
|
||||
[[nodiscard]] auto size() const -> std::size_t { return probes_.size(); }
|
||||
|
||||
void insert_probe(Coord const& c) { probes_.push_back(c); }
|
||||
Coord absolute_position_{0, 0, 0};
|
||||
bool located_{false};
|
||||
CoordVector probes_;
|
||||
};
|
||||
|
||||
using Scanners = std::vector<Scanner>;
|
||||
|
||||
auto main() -> int
|
||||
{
|
||||
std::string line;
|
||||
Scanners scanners;
|
||||
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
if (line.substr(0, 3) != "---") {
|
||||
std::cerr << "Unexpected header.\n";
|
||||
return 1;
|
||||
}
|
||||
scanners.emplace_back();
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
scanners.back().insert_probe(Coord{line});
|
||||
}
|
||||
}
|
||||
|
||||
/* We locate the first scanner in the default position. */
|
||||
scanners[0].locate();
|
||||
|
||||
while (!std::all_of(scanners.begin(), scanners.end(),
|
||||
[](auto const& scanner) { return scanner.located(); })) {
|
||||
/* While we have something to locate. */
|
||||
for (auto it{scanners.begin()}; it != scanners.end(); ++it) {
|
||||
/* Outer loop: loops over all located nodes - we have at least one (the first). */
|
||||
if (!it->located()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto it2{scanners.begin()}; it2 != scanners.end(); ++it2) {
|
||||
/* Inner loop: loops over all un-located nodes. */
|
||||
if (it2->located()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now iterate over the possible locations for the scanners relatvie to each other. */
|
||||
for (auto base_position{it->probes_begin()};
|
||||
base_position != it->probes_end() && !it2->located(); ++base_position) {
|
||||
for (auto probe_it{it2->probes_begin()}; probe_it != it2->probes_end() && !it2->located();
|
||||
++probe_it) {
|
||||
for (auto const& t : transforms) {
|
||||
auto abs_position{*base_position - transform(*probe_it, t)};
|
||||
CoordSet probes;
|
||||
auto inserter{std::inserter(probes, probes.end())};
|
||||
std::copy(it->probes_begin(), it->probes_end(), inserter);
|
||||
std::transform(
|
||||
it2->probes_begin(), it2->probes_end(), inserter,
|
||||
[&abs_position, &t](Coord const& c) { return transform(c, t) + abs_position; });
|
||||
|
||||
if (probes.size() + 12 <= it->size() + it2->size()) {
|
||||
/* Move probes to expected position. */
|
||||
it2->absolute_position(abs_position);
|
||||
std::for_each(
|
||||
it2->probes_begin(), it2->probes_end(),
|
||||
[&abs_position, &t](Coord& c) { c = transform(c, t) + abs_position; });
|
||||
std::cout << "Located: " << it2 - scanners.begin() << '\n';
|
||||
it2->locate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CoordSet probes;
|
||||
for (auto const& scanner : scanners) {
|
||||
probes.insert(scanner.probes_begin(), scanner.probes_end());
|
||||
assert(scanner.located());
|
||||
}
|
||||
|
||||
std::cout << "Number of probes: " << probes.size();
|
||||
return 0;
|
||||
}
|
217
2021/puzzle-19-02.cc
Normal file
217
2021/puzzle-19-02.cc
Normal file
@@ -0,0 +1,217 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using Int = long;
|
||||
struct Coord
|
||||
{
|
||||
constexpr Coord(Int x, Int y, Int z) noexcept : x_(x), y_(y), z_(z) {}
|
||||
|
||||
explicit Coord(std::string const& s)
|
||||
{
|
||||
std::size_t idx{0};
|
||||
x_ = std::stol(s, &idx);
|
||||
assert(idx < s.size() && s[idx] == ',');
|
||||
++idx;
|
||||
std::size_t end{0};
|
||||
y_ = std::stol(s.substr(idx), &end);
|
||||
idx += end;
|
||||
assert(idx < s.size() && s[idx] == ',');
|
||||
++idx;
|
||||
z_ = std::stol(s.substr(idx));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto x() const noexcept -> Int { return x_; }
|
||||
[[nodiscard]] auto y() const noexcept -> Int { return y_; }
|
||||
[[nodiscard]] auto z() const noexcept -> Int { return z_; }
|
||||
|
||||
auto operator+=(Coord const& c) -> Coord
|
||||
{
|
||||
x_ += c.x_;
|
||||
y_ += c.y_;
|
||||
z_ += c.z_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator-=(Coord const& c) -> Coord
|
||||
{
|
||||
x_ -= c.x_;
|
||||
y_ -= c.y_;
|
||||
z_ -= c.z_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator<(Coord const& c) const -> bool
|
||||
{
|
||||
return x_ < c.x_ || (x_ == c.x_ && y_ < c.y_) || (x_ == c.x_ && y_ < c.y_ && z_ < c.z_);
|
||||
}
|
||||
|
||||
private:
|
||||
Int x_{0};
|
||||
Int y_{0};
|
||||
Int z_{0};
|
||||
};
|
||||
|
||||
auto operator<<(std::ostream& os, Coord const& c) -> std::ostream&
|
||||
{
|
||||
os << "[" << c.x() << ", " << c.y() << ", " << c.z() << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
auto operator+(Coord const& lhs, Coord const& rhs) -> Coord
|
||||
{
|
||||
auto result(lhs);
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto operator-(Coord const& lhs, Coord const& rhs) -> Coord
|
||||
{
|
||||
auto result(lhs);
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto operator-(Coord const& lhs) -> Coord { return {-lhs.x(), -lhs.y(), -lhs.z()}; }
|
||||
|
||||
auto manhattan_distance(Coord const& lhs, Coord const& rhs) -> Int
|
||||
{
|
||||
return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()) + std::abs(lhs.z() - rhs.z());
|
||||
}
|
||||
|
||||
using CoordVector = std::vector<Coord>;
|
||||
using CoordSet = std::set<Coord>;
|
||||
using Transform = std::array<Coord, 3>;
|
||||
|
||||
auto operator<<(std::ostream& os, Transform const& t) -> std::ostream&
|
||||
{
|
||||
os << "[[" << t[0].x() << ' ' << t[0].y() << ' ' << t[0].z() << ']';
|
||||
os << '[' << t[1].x() << ' ' << t[1].y() << ' ' << t[1].z() << ']';
|
||||
os << '[' << t[2].x() << ' ' << t[2].y() << ' ' << t[2].z() << "]]";
|
||||
return os;
|
||||
}
|
||||
|
||||
auto transform(Coord const& c, Transform const& t) -> Coord
|
||||
{
|
||||
return {c.x() * t[0].x() + c.y() * t[0].y() + c.z() * t[0].z(),
|
||||
c.x() * t[1].x() + c.y() * t[1].y() + c.z() * t[1].z(),
|
||||
c.x() * t[2].x() + c.y() * t[2].y() + c.z() * t[2].z()};
|
||||
}
|
||||
|
||||
constexpr Coord x{1, 0, 0};
|
||||
constexpr Coord y{0, 1, 0};
|
||||
constexpr Coord z{0, 0, 1};
|
||||
|
||||
Transform const transforms[24] = {{-z, -y, -x}, {-z, -x, y}, {-z, x, -y}, {-z, y, x}, {-y, -z, x},
|
||||
{-y, -x, -z}, {-y, x, z}, {-y, z, -x}, {-x, -z, -y}, {-x, -y, z},
|
||||
{-x, y, -z}, {-x, z, y}, {x, -z, y}, {x, -y, -z}, {x, y, z},
|
||||
{x, z, -y}, {y, -z, -x}, {y, -x, z}, {y, x, -z}, {y, z, x},
|
||||
{z, -y, x}, {z, -x, -y}, {z, x, y}, {z, y, -x}};
|
||||
|
||||
struct Scanner
|
||||
{
|
||||
void absolute_position(Coord const& c) { absolute_position_ = c; }
|
||||
[[nodiscard]] auto absolute_position() const -> Coord const& { return absolute_position_; }
|
||||
[[nodiscard]] auto located() const -> bool { return located_; }
|
||||
void locate() { located_ = true; }
|
||||
[[nodiscard]] auto scanned() const -> bool { return scanned_; }
|
||||
void scan() { scanned_ = true; }
|
||||
|
||||
[[nodiscard]] auto probes_begin() const { return probes_.begin(); }
|
||||
[[nodiscard]] auto probes_end() const { return probes_.end(); }
|
||||
[[nodiscard]] auto probes_begin() { return probes_.begin(); }
|
||||
[[nodiscard]] auto probes_end() { return probes_.end(); }
|
||||
[[nodiscard]] auto size() const -> std::size_t { return probes_.size(); }
|
||||
|
||||
void insert_probe(Coord const& c) { probes_.push_back(c); }
|
||||
Coord absolute_position_{0, 0, 0};
|
||||
bool located_{false};
|
||||
bool scanned_{false};
|
||||
CoordVector probes_;
|
||||
};
|
||||
|
||||
using Scanners = std::vector<Scanner>;
|
||||
|
||||
auto main() -> int
|
||||
{
|
||||
std::string line;
|
||||
Scanners scanners;
|
||||
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
if (line.substr(0, 3) != "---") {
|
||||
std::cerr << "Unexpected header.\n";
|
||||
return 1;
|
||||
}
|
||||
scanners.emplace_back();
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
scanners.back().insert_probe(Coord{line});
|
||||
}
|
||||
}
|
||||
|
||||
/* We locate the first scanner in the default position. */
|
||||
scanners[0].locate();
|
||||
|
||||
while (!std::all_of(scanners.begin(), scanners.end(),
|
||||
[](auto const& scanner) { return scanner.located(); })) {
|
||||
/* While we have something to locate. */
|
||||
for (auto it{scanners.begin()}; it != scanners.end(); ++it) {
|
||||
/* Outer loop: loops over all located nodes - we have at least one (the first). */
|
||||
if (!it->located() || it->scanned()) {
|
||||
continue;
|
||||
}
|
||||
it->scan();
|
||||
|
||||
for (auto it2{scanners.begin()}; it2 != scanners.end(); ++it2) {
|
||||
/* Inner loop: loops over all un-located nodes. */
|
||||
if (it2->located()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now iterate over the possible locations for the scanners relatvie to each other. */
|
||||
for (auto base_position{it->probes_begin()};
|
||||
base_position != it->probes_end() && !it2->located(); ++base_position) {
|
||||
for (auto probe_it{it2->probes_begin()}; probe_it != it2->probes_end() && !it2->located();
|
||||
++probe_it) {
|
||||
for (auto const& t : transforms) {
|
||||
auto abs_position{*base_position - transform(*probe_it, t)};
|
||||
CoordSet probes;
|
||||
auto inserter{std::inserter(probes, probes.end())};
|
||||
std::copy(it->probes_begin(), it->probes_end(), inserter);
|
||||
std::transform(
|
||||
it2->probes_begin(), it2->probes_end(), inserter,
|
||||
[&abs_position, &t](Coord const& c) { return transform(c, t) + abs_position; });
|
||||
|
||||
if (probes.size() + 12 <= it->size() + it2->size()) {
|
||||
/* Move probes to expected position. */
|
||||
it2->absolute_position(abs_position);
|
||||
std::for_each(
|
||||
it2->probes_begin(), it2->probes_end(),
|
||||
[&abs_position, &t](Coord& c) { c = transform(c, t) + abs_position; });
|
||||
std::cout << "Located: " << it2 - scanners.begin() << '\n';
|
||||
it2->locate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CoordSet probes;
|
||||
Int max_dist{0};
|
||||
for (auto const& scanner : scanners) {
|
||||
probes.insert(scanner.probes_begin(), scanner.probes_end());
|
||||
for (auto const& scanner2 : scanners) {
|
||||
auto dist{manhattan_distance(scanner.absolute_position(), scanner2.absolute_position())};
|
||||
max_dist = std::max(dist, max_dist);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Number of probes: " << probes.size() << '\n';
|
||||
std::cout << "Maximum distance: " << max_dist << '\n';
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user