day13.scm (5732B)
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 string) 16 comparse 17 srfi-1 18 srfi-14) 19 20 ;;;;;;;;;;;;;;;;; 21 ;; Input parsing 22 23 (define symbol 24 (in #\. #\#)) 25 26 (define line 27 (sequence* ((data (one-or-more symbol)) 28 (_ (is #\newline))) 29 (result data))) 30 31 (define area 32 (sequence* ((lines (one-or-more line)) 33 (_ (zero-or-more (is #\newline)))) 34 (result lines))) 35 36 (define all-data 37 (zero-or-more area)) 38 39 (define data (parse all-data (read-string))) 40 41 (define (draw-area prefix m) 42 (unless (null? m) 43 (write-line (conc prefix (list->string (car m)))) 44 (draw-area prefix (cdr m)))) 45 46 ;(let ((count 0)) 47 ; (for-each (lambda (area) (set! count (add1 count)) (draw-area (conc count ": ") area)) data)) 48 49 ;(write-line "Input:") 50 ;(draw-area " " data) 51 52 ;;;;;;;;;;;;;;;;; 53 ;; First Puzzle 54 55 (define (is-reflect-or-null? first second) 56 (or (null? first) 57 (null? second) 58 (and (equal? (car first) (car second)) 59 (is-reflect-or-null? (cdr first) (cdr second))))) 60 61 (define (is-reflect? first second) 62 (and (not (null? first)) 63 (not (null? second)) 64 (is-reflect-or-null? first second))) 65 66 (define (reflect-indices l) 67 ;(let ((result 68 (let loop ((reflected (list (car l))) 69 (todo (cdr l)) 70 (acc '())) 71 (if (null? todo) 72 (reverse acc) 73 (loop (cons (car todo) reflected) 74 (cdr todo) 75 (if (is-reflect-or-null? reflected todo) 76 (cons (length reflected) acc) 77 acc))))) 78 ;)(write-line (conc "reflect-indices " l " -> " result)) result)) 79 80 (define (merge-cols left right) 81 ;(let ((result 82 (let loop ((todo-1 left) 83 (todo-2 right) 84 (acc '())) 85 (cond ((or (null? todo-1) (null? todo-2)) (reverse acc)) 86 ((< (car todo-1) (car todo-2)) (loop (cdr todo-1) todo-2 acc)) 87 ((> (car todo-1) (car todo-2)) (loop todo-1 (cdr todo-2) acc)) 88 (else (loop (cdr todo-1) (cdr todo-2) (cons (car todo-1) acc)))))) 89 ;)(write-line (conc "result " left " " right " -> " result)) result)) 90 91 (define (reflect-cols area) 92 (let loop ((todo (cdr area)) 93 (acc (reflect-indices (car area)))) 94 (if (null? todo) 95 (begin (assert (<= (length acc) 1)) acc) 96 (loop (cdr todo) 97 (merge-cols acc (reflect-indices (car todo))))))) 98 99 (define (term-1 area) 100 (let ((cols (reflect-cols area)) 101 (rows (reflect-indices area))) 102 ; (write-line (conc "cols: " cols ", rows: " rows)) 103 (unless (= (+ (length cols) (length rows)) 1) 104 (write-line (conc "== cols: " cols ", rows: " rows)) 105 (draw-area " " area)) 106 (assert (= 1 (+ (length cols) (length rows)))) 107 (+ (apply + cols) (* 100 (apply + rows))))) 108 109 ;(let ((count 0)) 110 ; (for-each 111 ; (lambda (area) (set! count (add1 count)) 112 ; (write-line (conc count ": " (term-1 area)))) 113 ; data)) 114 115 (write-line (conc "First puzzle: " 116 (apply + (map (lambda (area) (term-1 area)) data)))) 117 118 ;;;;;;;;;;;;;;;;; 119 ;; Second Puzzle 120 121 (define (reflect-cols* area) 122 (let loop ((todo (cdr area)) 123 (acc (reflect-indices (car area)))) 124 (if (null? todo) 125 acc 126 (loop (cdr todo) 127 (merge-cols acc (reflect-indices (car todo))))))) 128 129 (define (term-1* area prev-term) 130 ; (write-line (conc "term-1* " area)) 131 ;(let ((result 132 (let ((cols (filter (lambda (i) (not (= i prev-term))) (reflect-cols* area))) 133 (rows (filter (lambda (i) (not (= prev-term (* 100 i)))) (reflect-indices area)))) 134 ;(write-line (conc " cols: " cols ", rows: " rows)) 135 (if (= (+ (length cols) (length rows)) 1) 136 (+ (apply + cols) (* 100 (apply + rows))) 137 0))) 138 ;)(write-line (conc " -> " result)) result)) 139 140 (define (term-2 area) 141 (let ((prev-term (term-1 area))) 142 (let loop ((prev-lines '()) 143 (prev-cols '()) 144 (next-cols (car area)) 145 (next-lines (cdr area))) 146 (if (null? next-cols) 147 (loop (append prev-lines (list (reverse prev-cols))) 148 '() 149 (car next-lines) 150 (cdr next-lines)) 151 (let ((try (term-1* (append prev-lines 152 (list (append (reverse prev-cols) 153 (if (eqv? (car next-cols) #\#) 154 '(#\.) '(#\#)) 155 (cdr next-cols))) 156 next-lines) 157 prev-term))) 158 (if (> try 0) 159 try 160 (loop prev-lines 161 (cons (car next-cols) prev-cols) 162 (cdr next-cols) 163 next-lines))))))) 164 165 ;(let ((count 0)) 166 ; (for-each 167 ; (lambda (area) (set! count (add1 count)) 168 ; (write-line (conc count ": " (term-2 area)))) 169 ; data)) 170 171 (write-line (conc "Second puzzle: " 172 (apply + (map (lambda (area) (term-2 area)) data))))