summaryrefslogtreecommitdiff
path: root/src/day06.zig
blob: bbea665aab764fc2c5f9b0fb17ad22efeb91f412 (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
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 {
    var lines = std.mem.splitScalar(u8, buffer, '\n');
    var grid = std.ArrayList([]u8).init(allocator);
    defer grid.deinit();
    var x: i32 = 0;
    var y: i32 = 0;

    var row: usize = 0;
    while (lines.next()) |line| : (row += 1) {
        for (line, 0..) |element, i| {
            if (element == '^') {
                x = @intCast(i);
                y = @intCast(row);
            }
        }
        try grid.append(@constCast(line));
    }

    if (std.mem.eql(u8, part, "1")) {
        try part1(&grid, x, y, allocator);
    } else {
        try part2(&grid, x, y, allocator);
    }
}

fn locations(grid: *std.ArrayList([]u8), startx: i32, starty: i32, allocator: std.mem.Allocator) !std.AutoHashMap(std.meta.Tuple(&.{ i32, i32 }), void) {
    var dirx: i32 = 0;
    var diry: i32 = -1;
    var x = startx;
    var y = starty;
    var unique = std.AutoHashMap(std.meta.Tuple(&.{ i32, i32 }), void).init(allocator);
    errdefer unique.deinit();

    while (y >= 0 and y < grid.items.len and x >= 0 and x < grid.items[@intCast(y)].len) {
        if (grid.items[@intCast(y)][@intCast(x)] == '#') {
            x -= dirx;
            y -= diry;
            const temp = dirx;
            dirx = -diry;
            diry = temp;
        }

        try unique.put(.{ x, y }, {});

        x += dirx;
        y += diry;
    }

    return unique;
}

fn part1(grid: *std.ArrayList([]u8), startx: i32, starty: i32, allocator: std.mem.Allocator) !void {
    var locs = try locations(grid, startx, starty, allocator);
    defer locs.deinit();
    print("{d}\n", .{locs.count()});
}

//----------------------------PART 2---------------------------------------------

fn directionToIndex(dirx: i32, diry: i32) i32 {
    if (dirx == 0 and diry == -1) {
        return 0;
    } else if (dirx == 1 and diry == 0) {
        return 1;
    } else if (dirx == 0 and diry == 1) {
        return 2;
    } else {
        return 3;
    }
}
fn part2(grid: *std.ArrayList([]u8), startx: i32, starty: i32, allocator: std.mem.Allocator) !void {
    var locs = try locations(grid, startx, starty, allocator);
    defer locs.deinit();
    var total: usize = 0;

    var iterator = locs.keyIterator();
    var history = try allocator.alloc(bool, grid.items.len * grid.items[0].len * 4);
    defer allocator.free(history);

    const width: i32 = @intCast(grid.items[0].len);

    while (iterator.next()) |location| {
        grid.items[@intCast(location[1])][@intCast(location[0])] = '#';
        var dirx: i32 = 0;
        var diry: i32 = -1;
        var x = startx;
        var y = starty;

        for (history) |*elem| {
            elem.* = false;
        }

        while (y >= 0 and y < grid.items.len and x >= 0 and x < grid.items[@intCast(y)].len) {
            const index = y * width * 4 + x * 4 + directionToIndex(dirx, diry);
            if (history[@intCast(index)]) {
                total += 1;
                break;
            }
            if (grid.items[@intCast(y)][@intCast(x)] == '#') {
                x -= dirx;
                y -= diry;
                const temp = dirx;
                dirx = -diry;
                diry = temp;
            }

            history[@intCast(index)] = true;

            x += dirx;
            y += diry;
        }

        grid.items[@intCast(location[1])][@intCast(location[0])] = '.';
    }

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