advent-of-code/2020/day04/day04.rkt
2024-11-12 21:46:18 +01:00

99 lines
2.6 KiB
Racket

#lang racket
(module+ test
(require rackunit))
(module+ main
(displayln "Day 4"))
(define (parse-passport str)
(define fields (string-split str #px"\\s+"))
(for/hash ([f fields])
(apply values (string-split f ":"))))
(define (read-input filename)
(define passports-str (string-split (file->string filename) "\n\n"))
(map parse-passport passports-str))
(define (valid? passport)
(for/and ([key '("byr" "iyr" "eyr" "hgt" "hcl" "ecl" "pid")])
(hash-has-key? passport key)))
(define (part1 filename)
(define passports (read-input filename))
(length (filter valid? passports)))
(module+ test
(check-equal? (part1 "test") 2))
(module+ main
(displayln (part1 "input")))
(define (byr-valid? v)
(<= 1920 (string->number v) 2002))
(module+ test
(check-pred byr-valid? "2002")
(check-pred (negate byr-valid?) "2003"))
(define (iyr-valid? v)
(<= 2010 (string->number v) 2020))
(define (eyr-valid? v)
(<= 2020 (string->number v) 2030))
(define (hgt-valid? v)
(cond
[(string-suffix? v "cm") (<= 150 (string->number (string-trim v "cm")) 193)]
[(string-suffix? v "in") (<= 59 (string->number (string-trim v "in")) 76)]
[else #f]))
(module+ test
(check-pred hgt-valid? "60in")
(check-pred hgt-valid? "190cm")
(check-pred (negate hgt-valid?) "190in")
(check-pred (negate hgt-valid?) "190"))
(define (hcl-valid? v)
(regexp-match-exact? #px"#[0-9a-f]{6}" v))
(module+ test
(check-pred hcl-valid? "#123abc")
(check-pred (negate hcl-valid?) "#123abz")
(check-pred (negate hcl-valid?) "123abc"))
(define (ecl-valid? v)
(member v '("amb" "blu" "brn" "gry" "grn" "hzl" "oth")))
(module+ test
(check-pred ecl-valid? "brn")
(check-pred (negate ecl-valid?) "wat"))
(define (pid-valid? v)
(regexp-match-exact? #px"[0-9]{9}" v))
(module+ test
(check-pred pid-valid? "000000001")
(check-pred (negate pid-valid?) "0123456789"))
(define (strict-valid? passport)
(and (for/and ([key '("byr" "iyr" "eyr" "hgt" "hcl" "ecl" "pid")])
(hash-has-key? passport key))
(byr-valid? (hash-ref passport "byr"))
(iyr-valid? (hash-ref passport "iyr"))
(eyr-valid? (hash-ref passport "eyr"))
(hgt-valid? (hash-ref passport "hgt"))
(hcl-valid? (hash-ref passport "hcl"))
(ecl-valid? (hash-ref passport "ecl"))
(pid-valid? (hash-ref passport "pid"))))
(define (part2 filename)
(define passports (read-input filename))
(length (filter strict-valid? passports)))
(module+ test
(check-equal? (part2 "valid") 4)
(check-equal? (part2 "invalid") 0))
(module+ main
(displayln (part2 "input")))