;; 11:45 ;; (ql:quickload '(fiveam arrows cl-heap)) (defun in-bounds (field position) (destructuring-bind (maxrow maxcol) (array-dimensions field) (destructuring-bind (row col) position (and (< -1 row maxrow) (< -1 col maxcol))))) (defun advance (row col dir) (cons dir (ecase dir (up (list (1- row) col)) (lf (list row (1- col))) (dw (list (1+ row) col)) (rt (list row (1+ col)))))) (defun parse-input (filepath) (let* ((input (uiop:read-file-lines filepath)) (rows (length input))) (make-array (list rows (length (car input))) :initial-contents (mapcar (lambda (line) (map 'vector (lambda (c) (logand 15 (char-code c))) line)) input)))) (defun backtrack (dir) (ecase dir (up 'dw) (rt 'lf) (dw 'up) (lf 'rt))) (defun next-moves (field tried walker) (destructuring-bind (track dir row col) walker (arrows:->> (remove dir '(rt dw lf up) :key #'backtrack) (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) (destructuring-bind (row col) (cddr step) (and (= row (1- maxrow)) (= col (1- maxcol)))))) (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))) (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))) (fiveam:test solutions (fiveam:is (= 102 (solver "eg-in"))) (fiveam:is (= 963 (solver "input"))))