diff options
Diffstat (limited to 'src/04/main.zig')
| -rw-r--r-- | src/04/main.zig | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/04/main.zig b/src/04/main.zig new file mode 100644 index 0000000..e2a860d --- /dev/null +++ b/src/04/main.zig @@ -0,0 +1,108 @@ +const std = @import("std"); +const aoc = @import("aoc"); + +fn intChecker( + comptime min: u32, + comptime max: u32, + comptime len: ?u32, + comptime suffix: ?[]const u8, +) fn ([]const u8) bool { + const impl = struct { + fn check(input: []const u8) bool { + var parsed = input; + if (suffix) |suf| { + if (!std.mem.eql(u8, suf, input[(input.len - suf.len)..])) + return false; + parsed = input[0..(input.len - suf.len)]; + } + if (len != null and parsed.len != len.?) + return false; + const val = std.fmt.parseInt(u32, parsed, 10) catch { + return false; + }; + return (val >= min and val <= max); + } + }; + return impl.check; +} + +fn combineOr( + comptime f1: fn ([]const u8) bool, + comptime f2: fn ([]const u8) bool, +) fn ([]const u8) bool { + const impl = struct { + fn check(input: []const u8) bool { + return f1(input) or f2(input); + } + }; + return impl.check; +} + +fn isColorStr(input: []const u8) bool { + if (input.len != 7) return false; + _ = std.fmt.parseInt(u32, input[1..], 16) catch { + return false; + }; + return input[0] == '#'; +} + +fn isEyeColor(input: []const u8) bool { + const valids = "amb blu brn gry grn hzl oth"; + return std.mem.indexOf(u8, valids[0..], input) != null; +} + +fn countValids(input: []u8, validate: bool) !u16 { + var entryit = std.mem.split(u8, input, "\n\n"); + const required_keys = [_][]const u8{ "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", "cid" }; + const validation_funcs = [required_keys.len]?*const fn ([]const u8) bool{ + intChecker(1920, 2002, 4, null), + intChecker(2010, 2020, 4, null), + intChecker(2020, 2030, 4, null), + combineOr(intChecker(150, 193, 3, "cm"), intChecker(59, 76, 2, "in")), + isColorStr, + isEyeColor, + intChecker(0, 999999999, 9, null), + null, + }; + var count: u16 = 0; + entryloop: while (entryit.next()) |entry| { + const key_mask = [required_keys.len]u8{ 1, 1, 1, 1, 1, 1, 1, 'X' }; + var present = [required_keys.len]u1{ 0, 0, 0, 0, 0, 0, 0, 0 }; + var partit = std.mem.tokenize(u8, entry, ": \n"); + while (partit.next()) |key| { + const value = partit.next().?; + for (required_keys) |ckey, i| { + if (std.mem.eql(u8, key, ckey)) { + if (validate and validation_funcs[i] != null) { + if (!validation_funcs[i].?(value)) continue :entryloop; + } + present[i] = 1; + } + } + } + for (key_mask) |k, i| { + if (k != 'X' and present[i] != k) + continue :entryloop; + } + count += 1; + } + return count; +} + +fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { + _ = args; + + const answer = try countValids(input, false); + + return try std.fmt.allocPrint(allocator, "{d}", .{answer}); +} + +fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { + _ = args; + + const answer = try countValids(input, true); + + return try std.fmt.allocPrint(allocator, "{d}", .{answer}); +} + +pub const main = aoc.main(part1, part2, .{ "226", "160" }); |
