main.zig (3635B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4const BagCount = struct { id: u64, count: u32 }; 5 6const BagRule = struct { 7 outer: u64, 8 innerit: std.mem.SplitIterator(u8), 9 10 fn from(line: []const u8) BagRule { 11 var partit = std.mem.split(u8, line, " bags contain "); 12 const outer = std.hash.CityHash64.hash(partit.next().?); 13 var innerit = std.mem.split(u8, partit.next().?, ", "); 14 return BagRule{ .outer = outer, .innerit = innerit }; 15 } 16 17 fn nextInner(self: *BagRule) !?BagCount { 18 if (self.innerit.next()) |bagstr| { 19 if (std.mem.eql(u8, bagstr[0..2], "no")) return null; 20 const lastsep = std.mem.lastIndexOfScalar(u8, bagstr, ' ').?; 21 const firstsep = std.mem.indexOfScalar(u8, bagstr, ' ').?; 22 const count = try std.fmt.parseInt(u32, bagstr[0..firstsep], 10); 23 const id = std.hash.CityHash64.hash(bagstr[firstsep + 1 .. lastsep]); 24 return BagCount{ .id = id, .count = count }; 25 } else { 26 return null; 27 } 28 } 29}; 30 31fn countBagsTotal(map: *std.AutoHashMap(u64, std.ArrayList(BagCount)), outer: u64) u64 { 32 var sum: u64 = 0; 33 if (map.get(outer)) |inner| { 34 for (inner.items) |bag| 35 sum += bag.count * (1 + countBagsTotal(map, bag.id)); 36 } 37 return sum; 38} 39 40fn countParentTypes(map: *std.AutoHashMap(u64, std.ArrayList(u64)), inner: u64, seen: *std.ArrayList(u64)) anyerror!u64 { 41 var sum: u64 = 0; 42 if (map.get(inner)) |outer| { 43 for (outer.items) |bagid| { 44 if (std.mem.indexOfScalar(u64, seen.items, bagid) == null) { 45 try seen.append(bagid); 46 sum += 1 + try countParentTypes(map, bagid, seen); 47 } 48 } 49 } 50 return sum; 51} 52 53fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 54 _ = args; 55 56 var lineit = std.mem.tokenize(u8, input, "\n"); 57 var map = std.AutoHashMap(u64, std.ArrayList(u64)).init(allocator); 58 defer { 59 var mapit = map.iterator(); 60 while (mapit.next()) |kv| kv.value_ptr.deinit(); 61 map.deinit(); 62 } 63 64 while (lineit.next()) |line| { 65 var rule = BagRule.from(line); 66 while (try rule.nextInner()) |inner| { 67 if (map.get(inner.id) == null) 68 try map.put(inner.id, std.ArrayList(u64).init(allocator)); 69 try map.getEntry(inner.id).?.value_ptr.append(rule.outer); 70 } 71 } 72 73 const target = std.hash.CityHash64.hash("shiny gold"); 74 var seen = std.ArrayList(u64).init(allocator); 75 defer seen.deinit(); 76 77 const answer = try countParentTypes(&map, target, &seen); 78 79 return try std.fmt.allocPrint(allocator, "{d}", .{answer}); 80} 81 82fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 83 _ = args; 84 85 var lineit = std.mem.tokenize(u8, input, "\n"); 86 var map = std.AutoHashMap(u64, std.ArrayList(BagCount)).init(allocator); 87 defer { 88 var mapit = map.iterator(); 89 while (mapit.next()) |kv| kv.value_ptr.deinit(); 90 map.deinit(); 91 } 92 93 const target = std.hash.CityHash64.hash("shiny gold"); 94 while (lineit.next()) |line| { 95 var rule = BagRule.from(line); 96 if (map.get(rule.outer) == null) 97 try map.put(rule.outer, std.ArrayList(BagCount).init(allocator)); 98 while (try rule.nextInner()) |bag| { 99 try map.getEntry(rule.outer).?.value_ptr.append(bag); 100 } 101 } 102 103 const answer = countBagsTotal(&map, target); 104 105 return try std.fmt.allocPrint(allocator, "{d}", .{answer}); 106} 107 108pub const main = aoc.main(part1, part2, .{ "161", "30899" });