aboutsummaryrefslogtreecommitdiff
path: root/2020/day4.raku
diff options
context:
space:
mode:
Diffstat (limited to '2020/day4.raku')
-rw-r--r--2020/day4.raku146
1 files changed, 146 insertions, 0 deletions
diff --git a/2020/day4.raku b/2020/day4.raku
new file mode 100644
index 0000000..1790de4
--- /dev/null
+++ b/2020/day4.raku
@@ -0,0 +1,146 @@
+#!/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 = <byr iyr eyr hgt hcl ecl pid>;
+
+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/$<height> = [\d+] $<unit> = [ cm || in ]/ {
+ if $<unit> eq 'cm' { return 150 <= $<height> <= 193 }
+ else { return 59 <= $<height> <= 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<byr>('2002'), 'valid';
+ nok %validations<byr>('2003'), 'invalid';
+ };
+ subtest 'hgt', {
+ ok %validations<hgt>('60in'), 'valid in';
+ ok %validations<hgt>('190cm'), 'valid cm';
+ nok %validations<hgt>('190in'), 'invalid in';
+ nok %validations<hgt>('190'), 'invalid';
+ };
+ subtest 'hcl', {
+ ok %validations<hcl>('#123abc'), 'valid';
+ nok %validations<hcl>('#123abz'), 'invalid';
+ nok %validations<hcl>('123abc'), 'missing #';
+ };
+ subtest 'ecl', {
+ ok %validations<ecl>('brn'), 'valid';
+ nok %validations<ecl>('wat'), 'invalid';
+ }
+ subtest 'pid', {
+ ok %validations<pid>('000000001'), 'valid';
+ nok %validations<pid>('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";
+ }
+
+ }
+ }
+}