aboutsummaryrefslogtreecommitdiffstats
path: root/src/04/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/04/main.zig')
-rw-r--r--src/04/main.zig108
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" });