summaryrefslogtreecommitdiff
path: root/3.scm
blob: c43d0bd1dbed8b612b8b33fb0e7a7ee1028b948d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/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))))))