diff options
Diffstat (limited to 'day17.lisp')
-rw-r--r-- | day17.lisp | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/day17.lisp b/day17.lisp new file mode 100644 index 0000000..dca5e6e --- /dev/null +++ b/day17.lisp @@ -0,0 +1,63 @@ +(defun read-map (filespec) + (with-open-file (stream filespec) + (let ((lines (loop for line = (read-line stream nil) + while line + collect (make-array + (length line) + :initial-contents (loop for c across line + collect (- (char-code c) + (char-code #\0))))))) + (make-array (list (length lines) (length (first lines))) :initial-contents lines)))) + +(defun min-node (q) + (let ((mk ()) + (mv -1)) + (maphash (lambda (k v) (when (or (= mv -1) (< v mv)) (setf mk k mv v))) q) + mk)) + +(defun best-path (map min-moves max-moves) + (let ((q (make-hash-table :test #'equalp)) + (v (make-hash-table :test #'equalp)) + (n (array-dimension map 0)) + (m (array-dimension map 1))) + (labels ((is-final (node) + (multiple-value-bind (i j) (values-list node) + (and (= i (1- n)) (= j (1- m))))) + (is-possible (node) + (multiple-value-bind (i j c) (values-list node) + (and (>= i 0) (>= j 0) (< i n) (< j m) (<= c max-moves)))) + (add-node (node val) + (unless (or (not (is-possible node)) (gethash node v)) + (multiple-value-bind (oval found-p) (gethash node q) + (multiple-value-bind (i j) (values-list node) + (let ((val (+ val (aref map i j)))) + (setf (gethash node q) (if found-p (min val oval) val)))))))) + (setf (gethash '(0 1 1 #\R) q) (aref map 0 1)) + (setf (gethash '(1 0 1 #\D) q) (aref map 1 0)) + (loop for node = (min-node q) + while node + if (is-final node) + return (gethash node q) + do (multiple-value-bind (i j c d) (values-list node) + (let ((val (gethash node q))) + (remhash node q) + (setf (gethash node v) val) + (unless (or (equal d #\D) (and (not (equal d #\U)) (< c min-moves))) + (add-node (list (1- i) j (if (equal d #\U) (1+ c) 1) #\U) val)) + (unless (or (equal d #\U) (and (not (equal d #\D)) (< c min-moves))) + (add-node (list (1+ i) j (if (equal d #\D) (1+ c) 1) #\D) val)) + (unless (or (equal d #\R) (and (not (equal d #\L)) (< c min-moves))) + (add-node (list i (1- j) (if (equal d #\L) (1+ c) 1) #\L) val)) + (unless (or (equal d #\L) (and (not (equal d #\R)) (< c min-moves))) + (add-node (list i (1+ j) (if (equal d #\R) (1+ c) 1) #\R) val)))))))) + +(defun solve1 (filespec) + (best-path (read-map filespec) 0 3)) + +(defun solve2 (filespec) + (best-path (read-map filespec) 4 10)) + +(print (solve1 "data/17/example.txt")) ;; 102 +(print (solve1 "data/17/input.txt")) ;; 1039 +(print (solve2 "data/17/example.txt")) ;; 102 +(print (solve2 "data/17/input.txt")) ;; 1201 |