aboutsummaryrefslogtreecommitdiffstats
path: root/src/14/main.zig
blob: e45203dee5613e6e8d1e6e4a18081073522b2068 (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
const std = @import("std");
const aoc = @import("aoc");

fn getBit(v: u36, i: u6) bool {
    return ((v >> i) & 1) > 0;
}

fn clearBit(v: u36, i: u6) u36 {
    return v & ~(@as(u36, 1) << i);
}

fn setBit(v: u36, i: u6) u36 {
    return v | (@as(u36, 1) << i);
}

fn getValStr(line: []const u8) ![]const u8 {
    const sep = std.mem.indexOf(u8, line, " = ");
    if (sep == null) return aoc.Error.InvalidInput;
    return line[sep.? + 3 ..];
}

fn getAddrStr(line: []const u8) ![]const u8 {
    const sep = std.mem.indexOfScalar(u8, line, ']');
    if (sep == null) return aoc.Error.InvalidInput;
    return line[4..sep.?];
}

fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    _ = args;

    var answer: u64 = 0;

    var memmap = std.AutoHashMap(u36, u64).init(allocator);
    defer memmap.deinit();

    var ormask: u36 = 0;
    var andmask: u36 = ~@as(u36, 0);

    var lineit = std.mem.tokenize(u8, input, "\n");
    while (lineit.next()) |line| {
        if (std.mem.eql(u8, line[0..4], "mask")) {
            andmask = ~@as(u36, 0);
            ormask = 0;
            for (try getValStr(line)) |c, i| {
                if (c == '0') {
                    andmask = clearBit(andmask, @intCast(u6, 35 - i));
                } else if (c == '1') {
                    ormask = setBit(ormask, @intCast(u6, 35 - i));
                }
            }
        } else {
            const val = try std.fmt.parseInt(u36, try getValStr(line), 10);
            const addr = try std.fmt.parseInt(u36, try getAddrStr(line), 10);
            try memmap.put(addr, (val & andmask) | ormask);
        }
    }

    var mapit = memmap.iterator();
    while (mapit.next()) |kv| {
        answer += kv.value_ptr.*;
    }

    return try std.fmt.allocPrint(allocator, "{}", .{answer});
}

fn bitRecurse(map: *std.AutoHashMap(u36, u64), addr: *u36, val: u64, mask: u36, index: u6) anyerror!void {
    if (index == 36) {
        aoc.debugfmt("SET: {b} {}\n", .{ addr.*, val });
        try map.put(addr.*, val);
    } else {
        if (getBit(mask, index)) {
            addr.* = setBit(addr.*, index);
            try bitRecurse(map, addr, val, mask, index + 1);
            addr.* = clearBit(addr.*, index);
            try bitRecurse(map, addr, val, mask, index + 1);
        } else {
            try bitRecurse(map, addr, val, mask, index + 1);
        }
    }
}

fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    _ = args;

    var answer: u64 = 0;

    var memmap = std.AutoHashMap(u36, u64).init(allocator);
    defer memmap.deinit();

    var ormask: u36 = 0;
    var flipmask: u36 = 0;

    var lineit = std.mem.tokenize(u8, input, "\n");
    while (lineit.next()) |line| {
        if (std.mem.eql(u8, line[0..4], "mask")) {
            ormask = 0;
            flipmask = 0;
            for (try getValStr(line)) |c, i| {
                if (c == '1') {
                    ormask = setBit(ormask, @intCast(u6, 35 - i));
                } else if (c == 'X') {
                    flipmask = setBit(flipmask, @intCast(u6, 35 - i));
                }
            }
        } else {
            var addr = try std.fmt.parseInt(u36, try getAddrStr(line), 10);
            const val = try std.fmt.parseInt(u36, try getValStr(line), 10);
            addr = addr | ormask;
            aoc.debugfmt("{b} {b} {} {}\n", .{ flipmask, ormask, addr, val });
            try bitRecurse(&memmap, &addr, val, flipmask, 0);
        }
    }

    var mapit = memmap.iterator();
    while (mapit.next()) |kv| {
        answer += kv.value_ptr.*;
    }

    return try std.fmt.allocPrint(allocator, "{}", .{answer});
}

pub const main = aoc.main(part1, part2, .{ "4886706177792", "3348493585827" });