const std = @import("std"); const Str = []const u8; const PATH = "input/day04.txt"; pub fn first(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; const file = @embedFile(PATH); var lines = std.mem.split(u8, file, "\n"); var counter: usize = 0; var passport_bits: u7 = 0; while (lines.next()) |line| { if (std.mem.eql(u8, line, "")) { if (passport_bits == 0b1111111) counter += 1; passport_bits = 0; // new passport, zeroing checked bits } else { var items = std.mem.tokenize(u8, line, " "); while (items.next()) |item| { var parts = std.mem.tokenize(u8, item, ":"); const field = parts.next().?; if (std.mem.eql(u8, field, "byr")) { passport_bits |= 1 << 0; } else if (std.mem.eql(u8, field, "iyr")) { passport_bits |= 1 << 1; } else if (std.mem.eql(u8, field, "eyr")) { passport_bits |= 1 << 2; } else if (std.mem.eql(u8, field, "hgt")) { passport_bits |= 1 << 3; } else if (std.mem.eql(u8, field, "hcl")) { passport_bits |= 1 << 4; } else if (std.mem.eql(u8, field, "ecl")) { passport_bits |= 1 << 5; } else if (std.mem.eql(u8, field, "pid")) { passport_bits |= 1 << 6; } else if (std.mem.eql(u8, field, "cid")) { // does not matter } else { unreachable; } } } } return counter; } pub fn second(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; const file = @embedFile(PATH); var lines = std.mem.split(u8, file, "\n"); var counter: usize = 0; var passport_bits: u7 = 0; while (lines.next()) |line| { if (std.mem.eql(u8, line, "")) { if (passport_bits == 0b1111111) counter += 1; passport_bits = 0; // new passport, zeroing checked bits } else { var items = std.mem.tokenize(u8, line, " "); items: while (items.next()) |item| { var parts = std.mem.tokenize(u8, item, ":"); const field = parts.next().?; if (std.mem.eql(u8, field, "byr")) { const byr = try std.fmt.parseUnsigned(usize, parts.next().?, 0); if (byr >= 1920 and byr <= 2002) passport_bits |= 1 << 0; } else if (std.mem.eql(u8, field, "iyr")) { const iyr = try std.fmt.parseUnsigned(usize, parts.next().?, 0); if (iyr >= 2010 and iyr <= 2020) passport_bits |= 1 << 1; } else if (std.mem.eql(u8, field, "eyr")) { const eyr = try std.fmt.parseUnsigned(usize, parts.next().?, 0); if (eyr >= 2020 and eyr <= 2030) passport_bits |= 1 << 2; } else if (std.mem.eql(u8, field, "hgt")) { var hgt = parts.next().?; if (std.mem.endsWith(u8, hgt, "cm")) { hgt = hgt[0 .. hgt.len - 2]; const val = try std.fmt.parseUnsigned(usize, hgt, 0); if (val >= 150 and val <= 193) passport_bits |= 1 << 3; } else if (std.mem.endsWith(u8, hgt, "in")) { hgt = hgt[0 .. hgt.len - 2]; const val = try std.fmt.parseUnsigned(usize, hgt, 0); if (val >= 59 and val <= 76) passport_bits |= 1 << 3; } else { // do nothing => invalid } } else if (std.mem.eql(u8, field, "hcl")) { var hcl = parts.next().?; if (hcl[0] == '#') hcl = hcl[1..] else continue; if (hcl.len != 6) continue; for (hcl) |ch| { if (!(ch >= 48 and ch <= 57) and !(ch >= 97 and ch <= 102)) continue :items; } passport_bits |= 1 << 4; } else if (std.mem.eql(u8, field, "ecl")) { const ecl = parts.next().?; for ([_]Str{ "amb", "blu", "brn", "gry", "grn", "hzl", "oth" }) |eye_color| { if (std.mem.eql(u8, ecl, eye_color)) { passport_bits |= 1 << 5; continue :items; } } } else if (std.mem.eql(u8, field, "pid")) { const pid = parts.next().?; if (pid.len != 9) continue; for (pid) |ch| { if (ch < 48 or ch > 57) continue :items; } passport_bits |= 1 << 6; } else if (std.mem.eql(u8, field, "cid")) { // does not matter } else { unreachable; } } } } return counter; } test "day04a" { try std.testing.expectEqual(@as(usize, 235), try first(std.testing.allocator)); } test "day04b" { try std.testing.expectEqual(@as(usize, 194), try second(std.testing.allocator)); }