#!/usr/bin/env -S guile -s !# (use-modules (ice-9 regex) (ice-9 textual-ports) (srfi srfi-1)) (define line-length 140) ;; nasty :( (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 (candidates-for-line line) (letrec ((loop (lambda (l ls) (if (not l) ls (loop (string-match "[0-9]+" line (match:end l)) (cons l ls)))))) (loop (string-match "[0-9]+" line) '()))) (define (find-candidates lines) (let ((i -1)) (concatenate (map-in-order (lambda (line) (let ((cands (candidates-for-line line))) (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 (saturating-add lhs rhs max) (let ((res (+ lhs rhs))) (if (> res max) max res))) (define (saturating-sub lhs rhs min) (let ((res (- lhs rhs))) (if (< res min) min res))) (define (contains-part-symbol? str) (string-match "[^0-9|\\.]" str)) (define (part-number? candidate lines) (let ((above (substring (list-ref lines (saturating-sub (car candidate) 1 0)) (saturating-sub (cadr candidate) 1 0) (saturating-add (+ (cadr candidate) (caddr candidate)) 1 line-length))) (below (substring (list-ref lines (saturating-add (car candidate) 1 (- (length lines) 1))) (saturating-sub (cadr candidate) 1 0) (saturating-add (+ (cadr candidate) (caddr candidate)) 1 line-length))) (left (substring (list-ref lines (car candidate)) (saturating-sub (cadr candidate) 1 0) (cadr candidate))) (right (substring (list-ref lines (car candidate)) (+ (cadr candidate) (caddr candidate)) (saturating-add (+ (cadr candidate) (caddr candidate)) 1 line-length)))) (or (contains-part-symbol? above) (contains-part-symbol? below) (contains-part-symbol? left) (contains-part-symbol? right)))) (let* ((port (open-input-file "3.txt")) (lines (read-lines port))) (close-port port) (display (fold + 0 (map cadddr (filter (lambda (cand) (part-number? cand lines)) (find-candidates lines))))))