parent
0cbe285d54
commit
ac514c1cbc
1 changed files with 149 additions and 0 deletions
@ -0,0 +1,149 @@ |
|||||||
|
#+title: Solution to p21 |
||||||
|
|
||||||
|
Load map |
||||||
|
#+begin_src emacs-lisp :results none |
||||||
|
(require 'dash) |
||||||
|
(with-temp-buffer |
||||||
|
(insert-file-contents "input-test") |
||||||
|
(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 |
||||||
|
(setq numeric-keypad '("789" |
||||||
|
"456" |
||||||
|
"123" |
||||||
|
" 0A")) |
||||||
|
|
||||||
|
(setq dir-keypad '(" ^A" |
||||||
|
"<v>")) |
||||||
|
|
||||||
|
(setq numeric-keypad-data (-map #'advent/split-string-into-char-list numeric-keypad) |
||||||
|
dir-keypad-data (-map #'advent/split-string-into-char-list dir-keypad)) |
||||||
|
#+end_src |
||||||
|
|
||||||
|
This function takes a string and returns a list of ~(a . b)~, where |
||||||
|
these are the adjacent pairs in the string. For instance, if you feed |
||||||
|
it with "ABC" it will return ((?A . ?B) (?B . ?C)) |
||||||
|
#+begin_src emacs-lisp :results none |
||||||
|
(defun split-into-char-pairs (s) |
||||||
|
(let ((char-list (advent/split-string-into-char-list s))) |
||||||
|
(-zip-pair (-drop-last 1 char-list) (-drop 1 char-list)))) |
||||||
|
|
||||||
|
(defun char-pairs-to-coordinate-pairs (p keypad) |
||||||
|
(cons |
||||||
|
(car (advent/coordinates-of (car p) keypad)) |
||||||
|
(car (advent/coordinates-of (cdr p) keypad)))) |
||||||
|
#+end_src |
||||||
|
|
||||||
|
This takes a cons cell (p . q) of positions and returns all paths that |
||||||
|
go from p to q without getting out of the boundary |
||||||
|
#+begin_src emacs-lisp |
||||||
|
(defun subtract-vector (a b) |
||||||
|
(-zip-with #'- a b)) |
||||||
|
|
||||||
|
(defun add-vector (a b) |
||||||
|
(-zip-with #'+ a b)) |
||||||
|
|
||||||
|
(defun permute-string (s) |
||||||
|
"Return a list with all strings that can be obtained by permuting |
||||||
|
characters of S" |
||||||
|
(--map (apply #'string it) |
||||||
|
(-permutations |
||||||
|
(advent/split-string-into-char-list s)))) |
||||||
|
|
||||||
|
(defun connecting-paths (r keypad) |
||||||
|
(--map (concat it "A") |
||||||
|
(--filter (path-allowed-p it (car r) keypad) |
||||||
|
(let* ((difference (subtract-vector (cdr r) (car r))) |
||||||
|
(hor (car difference)) |
||||||
|
(ver (cadr difference))) |
||||||
|
(permute-string (concat |
||||||
|
(if (< hor 0) (make-string (- 0 hor) ?<) |
||||||
|
(make-string hor ?>)) |
||||||
|
(if (< ver 0) (make-string (- 0 ver) ?^) |
||||||
|
(make-string ver ?v)))))))) |
||||||
|
|
||||||
|
(setq dir-alist '((?> .(1 0)) |
||||||
|
(?< . (-1 0)) |
||||||
|
(?^ . (0 -1)) |
||||||
|
(?v . (0 1)))) |
||||||
|
|
||||||
|
(defun path-allowed-p (s start keypad) |
||||||
|
(not (--any (eq it 32) |
||||||
|
(--map (advent/char-at it keypad) |
||||||
|
(-reductions-from #'add-vector start (--map (cdr (assoc it dir-alist)) (advent/split-string-into-char-list s))))))) |
||||||
|
|
||||||
|
#+end_src |
||||||
|
|
||||||
|
#+RESULTS: |
||||||
|
: path-allowed-p |
||||||
|
|
||||||
|
#+begin_src emacs-lisp |
||||||
|
(defun directions-for-string (s keypad-data) |
||||||
|
(--map (connecting-paths it keypad-data) |
||||||
|
(--map |
||||||
|
(char-pairs-to-coordinate-pairs it keypad-data) |
||||||
|
(split-into-char-pairs (concat "A" s))))) |
||||||
|
|
||||||
|
(defun pick-shortest-string (l) |
||||||
|
"picks the shortest string in the list L" |
||||||
|
(-reduce (lambda (a b) |
||||||
|
(if (> (length a) (length b)) b a)) |
||||||
|
l)) |
||||||
|
(defun shortest-path (s) |
||||||
|
(let* ((first-directional-keypad |
||||||
|
(directions-for-string s numeric-keypad-data)) |
||||||
|
(second-directional-keypad |
||||||
|
(--map ; this iterates on the possible sequences of the num |
||||||
|
(--map (directions-for-string it dir-keypad-data) it) |
||||||
|
first-directional-keypad)) |
||||||
|
(third-directional-keypad |
||||||
|
(--map ; this iterates on the possible sequences of the num |
||||||
|
(--map ; this iterates on the possible sequences for the dir #1 |
||||||
|
(--map ; this iterates on the possible sequences for the dir #2 |
||||||
|
(--map |
||||||
|
(directions-for-string it dir-keypad-data) |
||||||
|
it) |
||||||
|
it) |
||||||
|
it) |
||||||
|
second-directional-keypad) |
||||||
|
)) |
||||||
|
(let* ((level-two |
||||||
|
(--map |
||||||
|
(--map |
||||||
|
(--map |
||||||
|
(--map |
||||||
|
(apply #'concat (-map #'pick-shortest-string it)) |
||||||
|
it) |
||||||
|
it) |
||||||
|
it) |
||||||
|
third-directional-keypad)) |
||||||
|
(level-one |
||||||
|
(--map |
||||||
|
(--map |
||||||
|
(apply #'concat (-map #'pick-shortest-string it)) |
||||||
|
it) |
||||||
|
level-two))) |
||||||
|
(apply #'concat (-map #'pick-shortest-string level-one))))) |
||||||
|
|
||||||
|
(defun replace-in-string (what with in) |
||||||
|
(replace-regexp-in-string (regexp-quote what) with in nil 'literal)) |
||||||
|
|
||||||
|
(defun complexity (s) |
||||||
|
(* (string-to-number (replace-in-string "A" "" s)) |
||||||
|
(length (shortest-path s)))) |
||||||
|
|
||||||
|
(-reduce #'+ (-map #'complexity data)) |
||||||
|
#+end_src |
||||||
|
|
||||||
|
#+RESULTS: |
||||||
|
: 222670 |
||||||
Loading…
Reference in new issue