const std = @import("std"); const Str = []const u8; const PATH = "input/day07.txt"; pub fn first(allocator: std.mem.Allocator) !usize { var known = std.StringHashMap(usize).init(allocator); defer known.deinit(); return try resolve(&known, @embedFile(PATH)); } pub fn second(allocator: std.mem.Allocator) !usize { var known = std.StringHashMap(usize).init(allocator); defer known.deinit(); try known.put("b", 956); return try resolve(&known, @embedFile(PATH)); } fn resolve(known: *std.StringHashMap(usize), input: Str) !usize { var lines = std.mem.tokenize(u8, input, "\n"); while (true) { const size = known.count(); lines.reset(); while (lines.next()) |line| { var words = std.mem.tokenize(u8, line, " "); if (std.mem.containsAtLeast(u8, line, 1, "NOT")) { _ = words.next(); // NOT const wire = words.next().?; const val = known.get(wire) orelse continue; _ = words.next().?; // drop '->' const target = words.next().?; try known.put(target, ~val); } else if (std.mem.containsAtLeast(u8, line, 1, "AND") or std.mem.containsAtLeast(u8, line, 1, "OR") or std.mem.containsAtLeast(u8, line, 1, "LSHIFT") or std.mem.containsAtLeast(u8, line, 1, "RSHIFT")) { const left = words.next().?; const operand = words.next().?; const right = words.next().?; _ = words.next(); // drop '->' const target = words.next().?; try handleOp(known, left, operand, right, target); } else { const wire = words.next().?; const val = std.fmt.parseUnsigned(usize, wire, 10) catch known.get(wire) orelse continue; _ = words.next(); // drop '->' const target = words.next().?; // Do not overwrite 'b' value - Part 2 if (std.mem.eql(u8, target, "b") and known.contains("b")) continue; try known.put(target, val); } } if (known.get("a")) |val| return val; if (size == known.count()) unreachable; } unreachable; } fn handleOp(known: *std.StringHashMap(usize), o1: Str, op: Str, o2: Str, target: Str) !void { const left = std.fmt.parseUnsigned(usize, o1, 10) catch known.get(o1) orelse return; const right = std.fmt.parseUnsigned(usize, o2, 10) catch known.get(o2) orelse return; if (std.mem.eql(u8, op, "AND")) { try known.put(target, left & right); } else if (std.mem.eql(u8, op, "OR")) { try known.put(target, left | right); } else if (std.mem.eql(u8, op, "RSHIFT")) { try known.put(target, left >> @intCast(u6, right)); } else if (std.mem.eql(u8, op, "LSHIFT")) { try known.put(target, left << @intCast(u6, right)); } else { unreachable; } } test "day07a" { try std.testing.expectEqual(@as(usize, 956), try first(std.testing.allocator)); } test "day07b" { try std.testing.expectEqual(@as(usize, 40149), try second(std.testing.allocator)); }