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