Day 20: Race Condition

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
    2
    ·
    2 days ago

    C++ / Boost

    Ah, cunning - my favourite one so far this year, I think. Nothing too special compared to the other solutions - floods the map using Dijkstra, then checks “every pair” for how much of a time saver it is. 0.3s on my laptop; it iterates through every pair twice since it does part 1 and part 2 separately, which could easily be improved upon.

    spoiler
    #include <boost/log/trivial.hpp>
    #include <boost/unordered/unordered_flat_map.hpp>
    #include <boost/unordered/unordered_flat_set.hpp>
    #include <cstddef>
    #include <fstream>
    #include <limits>
    #include <queue>
    #include <stdexcept>
    
    namespace {
    
    using Loc = std::pair<int, int>;
    using Dir = std::pair<int, int>;
    template <class T>
    using Score = std::pair<size_t, T>;
    template <class T>
    using MinHeap = std::priority_queue<Score<T>, std::vector<Score<T>>, std::greater<Score<T>>>;
    using Map = boost::unordered_flat_set<Loc>;
    
    auto operator+(const Loc &l, const Dir &d) {
      return Loc{l.first + d.first, l.second + d.second};
    }
    
    auto manhattan(const Loc &a, const Loc &b) {
      return std::abs(a.first - b.first) + std::abs(a.second - b.second);
    }
    
    auto dirs = std::vector<Dir>{
        {0,  -1},
        {0,  1 },
        {-1, 0 },
        {1,  0 }
    };
    
    struct Maze {
      Map map;
      Loc start;
      Loc end;
    };
    
    auto parse() {
      auto rval = Maze{};
      auto line = std::string{};
      auto ih = std::ifstream{"input/20"};
      auto row = 0;
      while (std::getline(ih, line)) {
        for (auto col = 0; col < int(line.size()); ++col) {
          auto t = line.at(col);
          switch (t) {
          case 'S':
            rval.start = Loc{col, row};
            rval.map.insert(Loc{col, row});
            break;
          case 'E':
            rval.end = Loc{col, row};
            rval.map.insert(Loc{col, row});
            break;
          case '.':
            rval.map.insert(Loc{col, row});
            break;
          case '#':
            break;
          default:
            throw std::runtime_error{"oops"};
          }
        }
        ++row;
      }
      return rval;
    }
    
    auto dijkstra(const Maze &m) {
      auto unvisited = MinHeap<Loc>{};
      auto visited = boost::unordered_flat_map<Loc, size_t>{};
    
      for (const auto &e : m.map)
        visited[e] = std::numeric_limits<size_t>::max();
    
      visited[m.start] = 0;
      unvisited.push({0, {m.start}});
    
      while (!unvisited.empty()) {
        auto next = unvisited.top();
        unvisited.pop();
    
        if (visited.at(next.second) < next.first)
          continue;
    
        for (const auto &dir : dirs) {
          auto prospective = Loc{next.second + dir};
          if (!visited.contains(prospective))
            continue;
          auto pscore = next.first + 1;
          if (visited.at(prospective) > pscore) {
            visited[prospective] = pscore;
            unvisited.push({pscore, prospective});
          }
        }
      }
    
      return visited;
    }
    
    using Walk = decltype(dijkstra(Maze{}));
    
    constexpr auto GOOD_CHEAT = 100;
    
    auto evaluate_cheats(const Walk &walk, int skip) {
      auto rval = size_t{};
      for (auto &start : walk) {
        for (auto &end : walk) {
          auto distance = manhattan(start.first, end.first);
          if (distance <= skip && end.second > start.second) {
            auto improvement = int(end.second) - int(start.second) - distance;
            if (improvement >= GOOD_CHEAT)
              ++rval;
          }
        }
      }
      return rval;
    }
    
    } // namespace
    
    auto main() -> int {
      auto p = parse();
      auto walk = dijkstra(p);
      BOOST_LOG_TRIVIAL(info) << "01: " << evaluate_cheats(walk, 2);
      BOOST_LOG_TRIVIAL(info) << "02: " << evaluate_cheats(walk, 20);
    }