Refactored Day 4.
This commit is contained in:
parent
1203dc4a1d
commit
27f527a3cb
34
lib.rkt
34
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
|
||||
|
|
103
src/04.rkt
103
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)
|
||||
|
|
Loading…
Reference in New Issue