main.zig (3728B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4fn getBit(v: u36, i: u6) bool { 5 return ((v >> i) & 1) > 0; 6} 7 8fn clearBit(v: u36, i: u6) u36 { 9 return v & ~(@as(u36, 1) << i); 10} 11 12fn setBit(v: u36, i: u6) u36 { 13 return v | (@as(u36, 1) << i); 14} 15 16fn getValStr(line: []const u8) ![]const u8 { 17 const sep = std.mem.indexOf(u8, line, " = "); 18 if (sep == null) return aoc.Error.InvalidInput; 19 return line[sep.? + 3 ..]; 20} 21 22fn getAddrStr(line: []const u8) ![]const u8 { 23 const sep = std.mem.indexOfScalar(u8, line, ']'); 24 if (sep == null) return aoc.Error.InvalidInput; 25 return line[4..sep.?]; 26} 27 28fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 29 _ = args; 30 31 var answer: u64 = 0; 32 33 var memmap = std.AutoHashMap(u36, u64).init(allocator); 34 defer memmap.deinit(); 35 36 var ormask: u36 = 0; 37 var andmask: u36 = ~@as(u36, 0); 38 39 var lineit = std.mem.tokenize(u8, input, "\n"); 40 while (lineit.next()) |line| { 41 if (std.mem.eql(u8, line[0..4], "mask")) { 42 andmask = ~@as(u36, 0); 43 ormask = 0; 44 for (try getValStr(line)) |c, i| { 45 if (c == '0') { 46 andmask = clearBit(andmask, @intCast(u6, 35 - i)); 47 } else if (c == '1') { 48 ormask = setBit(ormask, @intCast(u6, 35 - i)); 49 } 50 } 51 } else { 52 const val = try std.fmt.parseInt(u36, try getValStr(line), 10); 53 const addr = try std.fmt.parseInt(u36, try getAddrStr(line), 10); 54 try memmap.put(addr, (val & andmask) | ormask); 55 } 56 } 57 58 var mapit = memmap.iterator(); 59 while (mapit.next()) |kv| { 60 answer += kv.value_ptr.*; 61 } 62 63 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 64} 65 66fn bitRecurse(map: *std.AutoHashMap(u36, u64), addr: *u36, val: u64, mask: u36, index: u6) anyerror!void { 67 if (index == 36) { 68 aoc.debugfmt("SET: {b} {}\n", .{ addr.*, val }); 69 try map.put(addr.*, val); 70 } else { 71 if (getBit(mask, index)) { 72 addr.* = setBit(addr.*, index); 73 try bitRecurse(map, addr, val, mask, index + 1); 74 addr.* = clearBit(addr.*, index); 75 try bitRecurse(map, addr, val, mask, index + 1); 76 } else { 77 try bitRecurse(map, addr, val, mask, index + 1); 78 } 79 } 80} 81 82fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 83 _ = args; 84 85 var answer: u64 = 0; 86 87 var memmap = std.AutoHashMap(u36, u64).init(allocator); 88 defer memmap.deinit(); 89 90 var ormask: u36 = 0; 91 var flipmask: u36 = 0; 92 93 var lineit = std.mem.tokenize(u8, input, "\n"); 94 while (lineit.next()) |line| { 95 if (std.mem.eql(u8, line[0..4], "mask")) { 96 ormask = 0; 97 flipmask = 0; 98 for (try getValStr(line)) |c, i| { 99 if (c == '1') { 100 ormask = setBit(ormask, @intCast(u6, 35 - i)); 101 } else if (c == 'X') { 102 flipmask = setBit(flipmask, @intCast(u6, 35 - i)); 103 } 104 } 105 } else { 106 var addr = try std.fmt.parseInt(u36, try getAddrStr(line), 10); 107 const val = try std.fmt.parseInt(u36, try getValStr(line), 10); 108 addr = addr | ormask; 109 aoc.debugfmt("{b} {b} {} {}\n", .{ flipmask, ormask, addr, val }); 110 try bitRecurse(&memmap, &addr, val, flipmask, 0); 111 } 112 } 113 114 var mapit = memmap.iterator(); 115 while (mapit.next()) |kv| { 116 answer += kv.value_ptr.*; 117 } 118 119 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 120} 121 122pub const main = aoc.main(part1, part2, .{ "4886706177792", "3348493585827" });