aboutsummaryrefslogtreecommitdiffstats
path: root/src/07/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/07/main.zig')
-rw-r--r--src/07/main.zig108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/07/main.zig b/src/07/main.zig
new file mode 100644
index 0000000..f252d22
--- /dev/null
+++ b/src/07/main.zig
@@ -0,0 +1,108 @@
+const std = @import("std");
+const aoc = @import("aoc");
+
+const BagCount = struct { id: u64, count: u32 };
+
+const BagRule = struct {
+ outer: u64,
+ innerit: std.mem.SplitIterator(u8),
+
+ fn from(line: []const u8) BagRule {
+ var partit = std.mem.split(u8, line, " bags contain ");
+ const outer = std.hash.CityHash64.hash(partit.next().?);
+ var innerit = std.mem.split(u8, partit.next().?, ", ");
+ return BagRule{ .outer = outer, .innerit = innerit };
+ }
+
+ fn nextInner(self: *BagRule) !?BagCount {
+ if (self.innerit.next()) |bagstr| {
+ if (std.mem.eql(u8, bagstr[0..2], "no")) return null;
+ const lastsep = std.mem.lastIndexOfScalar(u8, bagstr, ' ').?;
+ const firstsep = std.mem.indexOfScalar(u8, bagstr, ' ').?;
+ const count = try std.fmt.parseInt(u32, bagstr[0..firstsep], 10);
+ const id = std.hash.CityHash64.hash(bagstr[firstsep + 1 .. lastsep]);
+ return BagCount{ .id = id, .count = count };
+ } else {
+ return null;
+ }
+ }
+};
+
+fn countBagsTotal(map: *std.AutoHashMap(u64, std.ArrayList(BagCount)), outer: u64) u64 {
+ var sum: u64 = 0;
+ if (map.get(outer)) |inner| {
+ for (inner.items) |bag|
+ sum += bag.count * (1 + countBagsTotal(map, bag.id));
+ }
+ return sum;
+}
+
+fn countParentTypes(map: *std.AutoHashMap(u64, std.ArrayList(u64)), inner: u64, seen: *std.ArrayList(u64)) anyerror!u64 {
+ var sum: u64 = 0;
+ if (map.get(inner)) |outer| {
+ for (outer.items) |bagid| {
+ if (std.mem.indexOfScalar(u64, seen.items, bagid) == null) {
+ try seen.append(bagid);
+ sum += 1 + try countParentTypes(map, bagid, seen);
+ }
+ }
+ }
+ return sum;
+}
+
+fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
+ _ = args;
+
+ var lineit = std.mem.tokenize(u8, input, "\n");
+ var map = std.AutoHashMap(u64, std.ArrayList(u64)).init(allocator);
+ defer {
+ var mapit = map.iterator();
+ while (mapit.next()) |kv| kv.value_ptr.deinit();
+ map.deinit();
+ }
+
+ while (lineit.next()) |line| {
+ var rule = BagRule.from(line);
+ while (try rule.nextInner()) |inner| {
+ if (map.get(inner.id) == null)
+ try map.put(inner.id, std.ArrayList(u64).init(allocator));
+ try map.getEntry(inner.id).?.value_ptr.append(rule.outer);
+ }
+ }
+
+ const target = std.hash.CityHash64.hash("shiny gold");
+ var seen = std.ArrayList(u64).init(allocator);
+ defer seen.deinit();
+
+ const answer = try countParentTypes(&map, target, &seen);
+
+ return try std.fmt.allocPrint(allocator, "{d}", .{answer});
+}
+
+fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
+ _ = args;
+
+ var lineit = std.mem.tokenize(u8, input, "\n");
+ var map = std.AutoHashMap(u64, std.ArrayList(BagCount)).init(allocator);
+ defer {
+ var mapit = map.iterator();
+ while (mapit.next()) |kv| kv.value_ptr.deinit();
+ map.deinit();
+ }
+
+ const target = std.hash.CityHash64.hash("shiny gold");
+ while (lineit.next()) |line| {
+ var rule = BagRule.from(line);
+ if (map.get(rule.outer) == null)
+ try map.put(rule.outer, std.ArrayList(BagCount).init(allocator));
+ while (try rule.nextInner()) |bag| {
+ try map.getEntry(rule.outer).?.value_ptr.append(bag);
+ }
+ }
+
+ const answer = countBagsTotal(&map, target);
+
+ return try std.fmt.allocPrint(allocator, "{d}", .{answer});
+}
+
+pub const main = aoc.main(part1, part2, .{ "161", "30899" });