diff --git a/p21/p21.org b/p21/p21.org new file mode 100644 index 0000000..31d56d2 --- /dev/null +++ b/p21/p21.org @@ -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" + "")) + + (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