|
| 1 | +#lang racket/base |
| 2 | + |
| 3 | +(define table |
| 4 | + (call-with-input-file "day03.txt" |
| 5 | + (lambda (in) |
| 6 | + (for*/vector ([line (in-lines in)] |
| 7 | + [char (in-string line)]) |
| 8 | + char)))) |
| 9 | +(define s (sqrt (vector-length table))) |
| 10 | +(define -s (- s)) |
| 11 | + |
| 12 | +(define (engine-symbol? c) |
| 13 | + (and (not (eqv? c #\.)) |
| 14 | + (not (char-numeric? c)))) |
| 15 | + |
| 16 | +(define-syntax-rule (define-finder id for*-id) |
| 17 | + (define (id t pos [ok? engine-symbol?]) |
| 18 | + (for*-id ([d (in-list (list (- -s 1) -s (+ -s 1) |
| 19 | + -1 1 |
| 20 | + (- s 1) s (+ s 1)))] |
| 21 | + [idx (in-value (+ pos d))] |
| 22 | + #:when (and (>= idx 0) |
| 23 | + (< idx (vector-length t)) |
| 24 | + (ok? (vector-ref t idx)))) |
| 25 | + idx))) |
| 26 | + |
| 27 | +(define-finder find-adjacent for*/list) |
| 28 | +(define-finder has-adjacent? for*/first) |
| 29 | + |
| 30 | +(define (char->decimal c) |
| 31 | + (- (char->integer c) |
| 32 | + (char->integer #\0))) |
| 33 | + |
| 34 | +(define part1 |
| 35 | + (for/fold ([num 0] |
| 36 | + [ok? #f] |
| 37 | + [total 0] |
| 38 | + #:result (if ok? (+ num total) total)) |
| 39 | + ([(c idx) (in-indexed (in-vector table))]) |
| 40 | + (if (char-numeric? c) |
| 41 | + (values (+ (* num 10) (char->decimal c)) |
| 42 | + (or ok? (has-adjacent? table idx)) |
| 43 | + total) |
| 44 | + (values 0 #f (if ok? (+ num total) total))))) |
| 45 | + |
| 46 | +(module+ test |
| 47 | + (require rackunit) |
| 48 | + (check-equal? part1 528799)) |
| 49 | + |
| 50 | +; invariant: indexes always start out as valid digit positions in the table |
| 51 | +(define (get-numbers t is) |
| 52 | + (let loop ([is is] |
| 53 | + [nums null]) |
| 54 | + (cond |
| 55 | + [(null? is) nums] |
| 56 | + [else |
| 57 | + (define-values (num rem-is) |
| 58 | + (let get-number ([i (car is)]) |
| 59 | + (if (or (< i 0) |
| 60 | + (not (char-numeric? (vector-ref t i)))) |
| 61 | + (for/fold ([n 0] [rem-is is]) |
| 62 | + ([(c idx) (in-indexed (in-vector t (add1 i)))]) |
| 63 | + #:break (not (char-numeric? c)) |
| 64 | + (values |
| 65 | + (+ (* n 10) (char->decimal c)) |
| 66 | + (remq (+ (add1 i) idx) rem-is))) |
| 67 | + (get-number (sub1 i))))) |
| 68 | + (loop rem-is (cons num nums))]))) |
| 69 | + |
| 70 | +(define part2 |
| 71 | + (for/fold ([total 0]) |
| 72 | + ([(c idx) (in-indexed (in-vector table))] |
| 73 | + #:when (eqv? c #\*)) |
| 74 | + (define adjacent-numbers |
| 75 | + (get-numbers table (find-adjacent table idx char-numeric?))) |
| 76 | + (if (= (length adjacent-numbers) 2) |
| 77 | + (+ total (apply * adjacent-numbers)) |
| 78 | + total))) |
| 79 | + |
| 80 | +(module+ test |
| 81 | + (check-equal? part2 84907174)) |
0 commit comments