summaryrefslogtreecommitdiff
path: root/2023/18/src/part2.cpp
blob: e9b6c028158dd382f8690c6c6a71a12c1529ef66 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <tuple>

#include "util.h"

enum Dir { R = 0, D, L, U };
using Cmd = std::tuple<Dir,long>;
using Pos = std::pair<long,long>;
using Polygon = std::vector<Pos>;

std::vector<Cmd> parse(const char* file)
{
    std::vector<Cmd> cmds;
    if (std::ifstream input{ file }; input.is_open())
    {
        Dir dir; int steps; std::string color;
        std::string line;
        while (not std::getline(input,line).eof())
        {
            std::stringstream in{ line };
            in >> util::skip<char> >> util::skip<int> >> color;
            steps = std::stoi(color.substr(2, 5), nullptr, 16);
            dir = static_cast<Dir>(std::stoi(color.substr(7, 1)));
            cmds.push_back({ dir, steps });
        }
    }
    return cmds;
}

std::pair<long,Polygon> compute_border(Pos pos, const std::vector<Cmd>& cmds)
{
    Polygon poly;
    long border{};
    auto [x, y] = pos;
    for(const auto& cmd : cmds)
    {
        auto [dir, steps] = cmd;
        switch (dir)
        {
            case R: y += steps; break;
            case D: x += steps; break;
            case L: y -= steps; break;
            case U: x -= steps;
        }
        poly.push_back({ x, y });
        border += steps;
    }
    return { border, std::move(poly) };
}

int main(int argc, char* argv[])
{
    auto cmds = parse(argv[1]);
    auto [border, polygon] = compute_border({ 0, 0 }, cmds);
    long area = util::shoelace<long>(polygon.cbegin(), polygon.cend());

    std::cout << border + util::pick(area, border) << std::endl;
    return 0;
}