#!/usr/bin/env -S guile -s !# (use-modules (ice-9 regex) (ice-9 textual-ports) (srfi srfi-1)) (define (read-lines port) (letrec ((loop (lambda (l ls) (if (eof-object? l) ls (loop (get-line port) (cons l ls)))))) (reverse (loop (get-line port) '())))) (define (matches-for-line line regex) (letrec ((loop (lambda (l ls) (if (not l) ls (loop (string-match regex line (match:end l)) (cons l ls)))))) (loop (string-match regex line) '()))) (define (find-candidates lines) (let ((i -1)) (concatenate (map-in-order (lambda (line) (let ((cands (matches-for-line line "[0-9]+"))) (set! i (+ i 1)) (map (lambda (cand) `(,i ,(match:start cand) ,(- (match:end cand) (match:start cand)) ,(string->number (match:substring cand)))) cands))) lines)))) (define (find-gears lines) (let ((i -1)) (concatenate (map-in-order (lambda (line) (let ((cands (matches-for-line line "\\*"))) (set! i (+ i 1)) (map (lambda (cand) `(,i ,(match:start cand))) cands))) lines)))) (define (parts-for-gear parts gear) (filter (lambda (part) (and (>= (car part) (- (car gear) 1)) (<= (car part) (+ (car gear) 1)) (<= (- (cadr gear) (cadr part)) (caddr part)) (>= (- (cadr gear) (cadr part)) -1))) parts)) (let* ((port (open-input-file "3.txt")) (lines (read-lines port)) (parts (find-candidates lines))) (close-port port) (display (fold + 0 (map (lambda (x) (* (car x) (cadr x))) (filter (lambda (x) (= (length x) 2)) (map (lambda (gear) (map cadddr (parts-for-gear parts gear))) (find-gears lines)))))))