summaryrefslogtreecommitdiffstats
path: root/day17.lisp
diff options
context:
space:
mode:
authorAlexandre Jesus <adbjesus@gmail.com>2024-01-18 19:19:44 +0000
committerAlexandre Jesus <adbjesus@gmail.com>2024-01-18 19:19:44 +0000
commit4c79a9473347668ad10fdb243f0d51d71975a807 (patch)
tree91a8bdb7312b8a89a835d698ab13b6d35e8f1aa3 /day17.lisp
parent614d85028e18bcf06015009fa024adb62139c3c7 (diff)
downloadaoc2023-4c79a9473347668ad10fdb243f0d51d71975a807.tar.gz
aoc2023-4c79a9473347668ad10fdb243f0d51d71975a807.zip
day17
Diffstat (limited to 'day17.lisp')
-rw-r--r--day17.lisp63
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