summaryrefslogtreecommitdiff
path: root/src/day12.zig
blob: 32fca4b9801a6c8659d0bf026bd1eff256c5cf0e (plain)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const std = @import("std");
const mecha = @import("mecha");
const print = std.debug.print;

pub fn solve(part: []u8, buffer: []u8, allocator: std.mem.Allocator) !void {
    if (std.mem.eql(u8, part, "1")) {
        try part1(buffer, allocator);
    } else {
        try part2(buffer, allocator);
    }
}

fn recursive(mapped: [][]bool, grid: [][]const u8, r: i32, c: i32, region: u8) std.meta.Tuple(&.{ usize, usize }) {
    if (r >= 0 and r < grid.len and c >= 0 and c < grid[@intCast(r)].len and grid[@intCast(r)][@intCast(c)] == region) {
        if (!mapped[@intCast(r)][@intCast(c)]) {
            mapped[@intCast(r)][@intCast(c)] = true;
            const up = recursive(mapped, grid, r - 1, c, region);
            const down = recursive(mapped, grid, r + 1, c, region);
            const left = recursive(mapped, grid, r, c - 1, region);
            const right = recursive(mapped, grid, r, c + 1, region);
            return .{ 1 + up[0] + down[0] + left[0] + right[0], up[1] + down[1] + left[1] + right[1] };
        } else {
            return .{ 0, 0 };
        }
    } else {
        return .{ 0, 1 };
    }
}

fn part1(buffer: []const u8, allocator: std.mem.Allocator) !void {
    var lines = std.mem.splitScalar(u8, buffer, '\n');

    var grid = std.ArrayList([]const u8).init(allocator);
    defer grid.deinit();

    var mapped = std.ArrayList([]bool).init(allocator);
    defer mapped.deinit();

    while (lines.next()) |line| {
        try grid.append(line);

        const mapped_row = try allocator.alloc(bool, line.len);
        @memset(mapped_row, false);
        try mapped.append(mapped_row);
    }

    var output: usize = 0;
    for (grid.items, 0..) |row, ri| {
        for (row, 0..) |item, ci| {
            if (!mapped.items[ri][ci]) {
                const plot = recursive(mapped.items, grid.items, @intCast(ri), @intCast(ci), item);
                output += plot[0] * plot[1];
            }
        }
    }

    for (mapped.items) |mapped_row| {
        allocator.free(mapped_row);
    }

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

//----------------------------------PART2-----------------------------

fn recursive2(mapped: [][]bool, grid: [][]const u8, pr: i32, pc: i32, r: i32, c: i32, region: u8, perimeters: *std.AutoHashMap(std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }), void)) !usize {
    if (r >= 0 and r < grid.len and c >= 0 and c < grid[@intCast(r)].len and grid[@intCast(r)][@intCast(c)] == region) {
        if (!mapped[@intCast(r)][@intCast(c)]) {
            mapped[@intCast(r)][@intCast(c)] = true;
            const up = try recursive2(mapped, grid, r, c, r - 1, c, region, perimeters);
            const down = try recursive2(mapped, grid, r, c, r + 1, c, region, perimeters);
            const left = try recursive2(mapped, grid, r, c, r, c - 1, region, perimeters);
            const right = try recursive2(mapped, grid, r, c, r, c + 1, region, perimeters);
            return 1 + up + down + left + right;
        } else {
            return 0;
        }
    } else {
        const key: std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }) = .{ (c < pc or r < pr), r, c, @intCast(@abs(c - pc)), @intCast(@abs(r - pr)) };
        try perimeters.put(key, {});
        return 0;
    }
}

fn find_edge(b: bool, rr: i32, cc: i32, dr: i32, dc: i32, perimeters: std.AutoHashMap(std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }), void), seen: *std.AutoHashMap(std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }), void)) !void {
    var r = rr + dr;
    var c = cc + dc;
    var key: std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }) = .{ b, r, c, @intCast(@abs(dr)), @intCast(@abs(dc)) };
    while (perimeters.contains(key) and !seen.contains(key)) : (key = .{ b, r, c, @intCast(@abs(dr)), @intCast(@abs(dc)) }) {
        try seen.put(key, {});
        r += dr;
        c += dc;
    }
}

fn part2(buffer: []const u8, allocator: std.mem.Allocator) !void {
    var lines = std.mem.splitScalar(u8, buffer, '\n');

    var grid = std.ArrayList([]const u8).init(allocator);
    defer grid.deinit();

    var mapped = std.ArrayList([]bool).init(allocator);
    defer mapped.deinit();

    while (lines.next()) |line| {
        if (line.len == 0) break;
        try grid.append(line);

        const mapped_row = try allocator.alloc(bool, line.len);
        @memset(mapped_row, false);
        try mapped.append(mapped_row);
    }

    var output: usize = 0;
    for (grid.items, 0..) |row, ri| {
        for (row, 0..) |item, ci| {
            if (!mapped.items[ri][ci]) {
                var perimeters = std.AutoHashMap(std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }), void).init(allocator);
                defer perimeters.deinit();

                const area = try recursive2(mapped.items, grid.items, @intCast(ri), @intCast(ci), @intCast(ri), @intCast(ci), item, &perimeters);
                var seen = std.AutoHashMap(std.meta.Tuple(&.{ bool, i32, i32, i32, i32 }), void).init(allocator);
                defer seen.deinit();
                var iterator = perimeters.keyIterator();
                var edge_count: usize = 0;
                while (iterator.next()) |key| {
                    if (!seen.contains(key.*)) {
                        try find_edge(key[0], key[1], key[2], key[3], key[4], perimeters, &seen);
                        try find_edge(key[0], key[1], key[2], -1 * key[3], -1 * key[4], perimeters, &seen);
                        edge_count += 1;
                    }
                }
                output += area * edge_count;
            }
        }
    }

    for (mapped.items) |mapped_row| {
        allocator.free(mapped_row);
    }

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