day03.scm (4554B)
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 srfi-1) 17 18 ;; input data, as a list of strings 19 (define grid (read-lines)) 20 21 ;; derived sizes 22 (define width (string-length (car grid))) 23 (define height (length grid)) 24 (define (xy-valid? x y) 25 (and (< -1 x width) (< -1 y height))) 26 27 ;; grid accessors 28 (define (grid-char x y) 29 (if (xy-valid? x y) 30 (string-ref (list-ref grid y) x) 31 #\nul)) 32 33 ;; grid iterators 34 (define (next-x x) 35 (if (>= x width) 0 (+ x 1))) 36 (define (next-y y) 37 (if (>= y height) 0 (+ y 1))) 38 (define (last? x y) 39 (and (= x (- width 1)) (= y (- height 1)))) 40 41 ;; symbol check 42 ;; (in my input, symbols are "#$%&*+-./=@") 43 (define (char-symbol? c) 44 (or (<= 35 (char->integer c) 45) (eqv? c #\/) (eqv? c #\=) (eqv? c #\@))) 45 46 ;;;;;;;;;;;;;;;;; 47 ;; First Puzzle 48 49 ;; list of (start-x end-x y value) for each part number 50 (define number-position-list 51 (let loop ((acc '()) (start-x -1) (x 0) (y 0) (n 0)) 52 (cond ((>= y height) acc) 53 ((>= x width) 54 (loop (if (>= start-x 0) (cons (list start-x x y n) acc) acc) 55 -1 0 (+ y 1) 0)) 56 ((char-numeric? (grid-char x y)) 57 (loop acc (if (>= start-x 0) start-x x) (+ x 1) y (+ (* n 10) (char->integer (grid-char x y)) -48))) 58 ((>= start-x 0) 59 (loop (cons (list start-x x y n) acc) -1 (+ x 1) y 0)) 60 (else 61 (loop acc -1 (+ x 1) y 0))))) 62 63 ;; check whether a given horizontal range contains a symbol 64 (define (contains-symbol? start-x end-x y) 65 (cond ((or (< y 0) (>= y height) (>= start-x end-x)) #f) 66 ((char-symbol? (grid-char start-x y)) #t) 67 (else (contains-symbol? (+ start-x 1) end-x y)))) 68 69 ;; check whether a symbol exists near the given number position 70 (define (is-part-position? pos) 71 (let ((start-x (car pos)) 72 (end-x (cadr pos)) 73 (y (caddr pos))) 74 (or (contains-symbol? (sub1 start-x) (add1 end-x) (sub1 y)) 75 (contains-symbol? (sub1 start-x) (add1 end-x) (add1 y)) 76 (contains-symbol? (sub1 start-x) start-x y) 77 (contains-symbol? end-x (add1 end-x) y)))) 78 79 ;; extract part number from all numbers 80 (define part-position-list (filter is-part-position? number-position-list)) 81 82 ;; sum of all part numbers 83 (define answer-1 84 (let loop ((position-list part-position-list) (acc 0)) 85 (if (null? position-list) 86 acc 87 (let ((rest (cdr position-list)) 88 (head (car position-list))) 89 (loop rest (+ acc (cadddr head))))))) 90 (write-line (conc "First puzzle: " answer-1)) 91 92 ;;;;;;;;;;;;;;;;; 93 ;; Second Puzzle 94 95 ;; is the given number-position adjacent to the given position 96 (define (adjacent? pos x y) 97 (let ((start-x (car pos)) 98 (end-x (cadr pos)) 99 (pos-y (caddr pos))) 100 (and (<= (sub1 pos-y) y (add1 pos-y)) 101 (<= (sub1 start-x) x end-x)))) 102 103 ;; list of all part positions adjacent to the given position 104 (define (adjacent-pos-list x y todo found) 105 (if (null? todo) 106 found 107 (adjacent-pos-list x y (cdr todo) 108 (if (adjacent? (car todo) x y) 109 (cons (car todo) found) 110 found)))) 111 112 ;; list of all part numbers adjacent to the given position 113 (define (adjacent-num-list x y) 114 (map cadddr (adjacent-pos-list x y part-position-list '()))) 115 116 ;; compute the gear ratio 117 (define (gear-ratio x y not-a-gear) 118 (if (eqv? (grid-char x y) #\*) 119 (let ((num-list (adjacent-num-list x y))) 120 (if (= (length num-list) 2) 121 (apply * num-list) 122 not-a-gear)) 123 not-a-gear)) 124 125 ;; iterate over the whole grid 126 (define answer-2 127 (let loop ((x 0) (y 0) (acc 0)) 128 (cond ((>= y height) acc) 129 ((>= x width) (loop 0 (add1 y) acc)) 130 (else (loop (add1 x) y (+ acc (gear-ratio x y 0))))))) 131 (write-line (conc "Second puzzle: " answer-2))