Day 18: Lavaduct Lagoon

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

  • cvttsd2si@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    1 year ago

    C++

    No scala today

    #include 
    #include 
    #include <map>
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct HorizontalEdge { boost::icl::discrete_interval x; long y; };
    
    long area(std::vector he) {
        if(he.empty())
            return 0;
    
        boost::icl::interval_set intervals;
        std::ranges::sort(he, std::less{}, &amp;HorizontalEdge::y);
        long area{};
        long y = he.front().y;
    
        for(auto const&amp; e : he) {
            area += intervals.size() * (e.y - std::exchange(y, e.y));
            if(intervals.find(e.x) != intervals.end())
                intervals.erase(e.x);
            else 
                intervals.add(e.x);
        }
    
        return area;
    }
    
    struct Instruction {
        long l;
        int d;
        std::string color;
    };
    
    enum Dir { R=0, U=1, L=2, D=3 };
    std::unordered_map char_to_dir = {{'R', R}, {'U', U}, {'L', L}, {'D', D}};
    
    auto transcode(std::vector const&amp; is) {
        return flux::from(std::move(is)).map([](Instruction in) {
            long v = std::stoul(in.color.substr(0, 5), nullptr, 16);
            return Instruction{.l = v, .d = (4 - (in.color.at(5) - '0')) % 4, .color=""};
        }).to>();
    }
    
    std::vector read(std::string path) {
        std::ifstream in(std::move(path));
        return flux::getlines(in).map([](std::string const&amp; s) {
            Instruction i;
            char dir;
            if(auto r = scn::scan(s, "{} {} (#{:6})", dir, i.l, i.color)) {
                i.d = char_to_dir[dir];
                return i;
            } else {
                throw std::runtime_error{r.error().msg()};
            }
        }).to>();
    }
    
    auto turns(std::vector is) {
        if(is.empty()) throw std::runtime_error{"Too few elements"};
        is.push_back(is.front());
        return flux::from(std::move(is)).pairwise_map([](auto const&amp; lhs, auto const&amp; rhs) { return (rhs.d - lhs.d + 4) % 4 == 1; });
    }
    
    std::vector toEdges(std::vector is, bool left) {
        std::vector res;
        long x{}, y{};
    
        auto t = turns(is).to>();
    
        // some magic required to turn the ### path into its outer edge
        // (which is the actual object we want to compute the area for)
        for(size_t j = 0; j &lt; is.size(); ++j) {
            auto const&amp; i = is.at(j);
            bool s1 = t.at((j + t.size() - 1) % t.size()) == left;
            bool s2 = t.at(j) == left;
            long sign = (i.d == U || i.d == L) ? -1 : 1;
            long old_x = x;
            if(i.d == R || i.d == L) {
                x += i.l * sign;
                auto [l, r] = old_x &lt; x ? std::tuple{old_x + !s1, x + s2} : std::tuple{x + !s2, old_x + s1};
                res.push_back(HorizontalEdge{.x = {l, r, boost::icl::interval_bounds::right_open()}, .y = y});
            } else {
                y += (i.l + s1 + s2 - 1) * sign;
            }
        }
    
        return res;
    }
    
    long solve(std::vector is) {
        auto tn = turns(is).sum() - ssize(is);
        return area(toEdges(std::move(is), tn > 0));
    }
    
    int main(int argc, char* argv[]) {
        auto instructions = read(argc > 1 ? argv[1] : "../task1.txt");
        auto start = std::chrono::steady_clock::now();
        fmt::print("task1={}\ntask2={}\n", solve(instructions), solve(transcode(std::move(instructions))));
        fmt::print("took {}\n", std::chrono::steady_clock::now() - start);
    }
    ```</map>