diff --git a/4.rkt b/4.rkt index d5139dc..77932fc 100644 --- a/4.rkt +++ b/4.rkt @@ -5,79 +5,51 @@ ;; solution for day 4 ;; helper functions here -(struct passport [byr iyr eyr hgt hcl ecl pid cid] #:transparent) +(define-simple-macro (magic-struct name:id fld:id ...+) + #:with fld-names (format-id #'name "~a-fields" #'name) + (begin (struct name [fld ...] #:transparent) + (define fld-names (map symbol->string '(fld ...))))) + +(magic-struct passport byr iyr eyr hgt hcl ecl pid cid) + +(define (string->passport str) + (define pp (make-vector 8 #f)) + (for ([part (in-list (string-split str))]) + (match-define (list name val) (string-split part ":")) + (vector-set! pp (index-of passport-fields name) val)) + (apply passport (vector->list pp))) + +(define pp-valid-part1? + (struct/c passport string? string? string? string? string? string? string? any/c)) (define (part1 input) - (define pp-valid? - (struct/c passport string? string? string? string? string? string? string? any/c)) - (for/sum ([pp (in-list input)] #:when (pp-valid? pp)) 1)) + (stream-count pp-valid-part1? (in-list input))) + +(define (strlen/c num) (compose (=/c num) string-length)) +(define (string-integer-in low high) (compose (integer-in low high) string->number)) +(define (height/c hs) + (match hs + [(pregexp #px"([0-9]+)cm" (list _ h)) ((string-integer-in 150 193) h)] + [(pregexp #px"([0-9]+)in" (list _ h)) ((string-integer-in 59 76) h)] + [_ #f])) + +(define pp-valid-part2? + (and/c pp-valid-part1? + (struct/c passport + (and/c (strlen/c 4) (string-integer-in 1920 2002)) + (and/c (strlen/c 4) (string-integer-in 2010 2020)) + (and/c (strlen/c 4) (string-integer-in 2020 2030)) + height/c + (curry regexp-match #px"#[0-9a-f]{6}") + (or/c "amb" "blu" "brn" "gry" "grn" "hzl" "oth") + (and/c (strlen/c 9) (string-integer-in 0 999999999)) + any/c))) (define (part2 input) - (define ((strlen/c num) str) - (= (string-length str) num)) - - (define ((strnum-range/c low high) s) - (define sn (string->number s)) - (and (number? sn) - (<= low sn high))) - - (define (height/c hs) - (match hs - [(pregexp #px"([0-9]+)cm" (list _ h)) ((strnum-range/c 150 193) h)] - [(pregexp #px"([0-9]+)in" (list _ h)) ((strnum-range/c 59 76) h)] - [_ #f])) - - (define (hcolor/c cs) - (match cs - [(pregexp #px"#[0-9a-f]{6}") #t] - [_ #f])) - - (define (ecolor/c cs) - (match cs - [(or "amb" "blu" "brn" "gry" "grn" "hzl" "oth") #t] - [_ #f])) - - (define pp-valid? - (struct/c passport - (and/c string? (strlen/c 4) (strnum-range/c 1920 2002)) - (and/c string? (strlen/c 4) (strnum-range/c 2010 2020)) - (and/c string? (strlen/c 4) (strnum-range/c 2020 2030)) - (and/c string? height/c) - (and/c string? hcolor/c) - (and/c string? ecolor/c) - (and/c string? (strlen/c 9) (strnum-range/c 0 999999999)) - any/c)) - (for/sum ([pp (in-list input)] #:when (pp-valid? pp)) 1)) - -(module+ test - (require rackunit) - ;; tests here - (displayln "no tests :(")) + (stream-count pp-valid-part2? (in-list input))) (module+ main - (define input-lines (file->lines "inputs/4")) - - (define input - (for/fold ([input (list (passport #f #f #f #f #f #f #f #f))]) ([line (in-list input-lines)]) - (define pp (first input)) - (cond - [(zero? (string-length line)) (cons (passport #f #f #f #f #f #f #f #f) input)] - [else - (define parts (string-split line " ")) - (define new-pp - (for/fold ([new-pp pp]) ([part (in-list parts)]) - (match-define (list name val) (string-split part ":")) - (match name - ["byr" (struct-copy passport new-pp [byr val])] - ["iyr" (struct-copy passport new-pp [iyr val])] - ["eyr" (struct-copy passport new-pp [eyr val])] - ["hgt" (struct-copy passport new-pp [hgt val])] - ["hcl" (struct-copy passport new-pp [hcl val])] - ["ecl" (struct-copy passport new-pp [ecl val])] - ["pid" (struct-copy passport new-pp [pid val])] - ["cid" (struct-copy passport new-pp [cid val])] - [_ (error "not shonks" line name val)]))) - (cons new-pp (rest input))]))) + (define input (map string->passport (string-split (file->string "inputs/4") "\n\n"))) ;; part 1 (answer 4 1 (part1 input))