-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathday19.lisp
More file actions
51 lines (43 loc) · 1.77 KB
/
day19.lisp
File metadata and controls
51 lines (43 loc) · 1.77 KB
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
(defpackage :aoc/2017/19 #.cl-user::*aoc-use*)
(in-package :aoc/2017/19)
(defun parse-tube-map (x)
(let ((entry (position #\| (first x)))
(height (length x))
(width (reduce #'max x :key #'length)))
(values (complex entry 0)
#C(0 -1)
(make-array (list height width) :initial-contents x))))
(defun tubes-get (tubes pos)
(let ((y (- (imagpart pos)))
(x (realpart pos)))
(if (array-in-bounds-p tubes y x)
(aref tubes y x))))
(defun letterp (c &aux (n (char-int c)))
(and (>= n (char-int #\A))
(<= n (char-int #\Z))))
(defun straightp (c)
(member c (list #\| #\-)))
(defun cornerp (c)
(char= c #\+))
(defun change-direction (tubes curr dir)
(let ((opts (list (complex-rotate-ccw dir) (complex-rotate-cw dir))))
(loop
:for new-dir :in opts
:for new-pos = (+ curr new-dir)
:for c = (tubes-get tubes new-pos)
:when (and c (not (char= c #\Space)))
:do (return (values new-pos new-dir)))))
(define-solution (2017 19) (data)
(multiple-value-bind (curr dir tubes) (parse-tube-map data)
(labels ((recur (curr dir letters steps)
(let ((c (tubes-get tubes curr)))
(cond ((letterp c) (recur (+ curr dir) dir (cons c letters) (1+ steps)))
((straightp c) (recur (+ curr dir) dir letters (1+ steps)))
((cornerp c) (multiple-value-bind
(curr dir)
(change-direction tubes curr dir)
(recur curr dir letters (1+ steps))))
(T (values (apply #'mkstr (reverse letters))
steps))))))
(recur curr dir nil 0))))
(define-test (2017 19) ("MKXOIHZNBL" 17872))