53 lines
2.2 KiB
Racket
53 lines
2.2 KiB
Racket
#lang racket
|
|
|
|
(require "../lib.rkt")
|
|
|
|
(define input (problem-input-grouped 4))
|
|
|
|
(struct passport
|
|
(byr iyr eyr hgt hcl ecl pid cid)
|
|
#:transparent)
|
|
|
|
(define default-passport
|
|
(passport #f #f #f #f #f #f #f #f))
|
|
|
|
(define (passport-set entry pass)
|
|
(let ([value (second entry)])
|
|
(match (first entry)
|
|
['byr (struct-copy passport pass [byr value])]
|
|
['iyr (struct-copy passport pass [iyr value])]
|
|
['eyr (struct-copy passport pass [eyr value])]
|
|
['hgt (struct-copy passport pass [hgt value])]
|
|
['hcl (struct-copy passport pass [hcl value])]
|
|
['ecl (struct-copy passport pass [ecl value])]
|
|
['pid (struct-copy passport pass [pid value])]
|
|
['cid (struct-copy passport pass [cid value])]
|
|
[else pass])))
|
|
|
|
(define (hgt? str)
|
|
(match str
|
|
[(regexp #px"^(\\d{3})cm$" (list _ hgt)) (<= 150 (string->number hgt) 193)]
|
|
[(regexp #px"^(\\d{2})in$" (list _ hgt)) (<= 59 (string->number hgt) 76)]
|
|
[_ #f]))
|
|
|
|
(define-values (part1 part2)
|
|
(let* ([passport-entries (map (λ~>> (string-split _ #px"[ \n]")
|
|
(map (match-lambda [(regexp #rx"(.+):(.+)" (list _ field value))
|
|
(list (string->symbol field) value)])))
|
|
input)]
|
|
[passports (map (∂ foldl passport-set default-passport) passport-entries)]
|
|
[valid-raw? (struct/c passport string? string? string? string? string? string? string? any/c)]
|
|
[valid? (struct/c passport
|
|
(and/c string? (∘ (integer-in 1920 2002) string->number))
|
|
(and/c string? (∘ (integer-in 2010 2020) string->number))
|
|
(and/c string? (∘ (integer-in 2020 2030) string->number))
|
|
hgt?
|
|
(and/c string? (∂ regexp-match-exact? #px"#[[:xdigit:]]{6}"))
|
|
(apply or/c '("amb" "blu" "brn" "gry" "grn" "hzl" "oth"))
|
|
(and/c string? (∂ regexp-match-exact? #px"\\d{9}"))
|
|
any/c)])
|
|
(values (count valid-raw? passports)
|
|
(count valid? passports))))
|
|
|
|
(show-solution part1 part2)
|