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


      1const std = @import("std");
      2const aoc = @import("aoc");
      3
      4const Range = struct { min: u32, max: u32 };
      5const FieldRule = struct { name: []const u8, r1: Range, r2: Range };
      6
      7fn assert(comptime T: type, part: ?T) !T {
      8    if (part == null) return aoc.Error.InvalidInput;
      9    return part.?;
     10}
     11
     12fn parseRange(str: []const u8) !Range {
     13    const sep = try assert(usize, std.mem.indexOfScalar(u8, str, '-'));
     14    if (sep == str.len - 1) return aoc.Error.InvalidInput;
     15    return Range{
     16        .min = try std.fmt.parseInt(u32, str[0..sep], 10),
     17        .max = try std.fmt.parseInt(u32, str[sep + 1 ..], 10),
     18    };
     19}
     20
     21fn parseRules(rules: *std.ArrayList(FieldRule), str: []const u8) !void {
     22    var lineit = std.mem.tokenize(u8, str, "\n");
     23    while (lineit.next()) |line| {
     24        const sep = try assert(usize, std.mem.indexOf(u8, line, ": "));
     25        if (sep == line.len - 1) return aoc.Error.InvalidInput;
     26        const name = line[0..sep];
     27        var rangepart = line[sep + 2 ..];
     28        var spaceit = std.mem.tokenize(u8, rangepart, " ");
     29        const r1 = try parseRange(try assert([]const u8, spaceit.next()));
     30        _ = spaceit.next();
     31        const r2 = try parseRange(try assert([]const u8, spaceit.next()));
     32        try rules.append(FieldRule{ .name = name, .r1 = r1, .r2 = r2 });
     33    }
     34}
     35
     36fn parseVals(vals: *std.ArrayList(u32), str: []const u8) !void {
     37    var lineit = std.mem.tokenize(u8, str, "\n");
     38    while (lineit.next()) |line| {
     39        var partit = std.mem.tokenize(u8, line, ",");
     40        while (partit.next()) |part| {
     41            try vals.append(try std.fmt.parseInt(u32, part, 10));
     42        }
     43    }
     44}
     45
     46fn matchesRule(rule: FieldRule, v: u32) bool {
     47    return (v >= rule.r1.min and v <= rule.r1.max or v >= rule.r2.min and v <= rule.r2.max);
     48}
     49
     50fn hasRule(rules: []FieldRule, v: u32) bool {
     51    for (rules) |r| {
     52        if (matchesRule(r, v)) return true;
     53    }
     54    return false;
     55}
     56
     57fn printCandidates(candidates: []u1, rulecount: usize, remove: usize) void {
     58    var i: u32 = 0;
     59    while (i < rulecount) : (i += 1) {
     60        for (candidates[i * rulecount .. (i + 1) * rulecount]) |c| {
     61            aoc.debugfmt("{} ", .{c});
     62        }
     63        if (i == remove) aoc.debugfmt(" <<<", .{});
     64        aoc.debugfmt("\n", .{});
     65    }
     66}
     67
     68fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
     69    _ = args;
     70
     71    var answer: u32 = 0;
     72
     73    var rules = std.ArrayList(FieldRule).init(allocator);
     74    defer rules.deinit();
     75
     76    var othervals = std.ArrayList(u32).init(allocator);
     77    defer othervals.deinit();
     78
     79    var secit = std.mem.split(u8, input, "\n\n");
     80    try parseRules(&rules, try assert([]const u8, secit.next()));
     81    _ = secit.next();
     82    try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]);
     83
     84    for (othervals.items) |v| {
     85        if (!hasRule(rules.items, v)) answer += v;
     86    }
     87
     88    return try std.fmt.allocPrint(allocator, "{}", .{answer});
     89}
     90
     91fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
     92    _ = args;
     93
     94    var rules = std.ArrayList(FieldRule).init(allocator);
     95    defer rules.deinit();
     96
     97    var ownvals = std.ArrayList(u32).init(allocator);
     98    defer ownvals.deinit();
     99
    100    var othervals = std.ArrayList(u32).init(allocator);
    101    defer othervals.deinit();
    102
    103    var secit = std.mem.split(u8, input, "\n\n");
    104    try parseRules(&rules, try assert([]const u8, secit.next()));
    105    try parseVals(&ownvals, (try assert([]const u8, secit.next()))[13..]);
    106    try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]);
    107
    108    const rulecount = rules.items.len;
    109
    110    {
    111        var index: u32 = 0;
    112        while (index < othervals.items.len) {
    113            var i: u32 = 0;
    114            while (i < rulecount) : (i += 1) {
    115                if (!hasRule(rules.items, othervals.items[index + i]))
    116                    break;
    117            }
    118
    119            if (i == rulecount) {
    120                index += @intCast(u32, rulecount);
    121            } else {
    122                if (aoc.debug)
    123                    aoc.debugfmt("REMOVE: ", .{});
    124                i = 0;
    125                while (i < rulecount) : (i += 1) {
    126                    if (aoc.debug)
    127                        aoc.debugfmt("{} ", .{othervals.items[index]});
    128                    _ = othervals.orderedRemove(index);
    129                }
    130                if (aoc.debug)
    131                    aoc.debugfmt("\n", .{});
    132            }
    133        }
    134    }
    135
    136    var candidates = try allocator.alloc(u1, rulecount * rulecount);
    137    defer allocator.free(candidates);
    138    std.mem.set(u1, candidates, 1);
    139
    140    if (aoc.debug)
    141        aoc.debugfmt("{}\n", .{othervals.items.len});
    142    {
    143        var index: u32 = 0;
    144        while (index < othervals.items.len) : (index += 1) {
    145            const ri = index % rulecount;
    146            const v = othervals.items[index];
    147            for (rules.items) |r, rri| {
    148                if (!matchesRule(r, v)) {
    149                    candidates[ri * rulecount + rri] = 0;
    150                }
    151            }
    152        }
    153    }
    154
    155    var answer: u64 = 1;
    156    {
    157        var index: u32 = 0;
    158        while (index < rulecount * rulecount) : (index += 1) {
    159            var ri = index % rulecount;
    160            const cc = candidates[ri * rulecount .. (ri + 1) * rulecount];
    161            if (std.mem.count(u1, cc, ([_]u1{1})[0..]) == 1) {
    162                const field = std.mem.indexOfScalar(u1, cc, 1).?;
    163                if (std.mem.indexOf(u8, rules.items[field].name, "departure") != null)
    164                    answer *= ownvals.items[ri];
    165                for (ownvals.items) |_, ii| {
    166                    candidates[ii * rulecount + field] = 0;
    167                }
    168                if (aoc.debug) {
    169                    printCandidates(candidates, rulecount, ri);
    170                    aoc.debugfmt("\n", .{});
    171                }
    172            }
    173        }
    174    }
    175
    176    return try std.fmt.allocPrint(allocator, "{}", .{answer});
    177}
    178
    179pub const main = aoc.main(part1, part2, .{ "25972", "622670335901" });