You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

90 lines
3.0 KiB

#+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