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


      1const std = @import("std");
      2const aoc = @import("aoc");
      3
      4const Rule = union(enum) {
      5    c: u8,
      6    combos: []const []const usize,
      7};
      8
      9fn printSlice(slice: []const usize) void {
     10    for (slice) |v, i| {
     11        if (i > 0) {
     12            aoc.debugfmt(" ", .{});
     13        }
     14        aoc.debugfmt("{}", .{v});
     15    }
     16}
     17
     18var stacktrace: std.ArrayList(usize) = undefined;
     19
     20fn checkRule(rules: *std.AutoHashMap(usize, Rule), rid: usize, msg: []const u8, nextstack: *std.ArrayList(usize)) anyerror!bool {
     21    if (msg.len == 0) return true;
     22    const rule = rules.get(rid) orelse return aoc.Error.InvalidInput;
     23
     24    if (rule == .c) {
     25        if (msg[0] != rule.c) return false;
     26        if (msg.len == 1) return (nextstack.items.len == 0);
     27        if (nextstack.items.len == 0) return false;
     28
     29        const next = nextstack.pop();
     30
     31        const valid = try checkRule(rules, next, msg[1..], nextstack);
     32        if (valid) try stacktrace.append(next);
     33        if (valid) return true;
     34
     35        try nextstack.append(next);
     36    } else {
     37        for (rule.combos) |ruleseq| {
     38            try nextstack.appendSlice(ruleseq[1..]);
     39            std.mem.reverse(usize, nextstack.items[nextstack.items.len - (ruleseq.len - 1) ..]);
     40
     41            const valid = try checkRule(rules, ruleseq[0], msg, nextstack);
     42            if (valid) try stacktrace.append(ruleseq[0]);
     43            if (valid) return true;
     44
     45            try nextstack.resize(nextstack.items.len - (ruleseq.len - 1));
     46        }
     47    }
     48    return false;
     49}
     50
     51fn freeRules(allocator: std.mem.Allocator, rules: *std.AutoHashMap(usize, Rule), ignore: ?[]const usize) void {
     52    var mapit = rules.iterator();
     53    while (mapit.next()) |kv| {
     54        if (ignore != null and std.mem.indexOfScalar(usize, ignore.?, kv.key_ptr.*) != null) continue;
     55        if (kv.value_ptr.* == .combos) {
     56            for (kv.value_ptr.combos) |rs| {
     57                allocator.free(rs);
     58            }
     59            allocator.free(kv.value_ptr.combos);
     60        }
     61    }
     62    rules.deinit();
     63}
     64
     65fn parseRule(allocator: std.mem.Allocator, rules: *std.AutoHashMap(usize, Rule), line: []const u8) !void {
     66    const indexsep = try aoc.unwrap(std.mem.indexOf(u8, line, ": "));
     67    const index = try std.fmt.parseInt(usize, line[0..indexsep], 10);
     68
     69    var chrsep = std.mem.indexOf(u8, line, "\"");
     70    if (chrsep != null) {
     71        if (chrsep.? == line.len - 1) return aoc.Error.InvalidInput;
     72        try rules.put(index, Rule{ .c = line[chrsep.? + 1] });
     73    } else {
     74        var vals = std.ArrayList([]usize).init(allocator);
     75        errdefer vals.deinit();
     76
     77        var ruleit = std.mem.split(u8, line[indexsep + 2 ..], " | ");
     78        while (ruleit.next()) |r| {
     79            var ruleids = std.ArrayList(usize).init(allocator);
     80            errdefer ruleids.deinit();
     81
     82            var spaceit = std.mem.tokenize(u8, r, " ");
     83            while (spaceit.next()) |word| {
     84                try ruleids.append(try std.fmt.parseInt(usize, word, 10));
     85            }
     86
     87            if (ruleids.items.len == 0) return aoc.Error.InvalidInput;
     88
     89            try vals.append(ruleids.items);
     90        }
     91
     92        try rules.put(index, Rule{ .combos = vals.items });
     93    }
     94}
     95
     96fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
     97    _ = args;
     98
     99    var rules = std.AutoHashMap(usize, Rule).init(allocator);
    100    defer freeRules(allocator, &rules, null);
    101
    102    var partit = std.mem.split(u8, input, "\n\n");
    103
    104    var lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n");
    105    while (lineit.next()) |line| {
    106        try parseRule(allocator, &rules, line);
    107    }
    108
    109    var answer: u32 = 0;
    110    var nextstack = std.ArrayList(usize).init(allocator);
    111    defer nextstack.deinit();
    112
    113    stacktrace = std.ArrayList(usize).init(allocator);
    114    defer stacktrace.deinit();
    115
    116    lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n");
    117    var count: usize = 0;
    118    while (lineit.next()) |line| {
    119        count += 1;
    120        if (try checkRule(&rules, 0, line, &nextstack))
    121            answer += 1;
    122        try nextstack.resize(0);
    123    }
    124
    125    return try std.fmt.allocPrint(allocator, "{}", .{answer});
    126}
    127
    128fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    129    _ = args;
    130
    131    var rules = std.AutoHashMap(usize, Rule).init(allocator);
    132    defer freeRules(allocator, &rules, ([_]usize{ 8, 11 })[0..]);
    133
    134    var partit = std.mem.split(u8, input, "\n\n");
    135
    136    var lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n");
    137    while (lineit.next()) |line| {
    138        if (std.mem.eql(u8, line[0..2], "8:")) {
    139            const p1: []const usize = ([_]usize{42})[0..];
    140            const p2: []const usize = ([_]usize{ 42, 8 })[0..];
    141            try rules.put(8, Rule{ .combos = ([_][]const usize{ p1, p2 })[0..] });
    142        } else if (std.mem.eql(u8, line[0..3], "11:")) {
    143            const p1: []const usize = ([_]usize{ 42, 31 })[0..];
    144            const p2: []const usize = ([_]usize{ 42, 11, 31 })[0..];
    145            try rules.put(11, Rule{ .combos = ([_][]const usize{ p1, p2 })[0..] });
    146        } else {
    147            try parseRule(allocator, &rules, line);
    148        }
    149    }
    150
    151    var answer: u32 = 0;
    152    var nextstack = std.ArrayList(usize).init(allocator);
    153    defer nextstack.deinit();
    154
    155    stacktrace = std.ArrayList(usize).init(allocator);
    156    defer stacktrace.deinit();
    157
    158    var count: usize = 0;
    159    lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n");
    160    while (lineit.next()) |line| {
    161        count += 1;
    162        const valid = try checkRule(&rules, 0, line, &nextstack);
    163        answer += @boolToInt(valid);
    164        if (aoc.debug) {
    165            aoc.debugfmt("TRACE: [", .{});
    166            std.mem.reverse(usize, stacktrace.items);
    167            printSlice(stacktrace.items);
    168            aoc.debugfmt("]\n", .{});
    169            if (valid) {
    170                aoc.debugfmt("MATCH {s}\n\n", .{line});
    171            } else {
    172                aoc.debugfmt("NO MATCH {s}\n\n", .{line});
    173            }
    174        }
    175        try nextstack.resize(0);
    176    }
    177
    178    return try std.fmt.allocPrint(allocator, "{}", .{answer});
    179}
    180
    181pub const main = aoc.main(part1, part2, .{ "134", "377" });