60 lines
1.9 KiB
Racket
60 lines
1.9 KiB
Racket
#lang curly-fn racket
|
|
|
|
(require "../lib.rkt")
|
|
|
|
(define (parse-rule rule)
|
|
(match rule
|
|
[(regexp #px"(\\d+): (.+)" (list _ rule alts))
|
|
(cons (string->number rule)
|
|
(~>> alts
|
|
(string-replace _ "|" ")(")
|
|
(format "((~a))")
|
|
open-input-string
|
|
read))]))
|
|
|
|
(define-values (rules msgs)
|
|
(match-let ([(list rules msgs) (problem-input-grouped 19)])
|
|
(values (make-hash (map parse-rule (string-lines rules)))
|
|
(string-lines msgs))))
|
|
|
|
(define (ruleset start)
|
|
(list->set
|
|
;; loop: number? -> (listof string?)
|
|
(let loop ([rule start])
|
|
(apply append
|
|
(map #{match %
|
|
[`(,l) #:when (string? l) %]
|
|
[`(,rs ...) (map #{apply string-append %}
|
|
(apply cartesian-product
|
|
(map #{loop %} rs)))]}
|
|
(hash-ref rules rule))))))
|
|
|
|
(define rule42 (ruleset 42))
|
|
(define rule31 (ruleset 31))
|
|
(define len (string-length (set-first rule42)))
|
|
|
|
(define (string-group len str)
|
|
(for/list ([group (/ (string-length str) len)])
|
|
(substring str (* group len) (* (add1 group) len))))
|
|
|
|
(define (matches-rules-1 str)
|
|
(and (= (string-length str) (* 3 len))
|
|
(let ([strs (string-group len str)])
|
|
(and (set-member? rule42 (first strs))
|
|
(set-member? rule42 (second strs))
|
|
(set-member? rule31 (third strs))))))
|
|
|
|
(define (matches-rules-2 str)
|
|
(and (zero? (remainder (string-length str) len))
|
|
(let* ([strs (string-group len str)]
|
|
[count (length strs)])
|
|
(for/or ([c (in-range (add1 (floor (/ count 2))) count)])
|
|
(and (andmap #{set-member? rule42 %} (take strs c))
|
|
(andmap #{set-member? rule31 %} (drop strs c)))))))
|
|
|
|
(define-values (part1 part2)
|
|
(values (count #{matches-rules-1 %} msgs)
|
|
(count #{matches-rules-2 %} msgs)))
|
|
|
|
(show-solution part1 part2)
|