#+title: Solution to p20 Load map #+begin_src emacs-lisp :results none (require 'dash) (with-temp-buffer (insert-file-contents "input") (advent/replace-multiple-regex-buffer '(("^\\(#.*#\\)$" . "\"\\1\""))) (goto-char (point-min)) (insert "(setq data '(") (goto-char (point-max)) (insert "))") (eval-buffer)) (setq data-chars (-map #'advent/split-string-into-char-list data) height (length data-chars) width (length (car data-chars))) #+end_src #+begin_src emacs-lisp :results none (defun char-at (p) (nth (car p) (nth (cadr p) data-chars))) (setq char-things-alist '((?# . wall) (?. . free) (?S . start) (?E . end))) (defun thing-at (p) "Returns which object (if any) is present at position P" (cdr (assoc (char-at p) char-things-alist))) (defun starting-pos () (car (advent/coordinates-of ?S data-chars))) #+end_src Let the stack burn #+begin_src emacs-lisp :results none (setq max-lisp-eval-depth 1000000) ; burn baby burn #+end_src First, we explore the maze and record the path from START to END #+begin_src emacs-lisp :results none (defun explore (p dir &optional past) "Explore the maze starting at position P and in the direction DIR. Returns a list of positions traversed END to START" (if (eq (thing-at p) 'end) (cons p past) (let* ((forward-dirs (--filter (>= (advent/dot it dir) 0) '((0 1) (0 -1) (-1 0) (1 0)))) (new-dir (car (--filter (not (eq (thing-at (advent/neighbour p it)) 'wall)) forward-dirs)))) (explore (advent/neighbour p new-dir) new-dir (cons p past))))) (setq distance-alist (-map-indexed (lambda (x y) (cons y x)) (explore (starting-pos) '(0 0)))) #+end_src Now look for gaps: #+begin_src emacs-lisp (defun subtract-nil (a b) (when a (- a b))) (length (--filter (>= it 100) (--map (- it 2) (-flatten (-non-nil (--map (-non-nil (-map (lambda (dir) (subtract-nil (cdr (assoc (advent/neighbour (car it) dir) distance-alist)) (cdr it))) '((0 2) (0 -2) (2 0) (-2 0)))) distance-alist)))))) #+end_src #+RESULTS: : 1426 Alternatively, collect all element of the path that are –in the taxicab distance– closer than 20 to any given element of the path, then compute the time saved by using the cheat and filter only those that save at least 100 picoseconds #+begin_src emacs-lisp (length (--filter (>= it 100) (-flatten (-map (lambda (x) (--map (- (cdar it) (cdr x) (cdr it)) (--filter (<= (cdr it) 20) (--map (cons it (advent/taxicab-distance (car it) (car x))) distance-alist)))) distance-alist)))) #+end_src #+RESULTS: : 1000697