summaryrefslogtreecommitdiff
path: root/aoc24/src/day8.zig
blob: 2d90fd6057f610594d5656e3d19f7346c7047d94 (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
const std = @import("std");

const Pos = @Vector(2, isize);

const Input = struct {
    width: usize,
    height: usize,
    antenna_locations: std.AutoHashMap(u8, std.ArrayList(Pos)),
};

pub fn parse(allocator: std.mem.Allocator, data: []const u8) !Input {
    var lines = std.mem.split(u8, data, "\n");
    var width: usize = undefined;
    var y: usize = 0;
    var antenna_locations = std.AutoHashMap(u8, std.ArrayList(Pos)).init(allocator);
    while (lines.next()) |line| : (y += 1) {
        if (line.len == 0) break;
        for (0.., line) |x, c| {
            switch (c) {
                '0'...'9', 'a'...'z', 'A'...'Z' => {
                    const res = try antenna_locations.getOrPut(c);
                    if (!res.found_existing)
                        res.value_ptr.* = std.ArrayList(Pos).init(allocator);
                    try res.value_ptr.*.append(.{ @intCast(x), @intCast(y) });
                },
                else => {},
            }
        }
        width = line.len;
    }
    return .{
        .width = width,
        .height = y,
        .antenna_locations = antenna_locations,
    };
}

const test_input =
    \\............
    \\........0...
    \\.....0......
    \\.......0....
    \\....0.......
    \\......A.....
    \\............
    \\............
    \\........A...
    \\.........A..
    \\............
    \\............
    \\
;

test "part1" {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit();

    const output = try part1(arena.allocator(), try parse(arena.allocator(), test_input));
    std.debug.print("got {}\n", .{output});
    std.debug.assert(output == 14);
}

pub fn part1(allocator: std.mem.Allocator, input: Input) !u32 {
    var it = input.antenna_locations.valueIterator();
    var antinodes = std.AutoHashMap(Pos, void).init(allocator);
    while (it.next()) |locations| {
        for (locations.items) |a| for (locations.items) |b| {
            if (@reduce(.And, a == b)) continue;
            const pos = b + b - a;
            if (pos[0] < 0 or input.width <= pos[0] or
                pos[1] < 0 or input.height <= pos[1]) continue;
            try antinodes.put(pos, {});
        };
    }
    return antinodes.count();
}

test "part2" {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit();

    const output = try part2(arena.allocator(), try parse(arena.allocator(), test_input));
    std.debug.print("got {}\n", .{output});
    std.debug.assert(output == 34);
}

pub fn part2(allocator: std.mem.Allocator, input: Input) !u32 {
    var it = input.antenna_locations.valueIterator();
    var antinodes = std.AutoHashMap(Pos, void).init(allocator);
    while (it.next()) |locations| {
        for (locations.items) |a| for (locations.items) |b| {
            if (@reduce(.And, a == b)) continue;
            const delta = b - a;
            var pos = b;
            while (0 <= pos[0] and pos[0] < input.width and
                0 <= pos[1] and pos[1] < input.height) : (pos += delta)
            {
                try antinodes.put(pos, {});
            }
        };
    }
    return antinodes.count();
}