aoc-2023

My solutions in CHICKEN scheme to Advent of Code 2023
git clone https://git.instinctive.eu/aoc-2023.git
Log | Files | Refs | README | LICENSE

day19.scm (7572B)


      1 ; Copyright (c) 2023, Natacha Porté
      2 ;
      3 ; Permission to use, copy, modify, and distribute this software for any
      4 ; purpose with or without fee is hereby granted, provided that the above
      5 ; copyright notice and this permission notice appear in all copies.
      6 ;
      7 ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     10 ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     12 ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     13 ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 (import (chicken io) (chicken sort) (chicken string)
     16         comparse
     17         srfi-1
     18         srfi-14
     19         srfi-69)
     20 
     21 ;;;;;;;;;;;;;;;;;
     22 ;; Input parsing
     23 
     24 (define (as-number parser)
     25   (bind (as-string parser)
     26         (lambda (s)
     27           (result (string->number s)))))
     28 
     29 (define spaces
     30   (one-or-more (is #\space)))
     31 
     32 (define digit
     33   (in char-set:digit))
     34 
     35 (define digits
     36   (as-number (one-or-more digit)))
     37 
     38 (define state-name
     39   (as-string (one-or-more (in char-set:letter))))
     40 
     41 (define category-name
     42   (in #\x #\m #\a #\s))
     43 
     44 (define category-assoc
     45   (sequence* ((name category-name)
     46               (_ (is #\=))
     47               (value digits))
     48     (result (list name value))))
     49 
     50 (define conditional-transition
     51   (sequence* ((category category-name)
     52               (operator (in #\< #\>))
     53               (value    digits)
     54               (_        (is #\:))
     55               (target   state-name))
     56     (result (list category operator value target))))
     57 
     58 (define conditional-transitions
     59   (sequence* ((first conditional-transition)
     60               (rest (zero-or-more
     61                        (preceded-by (is #\,) conditional-transition))))
     62     (result (cons first rest))))
     63 
     64 (define process-line
     65   (sequence* ((label state-name)
     66               (_ (is #\{))
     67               (transitions conditional-transitions)
     68               (_ (is #\,))
     69               (fallback state-name)
     70               (_ (char-seq "}\n")))
     71     (result (list label transitions fallback))))
     72 
     73 (define part-line
     74   (sequence* ((_ (is #\{))
     75               (first category-assoc)
     76               (rest (zero-or-more (preceded-by (is #\,) category-assoc)))
     77               (_ (char-seq "}\n")))
     78     (result (cons first rest))))
     79 
     80 (define all-data
     81   (sequence* ((processes (one-or-more process-line))
     82               (_ (is #\newline))
     83               (parts     (one-or-more part-line)))
     84     (result (list processes parts))))
     85 
     86 (define data (parse all-data (read-string)))
     87 (define verbose (< (length (cadr data)) 10))
     88 (when verbose (write-line (conc "Input: " data)))
     89 
     90 ;;;;;;;;;;;;;;;;;
     91 ;; First Puzzle
     92 
     93 (define process-hash
     94   (let ((result (make-hash-table)))
     95     (let loop ((todo (car data)))
     96       (if (null? todo)
     97           result
     98           (begin
     99             (hash-table-set! result (caar todo) (cdar todo))
    100             (loop (cdr todo)))))))
    101 
    102 (define (part-matches? condition part)
    103   (let* ((cat-name   (car   condition))
    104          (operator   (cadr  condition))
    105          (ref-value  (caddr condition))
    106          (part-value (cadr (assv cat-name part))))
    107     (case operator
    108       ((#\<) (< part-value ref-value))
    109       ((#\>) (> part-value ref-value))
    110       (else (assert #f "Unknown operator " operator)))))
    111 
    112 (define (apply-process process part)
    113   (let loop ((conds    (car  process))
    114              (fallback (cadr process)))
    115     (cond ((null? conds) fallback)
    116           ((part-matches? (car conds) part) (cadddr (car conds)))
    117           (else (loop (cdr conds) fallback)))))
    118 
    119 (define (process-part part)
    120   (let loop ((state "in"))
    121     (if (= 1 (string-length state))
    122         state
    123         (loop (apply-process (hash-table-ref process-hash state) part)))))
    124 
    125 (define (part-score part)
    126   (if (equal? (process-part part) "R")
    127       0
    128       (apply + (map cadr part))))
    129 
    130 (write-line (conc "First puzzle:  " (apply + (map part-score (cadr data)))))
    131 
    132 ;;;;;;;;;;;;;;;;;
    133 ;; Second Puzzle
    134 
    135 (define max-val 4000)
    136 (define min-val    1)
    137 
    138 (define (cut-with condition range)
    139   (let ((operator (cadr  condition))
    140         (value    (caddr condition)))
    141     (case operator
    142       ((#\<) (if (< (car range) value)
    143                  (cons (car range) (min (sub1 value) (cdr range)))
    144                  '()))
    145       ((#\>) (if (> (cdr range) value)
    146                  (cons (max (add1 value) (car range)) (cdr range))
    147                  '()))
    148       (else (assert #f "Bad condition " condition)))))
    149 
    150 (define (cut-without condition range)
    151   (let ((operator (cadr  condition))
    152         (value    (caddr condition)))
    153     (case operator
    154       ((#\>) (if (< (car range) value)
    155                  (cons (car range) (min value (cdr range)))
    156                  '()))
    157       ((#\<) (if (> (cdr range) value)
    158                  (cons (max value (car range)) (cdr range))
    159                  '()))
    160       (else (assert #f "Bad condition " condition)))))
    161 
    162 (define (cut-volume cut condition volume)
    163   (let ((x-range (car    volume))
    164         (m-range (cadr   volume))
    165         (a-range (caddr  volume))
    166         (s-range (cadddr volume)))
    167     (case (car condition)
    168       ((#\x) (list (cut condition x-range) m-range a-range s-range))
    169       ((#\m) (list x-range (cut condition m-range) a-range s-range))
    170       ((#\a) (list x-range m-range (cut condition a-range) s-range))
    171       ((#\s) (list x-range m-range a-range (cut condition s-range)))
    172       (else (assert #f "Bad condition " condition)))))
    173 
    174 (define (volume-valid? volume)
    175   (not (or (null? (car    volume))
    176            (null? (cadr   volume))
    177            (null? (caddr  volume))
    178            (null? (cadddr volume)))))
    179 
    180 (define (apply-process-2 process volume)
    181   (let loop ((conds    (car  process))
    182              (fallback (cadr process))
    183              (cur-vol  volume)
    184              (acc      '()))
    185     (if (or (null? conds) (not (volume-valid? cur-vol)))
    186         (filter! (lambda (item) (volume-valid? (cadr item)))
    187                  (cons (list fallback cur-vol) acc))
    188         (loop (cdr conds)
    189               fallback
    190               (cut-volume cut-without (car conds) cur-vol)
    191               (cons (list (cadddr (car conds))
    192                           (cut-volume cut-with (car conds) cur-vol))
    193                     acc)))))
    194 
    195 (define (range-size range)
    196   (- (cdr range) (car range) -1))
    197 
    198 (define (volume-size vol)
    199   (assert (= 4 (length vol)))
    200   (* (range-size (car    vol))
    201      (range-size (cadr   vol))
    202      (range-size (caddr  vol))
    203      (range-size (cadddr vol))))
    204 
    205 (define (answer-2-iter state count next-states)
    206   (let loop ((todo (apply-process-2 (hash-table-ref process-hash (car state))
    207                                     (cadr state)))
    208              (acc count)
    209              (result next-states))
    210     (if (null? todo)
    211         (list result acc)
    212         (loop (cdr todo)
    213               (if (equal? (caar todo) "A")
    214                   (+ acc (volume-size (cadar todo)))
    215                   acc)
    216               (if (> (string-length (caar todo)) 1)
    217                   (cons (car todo) result)
    218                   result)))))
    219 
    220 (define (answer-2 state-list acc)
    221   (if (null? state-list)
    222       acc
    223       (let ((iter (answer-2-iter (car state-list) acc (cdr state-list))))
    224         (answer-2 (car iter) (cadr iter)))))
    225 
    226 (define full-volume (list (cons min-val max-val)
    227                           (cons min-val max-val)
    228                           (cons min-val max-val)
    229                           (cons min-val max-val)))
    230 
    231 (write-line (conc "Second puzzle: "
    232   (answer-2 (list (list "in" full-volume)) 0)))