blob: e48c4330c30f526d21f5f2d48ed967d04569930b (
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
(define-module (day12)
#:use-module (ice-9 rdelim)
#:use-module (srfi srfi-1))
(define (read-input port)
(define (iter acc)
(define line (read-line port))
(if (or (eof-object? line) (string= line ""))
acc
(iter (cons (string->list line) acc))))
(list->array 2 (reverse (iter '()))))
(define (rectangle-fold proc init x0 xpast y0 ypast)
(let yloop ((y y0) (result init))
(if (>= y ypast)
result
(let xloop ((x x0) (result result))
(if (>= x xpast)
(yloop (+ y 1) result)
(xloop (+ x 1) (proc x y result)))))))
(define (add-margin input)
(define-values (h w) (apply values (array-dimensions input)))
(define result
(make-array #\space (list -1 h) (list -1 w)))
(rectangle-fold
(lambda (i j acc)
(array-set! result (array-ref input i j) i j))
#f 0 h 0 w)
result)
(define (get-area mp visited i j)
(define c (array-ref mp i j))
(array-set! visited #t i j)
(fold (lambda (di dj acc)
(define ni (+ i di))
(define nj (+ j dj))
(if (or (array-ref visited ni nj)
(not (char=? c (array-ref mp ni nj))))
acc
(+ acc (get-area mp visited ni nj))))
1 '(1 -1 0 0) '(0 0 1 -1)))
(define (set-area! mp areas val i j)
(define c (array-ref mp i j))
(when (zero? val) (error "Zero val!"))
(array-set! areas val i j)
(fold (lambda (di dj acc)
(define ni (+ i di))
(define nj (+ j dj))
(when (and (zero? (array-ref areas ni nj))
(char=? c (array-ref mp ni nj)))
(set-area! mp areas val ni nj)))
#f '(1 -1 0 0) '(0 0 1 -1)))
(define (get-areas mp h w)
(define result (make-array 0 (list -1 h) (list -1 w)))
(define visited (make-array #f (list -1 h) (list -1 w)))
(rectangle-fold (lambda (i j acc)
(unless (array-ref visited i j)
(set-area! mp result
(get-area mp visited i j)
i j)))
#f 0 h 0 w)
result)
(define (get-costs mp areas h w)
(rectangle-fold
(lambda (i j acc)
(define c (array-ref mp i j))
(+ acc
(if (char=? c (array-ref mp (+ i 1) j))
0
(+ (array-ref areas i j) (array-ref areas (+ i 1) j)))
(if (char=? c (array-ref mp i (+ j 1)))
0
(+ (array-ref areas i j) (array-ref areas i (+ j 1))))))
0 -1 h -1 w))
(define (part1 port)
(define input (read-input port))
(define-values (h w) (apply values (array-dimensions input)))
(define mp (add-margin input))
(define areas (get-areas mp h w))
(get-costs mp areas h w))
(define (get-discount-costs mp areas h w)
(define (count di dj)
(define visited
(make-array #f (list -1 h) (list -1 w)))
(define (visit! i j c)
(unless (or (not (char=? c (array-ref mp i j)))
(char=? c (array-ref mp (+ i di) (+ j dj))))
(array-set! visited #t i j)
(visit! (if (zero? di) (+ i 1) i)
(if (zero? dj) (+ j 1) j) c)))
(lambda (i j acc)
(if (array-ref visited i j)
acc
(let ((c (array-ref mp i j)))
(if (char=? c (array-ref mp (+ i di) (+ j dj)))
acc
(begin (visit! i j c)
(+ acc (array-ref areas i j))))))))
(+ (rectangle-fold (count -1 0) 0 0 h 0 w)
(rectangle-fold (count 1 0) 0 0 h 0 w)
(rectangle-fold (count 0 -1) 0 0 h 0 w)
(rectangle-fold (count 0 1) 0 0 h 0 w)))
(define (part2 port)
(define input (read-input port))
(define-values (h w) (apply values (array-dimensions input)))
(define mp (add-margin input))
(define areas (get-areas mp h w))
(get-discount-costs mp areas h w))
|