aboutsummaryrefslogtreecommitdiff
path: root/day12.scm
diff options
context:
space:
mode:
authorJuan Marín Noguera <juan@mnpi.eu>2024-12-15 11:59:53 +0100
committerJuan Marín Noguera <juan@mnpi.eu>2024-12-15 12:01:06 +0100
commit2e904e83f6fbc001e5b265d94283841a51050fac (patch)
tree474b533a0d76e8c0d67a3d2d2560abfac721f84f /day12.scm
parent774d3ff46a854bd9a9379ef2c0945048ec5aee1e (diff)
Days 08--12
These days have been done while traveling, so they may be less modular due to time/phone-screen constraints.
Diffstat (limited to 'day12.scm')
-rw-r--r--day12.scm115
1 files changed, 115 insertions, 0 deletions
diff --git a/day12.scm b/day12.scm
new file mode 100644
index 0000000..e48c433
--- /dev/null
+++ b/day12.scm
@@ -0,0 +1,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))