Day 8: Playground

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

you are viewing a single comment's thread
view the rest of the comments
[–] 3 points 11 months ago

C++

Both parts in 40 ms. As always, the real AoC with C++ is parsing the input, although having a number that changes in the puzzle messes up my test/ solution runners.

Uses Boost's implementations of sets, since they're just plain faster than the STL ones.

Code

#include <boost/log/trivial.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <filesystem>
#include <fstream>
#include <stdexcept>

namespace {

struct Point {
  int x, y, z;
};

auto distance(const Point &a, const Point &b) {
  auto &[ax, ay, az] = a;
  auto &[bx, by, bz] = b;
  ssize_t dx = ax - bx;
  ssize_t dy = ay - by;
  ssize_t dz = az - bz;
  return size_t(dx * dx + dy * dy + dz * dz);
}

using PList = std::vector<Point>;
using DMap = std::vector<std::pair<std::pair<size_t, size_t>, size_t>>;
using DSet = boost::unordered::unordered_flat_set<size_t>;

auto read() {
  auto rval = PList{};
  auto ih = std::ifstream{"08.txt"};
  auto line = std::string{};
  while (std::getline(ih, line)) {
    auto c1 = line.find(',');
    auto c2 = line.find(',', c1 + 1);
    rval.emplace_back(
        std::stoi(line.substr(0, c1)),
        std::stoi(line.substr(c1 + 1, c2 - c1 - 1)),
        std::stoi(line.substr(c2 + 1))
    );
  }
  return rval;
}

auto dmap(const PList &t) {
  auto rval = DMap{};
  for (auto a = size_t{}; a < t.size() - 1; ++a)
    for (auto b = a + 1; b < t.size(); ++b)
      rval.emplace_back(std::make_pair(a, b), distance(t.at(a), t.at(b)));
  return rval;
}

auto find(size_t c, std::vector<DSet> &sets) {
  for (auto i = sets.begin(); i != sets.end(); ++i)
    if (i->contains(c))
      return i;
  throw std::runtime_error{"can't find"};
}

auto part1(const PList &t, size_t count, const DMap &d) {
  auto circuits = std::vector<DSet>{};
  for (auto i = size_t{}; i < t.size(); ++i) {
    auto c = DSet{t.size()};
    c.insert(i);
    circuits.push_back(std::move(c));
  }

  for (auto i = size_t{}; i < count; ++i) {
    auto a = d.at(i).first.first;
    auto b = d.at(i).first.second;
    auto ac = find(a, circuits);
    auto bc = find(b, circuits);
    if (ac == bc)
      continue;
    ac->insert(bc->begin(), bc->end());
    circuits.erase(bc);
  }

  std::sort(circuits.begin(), circuits.end(), [](auto &a, auto &b) {
    return a.size() > b.size();
  });
  auto total = size_t{1};
  for (auto i = size_t{}; i < 3; ++i)
    total *= circuits.at(i).size();

  return total;
}

auto part2(const PList &t, const DMap &d) {
  auto circuits = std::vector<DSet>{};
  for (auto i = size_t{}; i < t.size(); ++i) {
    auto c = DSet{t.size()};
    c.insert(i);
    circuits.push_back(std::move(c));
  }

  for (auto i = size_t{}; i < d.size(); ++i) {
    auto a = d.at(i).first.first;
    auto b = d.at(i).first.second;
    auto ac = find(a, circuits);
    auto bc = find(b, circuits);
    if (ac == bc)
      continue;
    ac->insert(bc->begin(), bc->end());
    circuits.erase(bc);
    if (circuits.size() == 1) {
      return ssize_t(t.at(a).x) * ssize_t(t.at(b).x);
    }
  }
  throw std::runtime_error{"never joins?"};
}

} // namespace

auto main() -> int {
  auto t = read();
  BOOST_LOG_TRIVIAL(info) << "Day 8: read " << t.size();
  auto test = std::filesystem::current_path().filename().string() ==
              std::string{"test"};

  auto d = dmap(t);
  std::sort(d.begin(), d.end(), [](auto &a, auto &b) {
    return a.second < b.second;
  });

  BOOST_LOG_TRIVIAL(info) << "1: " << part1(t, test ? 10 : 1000, d);
  BOOST_LOG_TRIVIAL(info) << "2: " << part2(t, d);
}

  • source