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