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 (6732B)


      1const std = @import("std");
      2const aoc = @import("aoc");
      3
      4const hasher = std.hash.CityHash32;
      5const IngredientInfo = struct {
      6    count: u32,
      7};
      8const Pair = struct { ingredient: []const u8, allergen: []const u8 };
      9
     10fn freeListmap(listmap: *std.AutoHashMap(u32, std.ArrayList(u32))) void {
     11    var mapit = listmap.iterator();
     12    while (mapit.next()) |kv| {
     13        kv.value_ptr.deinit();
     14    }
     15    listmap.deinit();
     16}
     17
     18fn getAllergen(allergens: *std.AutoHashMap(u32, std.ArrayList(u32)), ingredient: u32) ?u32 {
     19    var allergenit = allergens.iterator();
     20    while (allergenit.next()) |alg| {
     21        if (alg.value_ptr.items.len == 1 and alg.value_ptr.items[0] == ingredient)
     22            return alg.key_ptr.*;
     23    }
     24    return null;
     25}
     26
     27fn updateAllergens(allocator: std.mem.Allocator, allergens: *std.AutoHashMap(u32, std.ArrayList(u32)), allergen: u32) !void {
     28    var next = std.ArrayList(u32).init(allocator);
     29    defer next.deinit();
     30
     31    try next.append(allergen);
     32
     33    while (next.items.len > 0) {
     34        const key = next.items[0];
     35        var ingredient = allergens.getEntry(key).?.value_ptr.items[0];
     36        var mapit = allergens.iterator();
     37        while (mapit.next()) |alg| {
     38            if (alg.key_ptr.* == key) continue;
     39            const ind = std.mem.indexOfScalar(u32, alg.value_ptr.items, ingredient);
     40            if (ind != null) {
     41                _ = alg.value_ptr.swapRemove(ind.?);
     42                if (alg.value_ptr.items.len == 1) {
     43                    try next.append(alg.key_ptr.*);
     44                }
     45            }
     46        }
     47        _ = next.swapRemove(0);
     48    }
     49}
     50
     51fn parseAllergens(allocator: std.mem.Allocator, allergens: *std.AutoHashMap(u32, std.ArrayList(u32)), unhash: *std.AutoHashMap(u32, []const u8), ingredient_counts: *std.AutoHashMap(u32, u32), input: []const u8) !void {
     52    var ingredients = std.ArrayList(u32).init(allocator);
     53    defer ingredients.deinit();
     54
     55    var lineit = std.mem.tokenize(u8, input, "\n");
     56    while (lineit.next()) |line| {
     57        var allergen = false;
     58
     59        try ingredients.resize(0);
     60
     61        var spaceit = std.mem.tokenize(u8, line, " ");
     62        while (spaceit.next()) |word| {
     63            if (std.mem.eql(u8, word, "(contains")) {
     64                allergen = true;
     65                continue;
     66            }
     67
     68            if (allergen) {
     69                const allergen_name = if (word[word.len - 1] == ')' or word[word.len - 1] == ',') word[0 .. word.len - 1] else word;
     70                const allergen_hash = hasher.hash(allergen_name);
     71                try unhash.put(allergen_hash, allergen_name);
     72                var algentry = allergens.getEntry(allergen_hash);
     73                if (algentry) |algent| {
     74                    var i: u32 = 0;
     75                    while (i < algent.value_ptr.items.len) {
     76                        if (std.mem.indexOfScalar(u32, ingredients.items, algent.value_ptr.items[i]) == null) {
     77                            _ = algent.value_ptr.swapRemove(i);
     78                        } else {
     79                            i += 1;
     80                        }
     81                    }
     82
     83                    if (algent.value_ptr.items.len == 1) {
     84                        try updateAllergens(allocator, allergens, algent.key_ptr.*);
     85                    }
     86                } else {
     87                    var copy = std.ArrayList(u32).init(allocator);
     88                    errdefer copy.deinit();
     89                    for (ingredients.items) |ing| {
     90                        if (getAllergen(allergens, ing) == null) {
     91                            try copy.append(ing);
     92                        }
     93                    }
     94                    try allergens.put(allergen_hash, copy);
     95                }
     96            } else {
     97                const ingredient_hash = hasher.hash(word);
     98                try unhash.put(ingredient_hash, word);
     99                try ingredients.append(ingredient_hash);
    100                const entry = ingredient_counts.getEntry(ingredient_hash);
    101                if (entry == null) {
    102                    try ingredient_counts.put(ingredient_hash, 1);
    103                } else {
    104                    entry.?.value_ptr.* += 1;
    105                }
    106            }
    107        }
    108    }
    109}
    110
    111fn ascendingAllergen(ctx: void, p1: Pair, p2: Pair) bool {
    112    _ = ctx;
    113    var i: u32 = 0;
    114    while (i < std.math.min(p1.allergen.len, p2.allergen.len) and p1.allergen[i] == p2.allergen[i]) : (i += 1) {}
    115    return p1.allergen[i] < p2.allergen[i];
    116}
    117
    118fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    119    _ = args;
    120
    121    var allergens = std.AutoHashMap(u32, std.ArrayList(u32)).init(allocator);
    122    defer freeListmap(&allergens);
    123
    124    var ingredient_counts = std.AutoHashMap(u32, u32).init(allocator);
    125    defer ingredient_counts.deinit();
    126
    127    var unhash = std.AutoHashMap(u32, []const u8).init(allocator);
    128    defer unhash.deinit();
    129
    130    try parseAllergens(allocator, &allergens, &unhash, &ingredient_counts, input);
    131
    132    var answer: u32 = 0;
    133
    134    var algit = allergens.iterator();
    135    while (algit.next()) |alg| {
    136        aoc.debugfmt("{} - ", .{alg.key_ptr.*});
    137        for (alg.value_ptr.items) |v| {
    138            aoc.debugfmt("{} ", .{v});
    139        }
    140        aoc.debugfmt("\n", .{});
    141    }
    142
    143    var mapit = ingredient_counts.iterator();
    144    while (mapit.next()) |kv| {
    145        if (getAllergen(&allergens, kv.key_ptr.*) == null) answer += kv.value_ptr.*;
    146    }
    147
    148    return try std.fmt.allocPrint(allocator, "{}", .{answer});
    149}
    150
    151fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    152    _ = args;
    153
    154    var allergens = std.AutoHashMap(u32, std.ArrayList(u32)).init(allocator);
    155    defer freeListmap(&allergens);
    156
    157    var ingredient_counts = std.AutoHashMap(u32, u32).init(allocator);
    158    defer ingredient_counts.deinit();
    159
    160    var unhash = std.AutoHashMap(u32, []const u8).init(allocator);
    161    defer unhash.deinit();
    162
    163    try parseAllergens(allocator, &allergens, &unhash, &ingredient_counts, input);
    164
    165    var pairs = std.ArrayList(Pair).init(allocator);
    166    defer pairs.deinit();
    167
    168    var mapit = ingredient_counts.iterator();
    169    while (mapit.next()) |kv| {
    170        const alg = getAllergen(&allergens, kv.key_ptr.*);
    171        if (alg != null) {
    172            try pairs.append(Pair{ .ingredient = unhash.get(kv.key_ptr.*).?, .allergen = unhash.get(alg.?).? });
    173        }
    174    }
    175
    176    std.sort.sort(Pair, pairs.items, {}, ascendingAllergen);
    177
    178    var parts = std.ArrayList([]const u8).init(allocator);
    179    defer parts.deinit();
    180    for (pairs.items) |p, i| {
    181        if (i > 0) try parts.append(",");
    182        try parts.append(p.ingredient);
    183    }
    184    return try std.mem.join(allocator, "", parts.items);
    185}
    186
    187const sol2 = "fqhpsl,zxncg,clzpsl,zbbnj,jkgbvlxh,dzqc,ppj,glzb";
    188pub const main = aoc.main(part1, part2, .{ "2584", sol2 });