aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AoC2023/day17/solver.lisp119
1 files changed, 33 insertions, 86 deletions
diff --git a/AoC2023/day17/solver.lisp b/AoC2023/day17/solver.lisp
index 94598db..7001eb8 100644
--- a/AoC2023/day17/solver.lisp
+++ b/AoC2023/day17/solver.lisp
@@ -2,10 +2,9 @@
;;
(ql:quickload '(fiveam arrows cl-heap))
-(defun in-bounds (field crucible)
+(defun in-bounds (field position)
(destructuring-bind (maxrow maxcol) (array-dimensions field)
- (destructuring-bind (dir row col) crucible
- (declare (ignorable dir))
+ (destructuring-bind (row col) position
(and (< -1 row maxrow)
(< -1 col maxcol)))))
@@ -28,11 +27,6 @@
line))
input))))
-(defstruct (walker (:copier nil))
- (path (make-hash-table :test #'equal))
- dir row col
- (track 0))
-
(defun backtrack (dir)
(ecase dir
(up 'dw)
@@ -40,93 +34,46 @@
(dw 'up)
(lf 'rt)))
-(defun next-direction (walker adv)
- (with-slots (path dir track) walker
- (destructuring-bind (move nrow ncol) adv
- (let ((np (alexandria:copy-hash-table path)))
- (setf (gethash adv np) t)
- (make-walker :path np
- :dir move
- :row nrow
- :col ncol
- :track (if (eq move dir) (1+ track) 0))))))
-
(defun next-moves (field tried walker)
- (with-slots (dir row col track) walker
+ (destructuring-bind (track dir row col) walker
(arrows:->>
(remove dir '(rt dw lf up) :key #'backtrack)
- (remove-if (lambda (d) (and (eq d dir)
- (<= 2 track))))
- (mapcar (alexandria:curry #'advance row col))
- (remove-if-not (alexandria:curry #'in-bounds field))
- (remove-if (lambda (p)
- (gethash (cons (if (eq (car p) dir) (1+ track) 0) p) tried)))
- (mapcar (lambda (p)
- (let ((nt (if (eq (car p) dir) (1+ track) 0)))
- (setf (gethash (cons nt p) tried) t)
- (next-direction walker p)
- ;; (destructuring-bind (dir row col) p
- ;; (make-walker :dir dir :row row :col col :track nt))
- )))
- ;; (mapcar (lambda (d) (next-direction walker d)))
- )))
+ (mapcar (lambda (d)
+ (unless (and (eq d dir) (<= 2 track))
+ (destructuring-bind (ndir . np) (advance row col d)
+ (when (in-bounds field np)
+ (let* ((nt (if (eq ndir dir) (1+ track) 0))
+ (npath (list* nt ndir np)))
+ (unless (gethash npath tried)
+ (setf (gethash npath tried) t)
+ npath)))))))
+ (delete nil))))
(defun finish-p (field step)
(destructuring-bind (maxrow maxcol) (array-dimensions field)
- (with-slots (row col) step
+ (destructuring-bind (row col) (cddr step)
(and (= row (1- maxrow))
(= col (1- maxcol))))))
-(defun path-cost (field walker)
- (let ((cost 0))
- (maphash (lambda (k v)
- (declare (ignorable v))
- (destructuring-bind (dir row col) k
- (declare (ignorable dir))
- (incf cost (aref field row col))))
- (walker-path walker))
- cost))
-
-
-(defun try (options known field iters)
- (let ((next (cl-heap:dequeue options)))
- ;; (with-slots (dir row col) next
- ;; (format t "i: ~d cost: ~d/~d p: ~a~%" iters (path-cost field next) (hash-table-count (walker-path next)) (list dir row col)))
- (when next
- (if (finish-p field next)
- (progn (format t "Took ~d iters\n" iters)
- next)
- (progn
- (dolist (newm (next-moves field known next))
- (cl-heap:enqueue options
- newm
- (path-cost field newm)))
- ;; (print (cl-heap:queue-size options))
- (try options known field (1+ iters))))))
+(defun vdequeue (q)
+ (cl-heap:pop-heap (slot-value q 'cl-heap:heap)))
- )
+(defun walk (options known field)
+ (loop for (pcost current) = (vdequeue options)
+ while current
+ until (finish-p field current)
+ do (dolist (next (next-moves field known current))
+ (cl-heap:enqueue options next (+ (apply #'aref field (cddr next)) pcost)))
+ finally (return pcost)))
-(let* ((field (parse-input "input"))
- ;; (maxloss (apply #'* 9 (array-dimensions field)))
- (options (make-instance 'cl-heap:priority-queue))
- (known (make-hash-table :test #'equal))
- (w (make-walker :dir 'rt :row 0 :col 0)))
- ;; (setf (gethash '(rt 0 0) (walker-path w)) 1)
- ;; (next-moves field w)
- ;; (carry field w maxloss 0)
- ;; (cl-heap:dequeue
- ;; options)
- (cl-heap:enqueue options w 0)
- ;; (cl-heap:enqueue options '(rt 0 0 0) 0)
- ;; options
- ;; (print)
- (time
- (let ((r
- (try options known field 0)))
- (list (path-cost field r) r)))
- )
+(defun solver (filename)
+ (let* ((field (parse-input filename))
+ (options (make-instance 'cl-heap:priority-queue))
+ (known (make-hash-table :test #'equal))
+ (w (list -1 'rt 0 0)))
+ (cl-heap:enqueue options w 0)
+ (walk options known field)))
-;; (let ( (w (make-walker :dir 'rt :row 0 :col 0))
-;; (y (make-walker :dir 'rt :row 0 :col 0)) )
-;; (equalp w y))
-;; (make-hash-table :test #'equalp)
+(fiveam:test solutions
+ (fiveam:is (= 102 (solver "eg-in")))
+ (fiveam:is (= 963 (solver "input"))))