#lang racket (require "../lib/utils.rkt") (require "../lib/obj.rkt") (define (read-input) (call-with-input-file "input" (λ (fp) (list->vector (get-lines fp))))) (define schema (read-input)) (define (char-at line col) (string-ref (vector-ref schema line) col)) (define height (vector-length schema)) (define width (string-length (vector-ref schema 0))) (define make-num (obj-maker 'line 'col 'value 'length)) (define (scan-nums) (define nums '()) (let loop ((i 0)) (if (>= i height) (void) (let () (let loop ((j 0)) (define curline (vector-ref schema i)) (if (>= j width) (void) (let () (define next 1) (define (find-next) (if (or (>= (+ j next) 140) (not (char-numeric? (char-at i (+ j next))))) (void) (let () (set! next (+ 1 next)) (find-next)))) (if (char-numeric? (char-at i j)) (let () (find-next) (define value (string->number (substring curline j (+ j next)))) (set! nums (cons (make-num i j value next) nums))) (void)) (loop (+ j next))))) (loop (+ 1 i))))) (reverse nums)) (define nums (scan-nums)) (define (collect-adjacent-positions num) (define (position-range line start end) (define delta (- end start)) (map list (repeat delta line) (range start end))) (define left (if (= 0 (num 'col)) '() (list (list (num 'line) (- (num 'col) 1))))) (define right (if (= width (+ (num 'col) (num 'length))) '() (list (list (num 'line) (+ (num 'col) (num 'length)))))) (define up (if (= 0 (num 'line)) '() (position-range (- (num 'line) 1) (max 0 (- (num 'col) 1)) (min width (+ (num 'col) (num 'length) 1))))) (define down (if (= (- height 1) (num 'line)) '() (position-range (+ (num 'line) 1) (max 0 (- (num 'col) 1)) (min width (+ (num 'col) (num 'length) 1))))) (append left right up down)) (define asterisks (make-hash)) (define (mark-adj-asterisk num) (define adjs (collect-adjacent-positions num)) (define (mark coord) (if (not (char=? #\* (char-at (car coord) (cadr coord)))) (void) (let () (when (not (hash-has-key? asterisks coord)) (hash-set! asterisks coord '())) (hash-set! asterisks coord (cons (num 'value) (hash-ref asterisks coord)))))) (for-each mark adjs)) (for-each mark-adj-asterisk nums) (define aster-list (hash->list asterisks)) (define (is-gear? aster) (define nums-list (cdr aster)) (= 2 (length nums-list))) (define (power aster) (define nums-list (cdr aster)) (* (car nums-list) (cadr nums-list))) (apply + (map power (filter is-gear? aster-list)))