From ee339873c617b02108026fc414ed20950d5b0f01 Mon Sep 17 00:00:00 2001 From: Jonathan Chan Date: Fri, 4 Dec 2020 12:48:29 -0800 Subject: [PATCH] Refactored Day 4. --- lib.rkt | 34 ++++++++++++++++-- src/04.rkt | 103 ++++++++++++++++++++++++----------------------------- 2 files changed, 78 insertions(+), 59 deletions(-) diff --git a/lib.rkt b/lib.rkt index 081ce35..85ea3ef 100644 --- a/lib.rkt +++ b/lib.rkt @@ -21,12 +21,19 @@ show-vector-grid show-hash-grid - ∘ ∂ $ % + ∘ ∂ ∂r $ % uncurry + apply* + apply-when + + string->number* + string->symbol* + + nchar=? + char-alphanumeric? sum - != nchar=? - char-alphanumeric? + != nzero? negate pos-or-zero @@ -54,12 +61,22 @@ ;; Function helpers ;; (define ∘ compose) (define ∂ curry) +(define ∂r curryr) ;; uncurry : (a1 -> ... -> an -> b) -> ((listof a) -> b) (define uncurry (curry apply)) (define $ uncurry) +;; apply* : (a -> b) -> a -> b +(define (apply* f a) + (f a)) + +;; apply-when : a -> (a -> b) -> b +;; Apply given function only when a is not #f; return #f otherwise +(define (apply-when p f) + (and p (f p))) + ;; IO helpers ;; @@ -137,6 +154,17 @@ (show-vector-grid char-hash (hash->vectors hash-grid default))) +;; Conversion helpers ;; + +;; string->number* : (or/c string? #f) -> (or/c number? #f) +(define (string->number* s) + (and (string? s) (string->number s))) + +;; string->symbol* : (or/c string? #f) -> (or/c symbol? #f) +(define (string->symbol* s) + (and (string? s) (string->symbol s))) + + ;; Char helpers ;; ;; nchar=? : char -> char -> boolean diff --git a/src/04.rkt b/src/04.rkt index 7573678..25dc218 100644 --- a/src/04.rkt +++ b/src/04.rkt @@ -19,65 +19,56 @@ hgt:179cm hcl:#cfa07d eyr:2025 pid:166559648 iyr:2011 ecl:brn hgt:59in") -(define fields '(byr iyr eyr hgt hcl ecl pid)) ;; except 'cid -(define ecls '(amb blu brn gry grn hzl oth)) +(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 (passports in) - (define (interp-value field value-string) - (match field - ['byr (string->number value-string)] - ['iyr (string->number value-string)] - ['eyr (string->number value-string)] - ['hgt (cond - [(string-suffix? value-string "in") - (cons 'in (string->number (string-trim value-string "in")))] - [(string-suffix? value-string "cm") - (cons 'cm (string->number (string-trim value-string "cm")))] - [else (cons 'na (string->number value-string))])] - ['hcl (string->list value-string)] - ['ecl (string->symbol value-string)] - ['pid (string->list value-string)] - ['cid value-string])) - (let* ([passport-strings (map (λ (p) (string-replace p "\n" " ")) + (let* ([passport-entries (map (compose + (∂ map (compose + (∂ map ∂ (list string->symbol identity)) + (∂r string-split ":"))) + (∂r string-split " ") + (∂r string-replace "\n" " ")) (string-split in "\n\n"))] - [passport-entries (map (λ (p) (map (curryr string-split ":") - (string-split p " "))) - passport-strings)] - [passport-hashes (map (λ (p) - (for/hash ([entry p]) - (let* ([field (string->symbol (first entry))] - [value (interp-value field (second entry))]) - (values field value)))) - passport-entries)]) - passport-hashes)) + [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)))) -(define part1 - (count (λ (p) (andmap (∂ hash-has-key? p) fields)) - (passports input))) - -(define part2 - (count - (λ (p) - (and (andmap (∂ hash-has-key? p) fields) - (match-let ([byr (hash-ref p 'byr)] - [iyr (hash-ref p 'iyr)] - [eyr (hash-ref p 'eyr)] - [`(,unit . ,hgt) (hash-ref p 'hgt)] - [`(,hash ,hex ...) (hash-ref p 'hcl)] - [ecl (hash-ref p 'ecl)] - [pid (hash-ref p 'pid)]) - (and (<= 1920 byr 2002) - (<= 2010 iyr 2020) - (<= 2020 eyr 2030) - (match unit - ['cm (<= 150 hgt 193)] - ['in (<= 59 hgt 76)] - [else #f]) - (char=? #\# hash) - (= (length hex) 6) - (andmap (curry char-alphanumeric?) hex) - (member ecl ecls) - (= (length pid) 9))))) - (passports input))) +(define-values (part1 part2) + (passports input)) (show-solution part1 part2)