aboutsummaryrefslogtreecommitdiffstats
path: root/day18/solution.zig
blob: 11da2a10ec7e04026b899b58f562c8bc8f57e9bf (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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const std = @import("std");
const print = std.debug.print;
const assert = std.debug.assert;
const ArrayList = std.ArrayList;
const HashMap = std.HashMap;
const mem = std.mem;

const fin = mem.trim(u8, @embedFile("./example.txt"), &std.ascii.whitespace);
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();

const Direction = [_][2]u64{
    [_]i64{ -1, 0 },
    [_]i64{ 0, 1 },
    [_]i64{ 1, 0 },
    [_]i64{ 0, -1 },
};

const Move = struct {
    dir: usize,
    dist: isize,
    color: []const u8,
};

fn abs(a: i64, b: i64) u64 {
    return @as(u64, @bitCast(@max(a, b) - @min(a, b)));
}

fn evaluate(moves: []const Move) !u64 {
    var polygon = ArrayList([2]i64).init(allocator);
    defer polygon.deinit();

    var curr = [_]i64{ 0, 0 };
    var bl: u64 = 0;

    for (moves) |m| {
        const next = switch (m.dir) {
            'U' => .{
                curr[0] - m.dist,
                curr[1],
            },
            'R' => .{
                curr[0],
                curr[1] + m.dist,
            },
            'D' => .{
                curr[0] + m.dist,
                curr[1],
            },
            'L' => .{
                curr[0],
                curr[1] - m.dist,
            },
            else => unreachable,
        };

        bl += abs(curr[0], next[0]) + abs(curr[1], next[1]);
        try polygon.append(next);
        curr = next;
    }

    const points = polygon.items;
    const nPoints = points.len;
    var a2: i64 = 0;

    for (points, 1..) |f, j| {
        const s = points[j % nPoints];

        a2 += f[0] * s[1] - f[1] * s[0];
    }

    const a: usize = @bitCast(@divTrunc(if (a2 > 0) a2 else -a2, 2));

    return a + 1 + bl / 2;
}

pub fn solve(moves: []const Move) !void {
    const part1 = try evaluate(moves);

    print("{d}\n", .{part1});

    var movespt2 = ArrayList(Move).init(allocator);
    defer movespt2.deinit();

    for (moves) |m| {
        const dist = try std.fmt.parseInt(i64, m.color[0..5], 16);
        const dir: u8 = switch (m.color[5]) {
            '0' => 'R',
            '1' => 'D',
            '2' => 'L',
            '3' => 'U',
            else => unreachable,
        };
        try movespt2.append(Move{
            .dist = dist,
            .dir = dir,
            .color = m.color,
        });
    }

    const part2 = try evaluate(movespt2.items);

    print("{d}\n", .{part2});
}

pub fn main() !void {
    var splitLines = mem.splitScalar(u8, fin, '\n');
    var moves = ArrayList(Move).init(allocator);

    while (splitLines.next()) |line| {
        var toks = mem.tokenizeAny(u8, line, " (#)");
        const dir = toks.next().?[0];
        const dist = try std.fmt.parseInt(i64, toks.next().?, 10);
        const color = toks.next().?;

        try moves.append(Move{
            .dir = dir,
            .dist = dist,
            .color = color,
        });
    }
    try solve(moves.items);
}