230 lines
6.9 KiB
Common Lisp
230 lines
6.9 KiB
Common Lisp
;; https://adventofcode.com/2022/day/22
|
|
(in-package :day-22)
|
|
|
|
;; monkey map. so, i'd want to store the map.
|
|
|
|
;; and have functions that return "neighbors" maybe as alist?
|
|
;; neighbor is the right place to calculate wrapping around empty space
|
|
|
|
;; on top of neighbors get walkable directions
|
|
|
|
;; how to best represent coord?
|
|
|
|
;; next - moving
|
|
|
|
;; looking at the map of input. maybe somehow precompute where to jump on the map?
|
|
;; nah.
|
|
;; so, let's get map. with chars space, dot, hash
|
|
;; have line of spaces at the start, end, left and right?
|
|
;; that would shift coords by +1
|
|
|
|
;; and i'd also like what? i'd also like to store the path?
|
|
;; when exiting save that last orientation at the point?
|
|
;; and only treat space and hast as special, dot and arrows as walkable
|
|
|
|
;; or i could print "every snapshot" with setting and removing the walkout
|
|
;; i could split the input into files, that would simplify things
|
|
|
|
;; let's read the map into array?
|
|
(setq *ugh*
|
|
(let* ((lines (uiop:read-file-lines "day22-test-map.txt"))
|
|
(rows (length lines))
|
|
(cols (apply #'max (mapcar #'length lines)))
|
|
(arr (make-array (list (+ 2 rows) (+ 2 cols)) ; adding for padding row of empty space
|
|
:initial-element #\ )))
|
|
(loop for row from 0 below rows
|
|
for line = (coerce (nth row lines) 'array)
|
|
do (loop for col from 0 below cols
|
|
for char = (if (array-in-bounds-p line col) (aref line col) #\ )
|
|
do (setf (aref arr (1+ row) (1+ col)) char)))
|
|
arr))
|
|
|
|
(setq *test-arr-out-bounds* (make-array '(2 2) :initial-element #\. :adjustable t))
|
|
|
|
|
|
(print-map *ugh*)
|
|
;; yep, this is what i want
|
|
|
|
(print-map (read-map-to-array "day22-map.txt"))
|
|
(setq *ugh* (read-map-to-array "day22-test-map.txt"))
|
|
;; seems to work.
|
|
;; what are next steps?
|
|
;;
|
|
;; for some coords get neighboring to four sides
|
|
;; this should just return coords even with wrapping
|
|
|
|
;; let's first do function that returns coord or wrapped coord if value is space?
|
|
|
|
(alexandria:assoc-value *movements* 'left)
|
|
|
|
;; so from coord as list to updated coord
|
|
(move-coord-one-step '(1 1) 'right)
|
|
|
|
;; next should check the value of the moved. and if it's space -
|
|
;; calculate wrap
|
|
;; would also take the map array
|
|
;; if we're out of bounds, just skip this movement. shouldn't happen in my data
|
|
|
|
(opposite-movement 'left)
|
|
(opposite-movement 'right)
|
|
(opposite-movement 'down)
|
|
(opposite-movement 'up)
|
|
|
|
(apply #'aref *ugh* '(1 12))
|
|
|
|
;; now i need to check that. hm.
|
|
*ugh*
|
|
(print-map *ugh*)
|
|
'(4 1) ; begining of part
|
|
|
|
|
|
(move-with-possible-wrap '(5 1) 'left *ugh*)
|
|
(aref *ugh* 5 0)
|
|
(let ((coord '(5 1))
|
|
(map *ugh*)
|
|
(direction 'left))
|
|
(do
|
|
((mov-coord coord
|
|
(move-coord-one-step mov-coord (opposite-movement direction))))
|
|
((equal #\ (apply #'aref map mov-coord)) (move-coord-one-step mov-coord direction))))
|
|
|
|
;; now? um
|
|
|
|
(move-with-possible-wrap '(5 2) 'up *ugh*) ; now that seems ok
|
|
|
|
;; next is from 'move-with-possible-wrap
|
|
;; i guess i'd alreay want to display?
|
|
;; set X on that coord?
|
|
|
|
|
|
|
|
(display-coord '(5 2) *ugh*)
|
|
(display-coord (move-with-possible-wrap '(5 2) 'up *ugh*) *ugh*)
|
|
;; yeah, kind of ok.
|
|
|
|
;; what next? simulate movement?
|
|
|
|
(move 4 'right '(1 1) *ugh*)
|
|
|
|
(display-coord '(6 1) *ugh*)
|
|
(display-coord (move 4 'right '(6 1) *ugh*) *ugh*)
|
|
|
|
(display-coord '(6 8) *ugh*)
|
|
(display-coord (move-with-possible-wrap '(6 8) 'left *ugh*) *ugh*)
|
|
(display-coord (move 1 'left '(6 8) *ugh*) *ugh*)
|
|
(display-coord (move 2 'left '(6 8) *ugh*) *ugh*)
|
|
(display-coord (move 3 'left '(6 8) *ugh*) *ugh*)
|
|
|
|
(display-coord '(6 8) *ugh*)
|
|
(display-coord (move-with-possible-wrap '(6 8) 'right *ugh*) *ugh*)
|
|
(display-coord (move 1 'right '(6 8) *ugh*) *ugh*)
|
|
(display-coord (move 2 'right '(6 8) *ugh*) *ugh*)
|
|
(display-coord (move 3 'right '(6 8) *ugh*) *ugh*)
|
|
|
|
(display-coord '(6 2) *ugh*)
|
|
(display-coord (move-with-possible-wrap '(6 2) 'left *ugh*) *ugh*)
|
|
(display-coord (move 1 'left '(6 2) *ugh*) *ugh*)
|
|
(display-coord (move 2 'left '(6 2) *ugh*) *ugh*)
|
|
(display-coord (move 3 'left '(6 2) *ugh*) *ugh*)
|
|
(display-coord (move 4 'left '(6 2) *ugh*) *ugh*)
|
|
(display-coord (move 5 'left '(6 2) *ugh*) *ugh*)
|
|
(display-coord (move 6 'left '(6 2) *ugh*) *ugh*)
|
|
;; ok, i guess
|
|
;;
|
|
;; and now code the walk?
|
|
|
|
(defparameter *test-path* "10R5L5R10L4R5L5")
|
|
(ppcre:split "(L|R|U|D])" *test-path* :with-registers-p t )
|
|
;; somewhat of what i want, but also lrud into words
|
|
|
|
|
|
(mapcar #'parse-integer-or-symbol
|
|
(ppcre:split "(L|R)" *test-path* :with-registers-p t ))
|
|
;; initial number is "forward" from initial direction
|
|
;; oh, so the path is with turns Right turn or Left turn.
|
|
;; with initial Right
|
|
;; so, now i'd want a fuction that transformes direction
|
|
;; i guess i could what? make cyclic list? not quite i guess
|
|
|
|
(alexandria:circular-list 'up 'right 'down 'left)
|
|
(position 'up (alexandria:circular-list 'up 'right 'down 'left))
|
|
(nth (mod -1 4) (alexandria:circular-list 'up 'right 'down 'left))
|
|
;; yeah i guess
|
|
|
|
(new-direction 'UP 'L)
|
|
(new-direction 'LEFT 'L)
|
|
(new-direction 'down 'L)
|
|
(new-direction 'right 'L)
|
|
|
|
(new-direction 'UP 'R)
|
|
(new-direction 'LEFT 'R)
|
|
(new-direction 'down 'R)
|
|
(new-direction 'right 'R)
|
|
;; yay. that's kind of ok
|
|
|
|
;; now. ugh
|
|
|
|
;; yup, let's add that in code...
|
|
(append (read-path "day22-test-path.txt") (list 'L))
|
|
(read-path "day22-path.txt")
|
|
;; the path is "go N to your direction"
|
|
;; then L or R to change direction
|
|
;; so, now the main loop?
|
|
;; i guess i could add one more R or L to the end
|
|
;; and treat path as (n turn-direction)
|
|
;; oh, but the final direction is part of the answer
|
|
|
|
;; OK, LET'S add L to the end
|
|
|
|
(let ((padded-path (append (read-path "day22-test-path.txt") (list 'L)))
|
|
(direction 'right)
|
|
(coords '(1 1)) ; to be calculated
|
|
(map *ugh*)
|
|
)
|
|
(loop
|
|
for (n turn-direction) on padded-path by #'cddr
|
|
|
|
do (progn
|
|
(setq coords (move n direction coords map))
|
|
(setq direction (new-direction direction turn-direction)))
|
|
finally (return (list coords direction))))
|
|
|
|
;; hoho. the task requires indices starting from 1, cool
|
|
;; and i did 1 too many left turns, so let's turn right
|
|
;; UP to right, is RIGHT
|
|
;; and 0 for right, cool
|
|
;; yay! now let's clean it up.
|
|
|
|
;; one more thing. determining top leftmost point.
|
|
(get-topmost-left-coords *ugh*)
|
|
(print-map *ugh*)
|
|
|
|
(apply #'calc-password (walk-path "day22-test-path.txt" "day22-test-map.txt"))
|
|
|
|
(apply #'calc-password (walk-path "day22-path.txt" "day22-map.txt"))
|
|
;; 11464
|
|
;; and one gold star.
|
|
|
|
;;; and PART 2.
|
|
;; then neighbors is different
|
|
;; especially the wrap thing.
|
|
;; how'd i calc that? for the map? ugh
|
|
|
|
;; so, it's 6 parts. huh. ugh
|
|
;; oh, they're oblong, but they are all 4 by 4
|
|
|
|
|
|
|
|
;; XX
|
|
;; X
|
|
;; XX
|
|
;; X
|
|
|
|
;; outline of my input
|
|
;; how do i get freaking folding?
|
|
;; ugh.
|
|
;; maybe go for the next? um.
|
|
|
|
;; yeah. i'm giving up for now. let's go to rest for the new years. 19:33 of Dec 31st
|
|
;; fare well Common Lisp, I'll return to use in Q2 or Q3
|