reimplement day21 but still stuck
This commit is contained in:
parent
28881608de
commit
669e47f572
2 changed files with 252 additions and 132 deletions
|
@ -9,15 +9,16 @@
|
||||||
#:part2
|
#:part2
|
||||||
#:key-to-pos
|
#:key-to-pos
|
||||||
#:press-key
|
#:press-key
|
||||||
#:type-code
|
|
||||||
#:type-manual
|
#:type-manual
|
||||||
#:complexity
|
#:complexity
|
||||||
#:combinations
|
#:combinations
|
||||||
#:press-key-combinations
|
#:press-key-combinations
|
||||||
#:path-invalid-p
|
#:path-invalid-p
|
||||||
#:easiest-to-type
|
#:easiest-to-type
|
||||||
#:easy-key-combinations
|
#:decode
|
||||||
#:easy-type-code
|
#:decode3
|
||||||
|
#:fewest-presses
|
||||||
|
#:fill-leg-table
|
||||||
))
|
))
|
||||||
|
|
||||||
(in-package :aoc/2024/21)
|
(in-package :aoc/2024/21)
|
||||||
|
@ -71,121 +72,6 @@
|
||||||
;; - sum it.
|
;; - sum it.
|
||||||
|
|
||||||
|
|
||||||
(defun key-to-pos (c)
|
|
||||||
(cond
|
|
||||||
((eq c #\0) (make-pos :x 1 :y 0))
|
|
||||||
((eq c #\A) (make-pos :x 2 :y 0))
|
|
||||||
((eq c #\^) (make-pos :x 1 :y 0))
|
|
||||||
((eq c #\<) (make-pos :x 0 :y 1))
|
|
||||||
((eq c #\v) (make-pos :x 1 :y 1))
|
|
||||||
((eq c #\>) (make-pos :x 2 :y 1))
|
|
||||||
((digit-char-p c) (make-pos
|
|
||||||
:x (mod (1- (digit-char-p c)) 3)
|
|
||||||
:y (floor (/ (+ 2 (digit-char-p c)) 3))))
|
|
||||||
(t nil)))
|
|
||||||
|
|
||||||
(defun press-key (start target &optional (numeric t))
|
|
||||||
(let ((diff (pos-subtract
|
|
||||||
(key-to-pos target)
|
|
||||||
(key-to-pos start))))
|
|
||||||
(coerce
|
|
||||||
(append
|
|
||||||
(loop for x from 0 below (pos-x diff) collect #\>)
|
|
||||||
(loop for y from 0 below (pos-y diff) collect (if numeric #\^ #\v))
|
|
||||||
(loop for y from 0 below (- (pos-y diff)) collect (if numeric #\v #\^))
|
|
||||||
(loop for x from 0 below (- (pos-x diff)) collect #\<)
|
|
||||||
'(#\A))
|
|
||||||
'string)))
|
|
||||||
|
|
||||||
(defun type-code (code &optional (numeric t))
|
|
||||||
(let ((keys (coerce code 'list)))
|
|
||||||
(format
|
|
||||||
nil "~{~A~}"
|
|
||||||
(loop
|
|
||||||
for start in (cons #\A keys)
|
|
||||||
for target in keys
|
|
||||||
collect (press-key start target numeric)))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defun combinations (as bs &optional (acc '()))
|
|
||||||
(cond
|
|
||||||
((emptyp as) (list (append bs acc)))
|
|
||||||
((emptyp bs) (list (append as acc)))
|
|
||||||
(t (append
|
|
||||||
(combinations (cdr as) bs (cons (car as) acc))
|
|
||||||
(combinations as (cdr bs) (cons (car bs) acc))))))
|
|
||||||
|
|
||||||
(defun pos-step (pos c &optional (numeric t))
|
|
||||||
(case c
|
|
||||||
((#\< #\>) (pos-move pos c))
|
|
||||||
(#\^ (pos-move pos (if numeric #\v #\^)))
|
|
||||||
(#\v (pos-move pos (if numeric #\^ #\v)))))
|
|
||||||
|
|
||||||
(defun path-invalid-p (start moves &optional (numeric t))
|
|
||||||
(loop
|
|
||||||
for dir in moves
|
|
||||||
for pos = (pos-step (or pos start) dir numeric)
|
|
||||||
thereis (and (zerop (pos-x pos)) (zerop (pos-y pos)))))
|
|
||||||
|
|
||||||
(defun press-key-combinations (start target &optional (numeric t))
|
|
||||||
(let* ((start-pos (key-to-pos start))
|
|
||||||
(diff (pos-subtract
|
|
||||||
(key-to-pos target)
|
|
||||||
start-pos))
|
|
||||||
(hp (loop
|
|
||||||
for x from 0 below (abs (pos-x diff))
|
|
||||||
collect (if (plusp (pos-x diff)) #\> #\<)))
|
|
||||||
(vp (loop
|
|
||||||
for y from 0 below (abs (pos-y diff))
|
|
||||||
collect (if (equal numeric (plusp (pos-y diff))) #\^ #\v)))
|
|
||||||
)
|
|
||||||
(mapcar
|
|
||||||
#'(lambda (c) (coerce (append c '(#\A)) 'string))
|
|
||||||
(remove-if
|
|
||||||
#'(lambda (moves) (path-invalid-p start-pos moves))
|
|
||||||
(combinations hp vp)))
|
|
||||||
))
|
|
||||||
|
|
||||||
(defun easiest-to-type (codes &optional (numeric t))
|
|
||||||
(format t "~A ~A~%" codes numeric)
|
|
||||||
(let ((min-taps (loop
|
|
||||||
for code in codes
|
|
||||||
minimize (length (type-code (type-code code t) nil)))))
|
|
||||||
(loop
|
|
||||||
for code in codes
|
|
||||||
if (= min-taps (length (type-code (type-code code numeric))))
|
|
||||||
collect code)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun easy-key-combinations (start target &optional (numeric t))
|
|
||||||
(easiest-to-type
|
|
||||||
(press-key-combinations start target numeric)
|
|
||||||
t))
|
|
||||||
|
|
||||||
(defun type-numpad (code)
|
|
||||||
(let ((keys (coerce code 'list)))
|
|
||||||
(format nil "~{~A~}"
|
|
||||||
(loop
|
|
||||||
for start in (cons #\A keys)
|
|
||||||
for target in keys
|
|
||||||
collect (first (easy-key-combinations start target t))))))
|
|
||||||
|
|
||||||
(defun type-dirpads (code n)
|
|
||||||
(loop
|
|
||||||
for i from 1 to n
|
|
||||||
do (setf code (type-code code nil))
|
|
||||||
finally (return code)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun type-manual (code n)
|
|
||||||
(type-dirpads (type-numpad code) n))
|
|
||||||
|
|
||||||
(defun complexity (code n)
|
|
||||||
(let ((l (length (type-manual code n)))
|
|
||||||
(v (parse-integer (ppcre:scan-to-strings "\\d+" code))))
|
|
||||||
(* l v)))
|
|
||||||
|
|
||||||
(defun pos-to-key (pos &optional (numeric t))
|
(defun pos-to-key (pos &optional (numeric t))
|
||||||
(cond
|
(cond
|
||||||
((zerop (pos-y pos)) (if numeric
|
((zerop (pos-y pos)) (if numeric
|
||||||
|
@ -226,17 +112,248 @@
|
||||||
nil)
|
nil)
|
||||||
t))
|
t))
|
||||||
|
|
||||||
|
(defun decoden (code n numeric)
|
||||||
|
(if (zerop n)
|
||||||
|
(decode code numeric)
|
||||||
|
(decode (decoden code (1- n) nil) numeric))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun key-to-pos (c)
|
||||||
|
(cond
|
||||||
|
((eq c #\0) (make-pos :x 1 :y 0))
|
||||||
|
((eq c #\A) (make-pos :x 2 :y 0))
|
||||||
|
((eq c #\^) (make-pos :x 1 :y 0))
|
||||||
|
((eq c #\<) (make-pos :x 0 :y 1))
|
||||||
|
((eq c #\v) (make-pos :x 1 :y 1))
|
||||||
|
((eq c #\>) (make-pos :x 2 :y 1))
|
||||||
|
((digit-char-p c) (make-pos
|
||||||
|
:x (mod (1- (digit-char-p c)) 3)
|
||||||
|
:y (floor (/ (+ 2 (digit-char-p c)) 3))))
|
||||||
|
(t nil)))
|
||||||
|
|
||||||
|
(defun press-key (start target &optional (numeric t))
|
||||||
|
(let ((diff (pos-subtract
|
||||||
|
(key-to-pos target)
|
||||||
|
(key-to-pos start))))
|
||||||
|
(coerce
|
||||||
|
(append
|
||||||
|
(loop for x from 0 below (pos-x diff) collect #\>)
|
||||||
|
(loop for y from 0 below (pos-y diff) collect (if numeric #\^ #\v))
|
||||||
|
(loop for y from 0 below (- (pos-y diff)) collect (if numeric #\v #\^))
|
||||||
|
(loop for x from 0 below (- (pos-x diff)) collect #\<)
|
||||||
|
'(#\A))
|
||||||
|
'string)))
|
||||||
|
|
||||||
|
(defun pos-step (pos c &optional (numeric t))
|
||||||
|
(case c
|
||||||
|
((#\< #\>) (pos-move pos c))
|
||||||
|
(#\^ (pos-move pos (if numeric #\v #\^)))
|
||||||
|
(#\v (pos-move pos (if numeric #\^ #\v)))))
|
||||||
|
|
||||||
|
(defun path-invalid-p (start moves &optional (numeric t))
|
||||||
|
(loop
|
||||||
|
for dir in moves
|
||||||
|
for pos = (pos-step (or pos start) dir numeric)
|
||||||
|
thereis (and (zerop (pos-x pos)) (zerop (pos-y pos)))))
|
||||||
|
|
||||||
|
(defun press-key-combinations (start target &optional (numeric t))
|
||||||
|
(let* ((start-pos (key-to-pos start))
|
||||||
|
(diff (pos-subtract
|
||||||
|
(key-to-pos target)
|
||||||
|
start-pos))
|
||||||
|
(hp (loop
|
||||||
|
for x from 0 below (abs (pos-x diff))
|
||||||
|
collect (if (plusp (pos-x diff)) #\> #\<)))
|
||||||
|
(vp (loop
|
||||||
|
for y from 0 below (abs (pos-y diff))
|
||||||
|
collect (if (equal numeric (plusp (pos-y diff))) #\^ #\v)))
|
||||||
|
)
|
||||||
|
(mapcar
|
||||||
|
#'(lambda (moves) (coerce (append moves '(#\A)) 'string))
|
||||||
|
(remove-if
|
||||||
|
#'(lambda (moves) (path-invalid-p start-pos moves))
|
||||||
|
(list
|
||||||
|
(append hp vp)
|
||||||
|
(append vp hp))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defparameter *tl-cache* (make-hash-table :test #'equal))
|
||||||
|
(defun reset-cache ()
|
||||||
|
(setf *tl-cache* (make-hash-table :test #'equal)))
|
||||||
|
|
||||||
|
(defun _type-length (code level numeric)
|
||||||
|
(if (zerop level)
|
||||||
|
(length code)
|
||||||
|
(loop
|
||||||
|
for part in (list code)
|
||||||
|
sum (let ((keys (coerce code 'list)))
|
||||||
|
(loop
|
||||||
|
for start in (cons #\A keys)
|
||||||
|
for target in keys
|
||||||
|
sum (loop
|
||||||
|
for c in (press-key-combinations start target numeric)
|
||||||
|
minimizing (type-length c (1- level) nil)
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun type-length (code level numeric)
|
||||||
|
(multiple-value-bind (v found) (gethash (cons code level) *tl-cache*)
|
||||||
|
(if found
|
||||||
|
v
|
||||||
|
(let ((l (_type-length code level numeric)))
|
||||||
|
(setf (gethash (cons code level) *tl-cache*) l) ))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defun print-lengths (data)
|
||||||
|
(reset-cache)
|
||||||
|
(loop
|
||||||
|
for n from 1 to 26
|
||||||
|
do (format t "~%n: ~A~%" n)
|
||||||
|
(loop
|
||||||
|
for code in data
|
||||||
|
do (format t "~15A~%" (type-length code n t))
|
||||||
|
)))
|
||||||
|
|
||||||
|
(defparameter dir-map
|
||||||
|
(make-array
|
||||||
|
'(2 3) :initial-contents
|
||||||
|
#(
|
||||||
|
#(#\SPACE #\^ #\A)
|
||||||
|
#( #\< #\v #\>)
|
||||||
|
)))
|
||||||
|
|
||||||
|
(defparameter num-map
|
||||||
|
(make-array
|
||||||
|
'(4 3)
|
||||||
|
:initial-contents
|
||||||
|
#(
|
||||||
|
#(#\7 #\8 #\9)
|
||||||
|
#(#\4 #\5 #\6)
|
||||||
|
#(#\1 #\2 #\3)
|
||||||
|
#(#\SPACE #\0 #\A))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun dir-pos (c)
|
||||||
|
(car (loop
|
||||||
|
for x from 0 below (array-dimension dir-map 1)
|
||||||
|
append (loop
|
||||||
|
for y from 0 below (array-dimension dir-map 0)
|
||||||
|
if (eq c (aref dir-map y x))
|
||||||
|
collect (cons x y)))))
|
||||||
|
|
||||||
|
(defun num-pos (c)
|
||||||
|
(car (loop
|
||||||
|
for x from 0 below (array-dimension num-map 1)
|
||||||
|
append (loop
|
||||||
|
for y from 0 below (array-dimension num-map 0)
|
||||||
|
if (eq c (aref num-map y x))
|
||||||
|
collect (cons x y)))))
|
||||||
|
|
||||||
|
(defvar leg-lengths (make-hash-table :test #'equal))
|
||||||
|
|
||||||
|
(defun fewest-presses (layer ks)
|
||||||
|
(loop
|
||||||
|
for ki in (cons #\A (coerce ks 'list))
|
||||||
|
for kf in (coerce ks 'list)
|
||||||
|
sum (let ((ll (gethash (list layer ki kf) leg-lengths)))
|
||||||
|
ll)))
|
||||||
|
|
||||||
|
(defun fill-leg-table (n-robots)
|
||||||
|
(setf leg-lengths (make-hash-table :test #'equal))
|
||||||
|
|
||||||
|
(loop
|
||||||
|
for ki from 0 below (array-total-size dir-map)
|
||||||
|
do (loop
|
||||||
|
for kf from 0 below (array-total-size dir-map)
|
||||||
|
do (setf
|
||||||
|
(gethash
|
||||||
|
(list
|
||||||
|
0
|
||||||
|
(row-major-aref dir-map ki)
|
||||||
|
(row-major-aref dir-map kf))
|
||||||
|
leg-lengths)
|
||||||
|
1)
|
||||||
|
))
|
||||||
|
(loop
|
||||||
|
for layer from 1 to n-robots
|
||||||
|
do (let* ((key-map (if (= layer n-robots) num-map dir-map))
|
||||||
|
(key-pos (if (= layer n-robots) #'num-pos #'dir-pos))
|
||||||
|
(space-pos (funcall key-pos #\SPACE)))
|
||||||
|
(loop
|
||||||
|
for i from 0 below (array-total-size key-map)
|
||||||
|
for ki = (row-major-aref key-map i)
|
||||||
|
for pos-i = (funcall key-pos ki)
|
||||||
|
for xi = (car pos-i)
|
||||||
|
for yi = (cdr pos-i)
|
||||||
|
do (loop
|
||||||
|
for j from 0 below (array-total-size key-map)
|
||||||
|
for kf = (row-major-aref key-map j)
|
||||||
|
for pos-f = (funcall key-pos kf)
|
||||||
|
for xf = (car pos-f)
|
||||||
|
for yf = (cdr pos-f)
|
||||||
|
do (let* (
|
||||||
|
(dx (- xf xi))
|
||||||
|
(dy (- yf yi))
|
||||||
|
(hp (loop
|
||||||
|
for x from 0 below (abs dx)
|
||||||
|
collect (if (plusp dx) #\> #\<)))
|
||||||
|
(vp (loop
|
||||||
|
for y from 0 below (abs dy)
|
||||||
|
collect (if (minusp dy) #\^ #\v)))
|
||||||
|
(hf (coerce (append hp vp '(#\A)) 'string))
|
||||||
|
(h-first (if (equal (cons xf yi) space-pos)
|
||||||
|
999
|
||||||
|
(fewest-presses (1- layer) hf)))
|
||||||
|
(vf (coerce (append vp hp '(#\A)) 'string))
|
||||||
|
(v-first (if (equal (cons xi yf) space-pos)
|
||||||
|
999
|
||||||
|
(fewest-presses (1- layer) vf))))
|
||||||
|
;;(format t "h ~A ~A ~A ~A~%" xi yf hf h-first)
|
||||||
|
;;(format t "v ~A ~A ~A ~A~%" xf yi vf v-first)
|
||||||
|
;;(format t "ll[~A ~A ~A] ~A~%" layer ki kf (min h-first v-first))
|
||||||
|
(setf
|
||||||
|
(gethash (list layer ki kf) leg-lengths)
|
||||||
|
(min h-first v-first)))))
|
||||||
|
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun complexity (code n)
|
||||||
|
(let ((l (fewest-presses n code))
|
||||||
|
(v (parse-integer (ppcre:scan-to-strings "\\d+" code))))
|
||||||
|
(* l v)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun print-llengths (data)
|
||||||
|
(reset-cache)
|
||||||
|
(loop
|
||||||
|
for n from 1 to 26
|
||||||
|
do (format t "~%n: ~A~%" n)
|
||||||
|
(fill-leg-table n)
|
||||||
|
(loop
|
||||||
|
for code in data
|
||||||
|
do (format t "~15A~%" (fewest-presses n code))
|
||||||
|
)))
|
||||||
|
|
||||||
|
|
||||||
(defun part1 (data)
|
(defun part1 (data)
|
||||||
|
(fill-leg-table 3)
|
||||||
(loop
|
(loop
|
||||||
for code in data
|
for code in data
|
||||||
sum (complexity code 2)))
|
sum (complexity code 3)))
|
||||||
|
|
||||||
(defun part2 (data)
|
(defun part2 (data)
|
||||||
|
(fill-leg-table 26)
|
||||||
(loop
|
(loop
|
||||||
for code in data
|
for code in data
|
||||||
sum (complexity code 25)))
|
sum (complexity code 26)))
|
||||||
|
|
||||||
(defun solve-day ()
|
(defun solve-day ()
|
||||||
|
(reset-cache)
|
||||||
(format t "part1: ~A~%" (part1 input-data))
|
(format t "part1: ~A~%" (part1 input-data))
|
||||||
(format t "part2: ~A~%" (part2 input-data)))
|
(format t "part2: ~A~%" (part2 input-data)))
|
||||||
|
|
||||||
|
|
|
@ -37,23 +37,26 @@
|
||||||
|
|
||||||
(define-test test-complexity
|
(define-test test-complexity
|
||||||
:parent suite-2024-21
|
:parent suite-2024-21
|
||||||
(is = (* 68 29) (complexity "029A" 2))
|
(is = (* 68 29) (complexity "029A" 3))
|
||||||
(is = (* 60 980) (complexity "980A" 2))
|
(is = (* 60 980) (complexity "980A" 3))
|
||||||
(is = (* 68 179) (complexity "179A" 2))
|
(is = (* 68 179) (complexity "179A" 3))
|
||||||
(is = (* 64 456) (complexity "456A" 2))
|
(is = (* 64 456) (complexity "456A" 3))
|
||||||
(is = (* 64 379) (complexity "379A" 2)))
|
(is = (* 64 379) (complexity "379A" 3)))
|
||||||
|
|
||||||
(define-test test-manual
|
(define-test test-fewest-presses
|
||||||
:parent suite-2024-21
|
:parent suite-2024-21
|
||||||
(is equal
|
(fill-leg-table 3)
|
||||||
"<v<A>>^AvA^A<vA<AA>>^AAvA<^A>AAvA^A<vA>^AA<A>A<v<A>A>^AAAvA<^A>A"
|
(is = 68 (fewest-presses 3 "029A"))
|
||||||
(type-manual "379A" 2)))
|
(is = 60 (fewest-presses 3 "980A"))
|
||||||
|
(is = 68 (fewest-presses 3 "179A"))
|
||||||
|
(is = 64 (fewest-presses 3 "456A"))
|
||||||
|
(is = 64 (fewest-presses 3 "379A")))
|
||||||
|
|
||||||
|
|
||||||
(define-test+run test-part1
|
(define-test+run test-part1
|
||||||
:parent suite-2024-21
|
:parent suite-2024-21
|
||||||
(is equal 126384 (part1 sample-data)))
|
(is equal 126384 (part1 sample-data)))
|
||||||
|
|
||||||
(define-test+run test-part2
|
|
||||||
:parent suite-2024-21
|
;; 143919110618572
|
||||||
(is equal nil (part2 sample-data)))
|
;; 167389793580400
|
||||||
|
|
Loading…
Reference in a new issue