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

88 lines
2.9 KiB
Racket

#lang racket
(module+ test
(require rackunit))
(define (parse-ticket str)
(map string->number (string-split str ",")))
(define (parse-rules lst)
(for/hash ([str (in-list lst)])
(define name (car (string-split str ": ")))
(define ranges (map string->number (regexp-match* #px"\\d+" str)))
(values name
(λ (n) (or (<= (first ranges) n (second ranges))
(<= (third ranges) n (fourth ranges)))))))
(define (read-input filename)
(define in-str (file->string filename))
(define rules (parse-rules (regexp-match* #px"[\\w ]+: \\d+-\\d+ or \\d+-\\d+" in-str)))
(define my-ticket
(parse-ticket (cadr (regexp-match #px"your ticket:\n([\\d,]+)" in-str))))
(define nearby-tickets
(map parse-ticket
(string-split
(cadr (regexp-match #px"nearby tickets:\n([\\d,\n]+)" in-str)))))
(values rules my-ticket nearby-tickets))
(define (part1 filename)
(define-values (rules my-ticket nearby-tickets) (read-input filename))
(define invalid-values
(for*/list ([ticket (in-list nearby-tickets)]
[val (in-list ticket)]
#:when (for/and ([(name rule-proc) (in-hash rules)])
(not (rule-proc val))))
val))
(apply + invalid-values))
(module+ test
(check-equal? (part1 "test1") 71))
(module+ main
(displayln (part1 "input")))
(define ((valid? rules) ticket)
(for/and ([val (in-list ticket)])
(for/or ([(name rule-proc) (in-hash rules)])
(rule-proc val))))
(define (field-positions h)
(if (for/and ([(k v) (in-hash h)]) (= 1 (length v)))
(for/hash ([(k v) (in-hash h)]) (values k (car v)))
(begin
(for ([(name lst) (in-hash h)]
#:when (= 1 (length lst)))
(for ([(other-name other-lst) (in-hash h)]
#:unless (equal? other-name name))
(hash-set! h other-name (remove (car lst) other-lst))))
(field-positions h))))
(define (determine-ticket filename)
(define-values (rules my-ticket nearby-tickets) (read-input filename))
(define valid-tickets (filter (valid? rules) nearby-tickets))
(define h (make-hash))
(for ([(name rule-proc) (in-hash rules)])
(hash-set! h name (range (length my-ticket))))
(for ([(name rule-proc) (in-hash rules)]
#:when #t
[ticket (in-list valid-tickets)]
#:when #t
[val (in-list ticket)]
[i (in-naturals)]
#:when (not (rule-proc val)))
(hash-update! h name (λ (lst) (remove i lst =))))
(define positions (field-positions h))
(for/hash ([(name pos) (in-hash positions)])
(values name (list-ref my-ticket pos))))
(module+ test
(check-equal? (determine-ticket "test2") (hash "class" 12 "row" 11 "seat" 13)))
(define (part2 filename)
(define ticket (determine-ticket filename))
(apply * (for/list ([(name val) (in-hash ticket)]
#:when (string-prefix? name "departure"))
val)))
(module+ main
(displayln (part2 "input")))