main.zig (3350B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4fn intChecker( 5 comptime min: u32, 6 comptime max: u32, 7 comptime len: ?u32, 8 comptime suffix: ?[]const u8, 9) fn ([]const u8) bool { 10 const impl = struct { 11 fn check(input: []const u8) bool { 12 var parsed = input; 13 if (suffix) |suf| { 14 if (!std.mem.eql(u8, suf, input[(input.len - suf.len)..])) 15 return false; 16 parsed = input[0..(input.len - suf.len)]; 17 } 18 if (len != null and parsed.len != len.?) 19 return false; 20 const val = std.fmt.parseInt(u32, parsed, 10) catch { 21 return false; 22 }; 23 return (val >= min and val <= max); 24 } 25 }; 26 return impl.check; 27} 28 29fn combineOr( 30 comptime f1: fn ([]const u8) bool, 31 comptime f2: fn ([]const u8) bool, 32) fn ([]const u8) bool { 33 const impl = struct { 34 fn check(input: []const u8) bool { 35 return f1(input) or f2(input); 36 } 37 }; 38 return impl.check; 39} 40 41fn isColorStr(input: []const u8) bool { 42 if (input.len != 7) return false; 43 _ = std.fmt.parseInt(u32, input[1..], 16) catch { 44 return false; 45 }; 46 return input[0] == '#'; 47} 48 49fn isEyeColor(input: []const u8) bool { 50 const valids = "amb blu brn gry grn hzl oth"; 51 return std.mem.indexOf(u8, valids[0..], input) != null; 52} 53 54fn countValids(input: []u8, validate: bool) !u16 { 55 var entryit = std.mem.split(u8, input, "\n\n"); 56 const required_keys = [_][]const u8{ "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", "cid" }; 57 const validation_funcs = [required_keys.len]?*const fn ([]const u8) bool{ 58 intChecker(1920, 2002, 4, null), 59 intChecker(2010, 2020, 4, null), 60 intChecker(2020, 2030, 4, null), 61 combineOr(intChecker(150, 193, 3, "cm"), intChecker(59, 76, 2, "in")), 62 isColorStr, 63 isEyeColor, 64 intChecker(0, 999999999, 9, null), 65 null, 66 }; 67 var count: u16 = 0; 68 entryloop: while (entryit.next()) |entry| { 69 const key_mask = [required_keys.len]u8{ 1, 1, 1, 1, 1, 1, 1, 'X' }; 70 var present = [required_keys.len]u1{ 0, 0, 0, 0, 0, 0, 0, 0 }; 71 var partit = std.mem.tokenize(u8, entry, ": \n"); 72 while (partit.next()) |key| { 73 const value = partit.next().?; 74 for (required_keys) |ckey, i| { 75 if (std.mem.eql(u8, key, ckey)) { 76 if (validate and validation_funcs[i] != null) { 77 if (!validation_funcs[i].?(value)) continue :entryloop; 78 } 79 present[i] = 1; 80 } 81 } 82 } 83 for (key_mask) |k, i| { 84 if (k != 'X' and present[i] != k) 85 continue :entryloop; 86 } 87 count += 1; 88 } 89 return count; 90} 91 92fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 93 _ = args; 94 95 const answer = try countValids(input, false); 96 97 return try std.fmt.allocPrint(allocator, "{d}", .{answer}); 98} 99 100fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 101 _ = args; 102 103 const answer = try countValids(input, true); 104 105 return try std.fmt.allocPrint(allocator, "{d}", .{answer}); 106} 107 108pub const main = aoc.main(part1, part2, .{ "226", "160" });