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.
 

4.9 KiB

Solution to p21

Load map

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

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

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

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

  (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)))))))
path-allowed-p
   (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))
222670