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

  • addie@feddit.uk
    link
    fedilink
    arrow-up
    3
    ·
    1 month 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);
    }