#!/usr/bin/env raku constant \EXAMPLE = q:to/END/; ecl:gry pid:860033327 eyr:2020 hcl:#fffffd byr:1937 iyr:2017 cid:147 hgt:183cm iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884 hcl:#cfa07d byr:1929 hcl:#ae17e1 iyr:2013 eyr:2024 ecl:brn pid:760753108 byr:1931 hgt:179cm hcl:#cfa07d eyr:2025 pid:166559648 iyr:2011 ecl:brn hgt:59in END constant \required-keys = ; sub split-input($input) { $input.split: /^^$$/; } sub valid-passport($passport --> Bool) { [&&] required-keys.map({ $passport.contains($_) }) } sub valid-passports($input) { split-input($input).grep(*.&valid-passport) } # Data Validation my %validations = ( byr => sub ($v) { 1920 <= $v <= 2002 }, iyr => sub ($v) { 2010 <= $v <= 2020 }, eyr => sub ($v) { 2020 <= $v <= 2030 }, hgt => sub ($v) { if $v ~~ m/$ = [\d+] $ = [ cm || in ]/ { if $ eq 'cm' { return 150 <= $ <= 193 } else { return 59 <= $ <= 76 } } False }, hcl => sub ($v) { so $v ~~ m/'#' <[0..9 a..f]> ** 6/ }, ecl => sub ($v) { so $v ~~ m/amb || blu || brn || gry || grn || hzl || oth/ }, pid => sub ($v) { so $v ~~ m/^^\d ** 9 $$/ }, cid => { True } ); sub data-validation($passport) { [&&] $passport.words».split(':').map( -> ($k, $v) { %validations{$k}($v) } ) } multi sub MAIN('part1', $file) { say valid-passports(slurp($file)).elems; } multi sub MAIN('part2', $file) { say +valid-passports(slurp($file)).grep({ $_.&data-validation}) } multi sub MAIN('test') { use Test; subtest 'Part1', { is split-input(EXAMPLE).elems, 4, 'length'; ok valid-passport(split-input(EXAMPLE)[0]), 'first input'; nok valid-passport(split-input(EXAMPLE)[1]), 'second input'; ok valid-passport(split-input(EXAMPLE)[2]), 'third input'; nok valid-passport(split-input(EXAMPLE)[3]), 'four input'; is valid-passports(EXAMPLE).elems, 2, 'validate-passports'; }; subtest 'Part 2', { subtest 'byr', { ok %validations('2002'), 'valid'; nok %validations('2003'), 'invalid'; }; subtest 'hgt', { ok %validations('60in'), 'valid in'; ok %validations('190cm'), 'valid cm'; nok %validations('190in'), 'invalid in'; nok %validations('190'), 'invalid'; }; subtest 'hcl', { ok %validations('#123abc'), 'valid'; nok %validations('#123abz'), 'invalid'; nok %validations('123abc'), 'missing #'; }; subtest 'ecl', { ok %validations('brn'), 'valid'; nok %validations('wat'), 'invalid'; } subtest 'pid', { ok %validations('000000001'), 'valid'; nok %validations('0123456789'), 'valid'; } subtest 'data validation', { my $invalid-data = q:to/END/; eyr:1972 cid:100 hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926 iyr:2019 hcl:#602927 eyr:1967 hgt:170cm ecl:grn pid:012533040 byr:1946 hcl:dab227 iyr:2012 ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277 hgt:59cm ecl:zzz eyr:2038 hcl:74454a iyr:2023 pid:3556412378 byr:2007 END for split-input($invalid-data).kv -> $i, $passport { nok data-validation($passport), "Run invalid $i"; } my $valid-data = q:to/END/; pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980 hcl:#623a2f eyr:2029 ecl:blu cid:129 byr:1989 iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm hcl:#888785 hgt:164cm byr:2001 iyr:2015 cid:88 pid:545766238 ecl:hzl eyr:2022 iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719 END for split-input($valid-data).kv -> $i, $passport { ok data-validation($passport), "Run valid $i"; } } } }