aoc-2020-zig

Advent of Code 2020 Solutions in Zig
git clone https://git.sinitax.com/sinitax/aoc-2020-zig
Log | Files | Refs | README | sfeed.txt

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" });