day 12 - paths over grid; dfs
This commit is contained in:
parent
f612d15eed
commit
047bc474bd
|
@ -0,0 +1,41 @@
|
|||
abcccccccaaaaaccccaaaaaaaccccccccccccccccccccccccccccccccccccaaaaa
|
||||
abaacccaaaaaaccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccaaaaaa
|
||||
abaacccaaaaaaaccccaaaaaaaaaaaaaacccccccccccccaacccccccccccccaaaaaa
|
||||
abaacccccaaaaaacaaaaaaaaaaaaaaaacccccccccccccaacccccccccccccacacaa
|
||||
abaccccccaaccaacaaaaaaaaaacccaacccccccccccccaaacccccccccccccccccaa
|
||||
abcccccccaaaacccaaaaaaaaacccccccccccccaaacccaaacccccccccccccccccaa
|
||||
abccccccccaaaccccccccaaaacccccccccccccaaaaacaaaccacacccccccccccccc
|
||||
abccccccccaaacaaacccccaaacccccccccccccaaaaaaajjjjjkkkcccccaacccccc
|
||||
abcccccaaaaaaaaaacccccaaccccccccccciiiiiijjjjjjjjjkkkcaaaaaacccccc
|
||||
abcccccaaaaaaaaacccccccccccccccccciiiiiiijjjjjjjrrkkkkaaaaaaaacccc
|
||||
abcccccccaaaaaccccccccccccccccccciiiiiiiijjjjrrrrrppkkkaaaaaaacccc
|
||||
abcccaaccaaaaaacccccccccccaacaaciiiiqqqqqrrrrrrrrpppkkkaaaaaaacccc
|
||||
abccaaaaaaaaaaaaccccacccccaaaaaciiiqqqqqqrrrrrruuppppkkaaaaacccccc
|
||||
abcccaaaaaaacaaaacaaacccccaaaaaahiiqqqqtttrrruuuuupppkkaaaaacccccc
|
||||
abcaaaaaaaccccaaaaaaacccccaaaaaahhqqqtttttuuuuuuuuuppkkkccaacccccc
|
||||
abcaaaaaaaaccccaaaaaacccccaaaaaahhqqqtttttuuuuxxuuuppkklcccccccccc
|
||||
abcaaaaaaaacaaaaaaaaaaacccccaaachhhqqtttxxxuuxxyyuuppllllccccccccc
|
||||
abcccaaacaccaaaaaaaaaaaccccccccchhhqqtttxxxxxxxyuupppplllccccccccc
|
||||
abaacaacccccaaaaaaaaaaaccccccccchhhqqtttxxxxxxyyvvvpppplllcccccccc
|
||||
abaacccccccccaaaaaaacccccccccccchhhpppttxxxxxyyyvvvvpqqqlllccccccc
|
||||
SbaaccccccaaaaaaaaaaccccccccccchhhppptttxxxEzzyyyyvvvqqqlllccccccc
|
||||
abaaaaccccaaaaaaaaacccccccccccchhhpppsssxxxyyyyyyyyvvvqqqlllcccccc
|
||||
abaaaacccccaaaaaaaacccccccccccgggpppsssxxyyyyyyyyyvvvvqqqlllcccccc
|
||||
abaaacccaaaacaaaaaaaccccccccccgggpppsswwwwwwyyyvvvvvvqqqllllcccccc
|
||||
abaaccccaaaacaaccaaaacccccccccgggppssswwwwwwyyywvvvvqqqqmmmccccccc
|
||||
abaaccccaaaacaaccaaaaccaaaccccggpppssssswwswwyywvqqqqqqmmmmccccccc
|
||||
abcccccccaaacccccaaacccaaacaccgggpppssssssswwwwwwrqqmmmmmccccccccc
|
||||
abcccccccccccccccccccaacaaaaacgggppooosssssrwwwwrrrmmmmmcccccccccc
|
||||
abcccccccccccccccccccaaaaaaaacggggoooooooorrrwwwrrnmmmdddccaaccccc
|
||||
abaccccccccccccaacccccaaaaaccccggggoooooooorrrrrrrnmmddddcaaaccccc
|
||||
abaccccccccaaaaaaccccccaaaaaccccggfffffooooorrrrrnnndddddaaaaccccc
|
||||
abaacccccccaaaaaacccccaaaaaacccccffffffffoonrrrrrnnndddaaaaaaacccc
|
||||
abaaccccccccaaaaaaaccacaaaacccccccccffffffonnnnnnnndddaaaaaaaacccc
|
||||
abccccccccccaaaaaaaaaaaaaaaccccccccccccfffennnnnnnddddccaaaccccccc
|
||||
abcccccccccaaaaaaacaaaaaaaaaacccccccccccffeennnnnedddccccaaccccccc
|
||||
abcccccccccaaaaaaccaaaaaaaaaaaccccccccccaeeeeeeeeeedcccccccccccccc
|
||||
abccccccccccccaaaccaaaaaaaaaaaccccccccccaaaeeeeeeeecccccccccccccaa
|
||||
abcccccccaaccccccccaaaaaaaacccccccccccccaaaceeeeecccccccccccccccaa
|
||||
abaaccaaaaaaccccccccaaaaaaaacccccccccccccaccccaaacccccccccccaaacaa
|
||||
abaaccaaaaacccccaaaaaaaaaaacccccccccccccccccccccacccccccccccaaaaaa
|
||||
abaccaaaaaaaaccaaaaaaaaaaaaaacccccccccccccccccccccccccccccccaaaaaa
|
|
@ -0,0 +1,239 @@
|
|||
;;; https://jira.ringcentral.com/browse/ANY-13016
|
||||
|
||||
;; climbind the hill - only 1 elevation higher, any elevation lower
|
||||
;; only movements UP, DOWN, LEFT, RIGHT.
|
||||
;; bfs should do.
|
||||
;; and hide current character in order to prevent backtracking
|
||||
|
||||
;; so. from start (consider it to be 'a')
|
||||
;; one iteration is:
|
||||
;; collect neighbors, filter them to only have applicable neighbors elevation +1 or lover
|
||||
;; hide current place, run dfs from the neighbors - it should return the shortest path from them or -1
|
||||
;; then select shortest path add +1 and return to parent
|
||||
|
||||
;; not sure which structures would be more comfortable
|
||||
|
||||
(defparameter *day-12-test-lines*
|
||||
(mapcar (lambda (line) (cl-ppcre:split "" line)) (uiop:read-file-lines "day12-test.txt")))
|
||||
|
||||
(defparameter *test-array* (make-array (list (length *day-12-test-lines*) (length (first *day-12-test-lines*)))))
|
||||
(array-dimensions *test-array*)
|
||||
|
||||
(destructuring-bind (rows cols) (array-dimensions *test-array*)
|
||||
(loop for row from 0 below rows do
|
||||
(loop for col from 0 below cols do
|
||||
(setf (aref *test-array* row col)
|
||||
(nth col (nth row *day-12-test-lines*))))))
|
||||
|
||||
(coerce (coerce "a" 'character) 'integer)
|
||||
(char-code (coerce "a" 'character))
|
||||
|
||||
|
||||
(- "c" "a")
|
||||
(- #\c #\a)
|
||||
(eq #\c #\a)
|
||||
(eq #\a #\a)
|
||||
|
||||
;; next - instead of S set a, instead of E set z
|
||||
;; and store S and E coords in a parameter
|
||||
|
||||
(destructuring-bind (rows cols) (array-dimensions *test-array*)
|
||||
(loop for row from 0 below rows do
|
||||
(loop for col from 0 below cols do
|
||||
(let* ((input-place-string (nth col (nth row *day-12-test-lines*)))
|
||||
(input-char (coerce input-place-string 'character)))
|
||||
(when (eq #\S input-char)
|
||||
(setq input-char #\a)
|
||||
;; set coords for start
|
||||
)
|
||||
(when (eq #\E input-char)
|
||||
(setq input-char #\z)
|
||||
;; set end coords
|
||||
)
|
||||
(setf (aref *test-array* row col)
|
||||
input-char)))))
|
||||
|
||||
*test-array*
|
||||
|
||||
;; well. nah, using different parameters is not cool
|
||||
;; next steps:
|
||||
;;
|
||||
;; function to get next points to check
|
||||
(defun get-neighbors (row col)
|
||||
(list (list row (1- col))
|
||||
(list (1- row) col)
|
||||
(list row (1+ col))
|
||||
(list (1+ row) col)))
|
||||
|
||||
(defun coord-in-dimentions (coords array)
|
||||
(destructuring-bind (row col) coords
|
||||
(destructuring-bind (rows cols) (array-dimensions array)
|
||||
(and (>= row 0)
|
||||
(>= col 0)
|
||||
(< row rows)
|
||||
(< col cols)))))
|
||||
|
||||
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords *array*) coords))
|
||||
(get-neighbors 0 0))
|
||||
(array-dimensions *array*) ; (5 8) -
|
||||
|
||||
(defun get-neighbors-in-array (coords array)
|
||||
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords array) coords))
|
||||
(apply #'get-neighbors coords )))
|
||||
|
||||
(get-neighbors-in-array '(0 0) *array*)
|
||||
(get-neighbors-in-array '(1 1) *array*)
|
||||
(get-neighbors-in-array '(2 2) *array*)
|
||||
|
||||
;; function to filter to be inside of array
|
||||
|
||||
(defun move-valid-p (cur-char next-char)
|
||||
(and (>= 1 (- (char-code next-char)
|
||||
(char-code cur-char)))
|
||||
(not (eq next-char #\%))))
|
||||
|
||||
(move-valid-p #\a #\a)
|
||||
(move-valid-p #\a #\b)
|
||||
(move-valid-p #\a #\c)
|
||||
(move-valid-p #\a #\z)
|
||||
(move-valid-p #\a #\%)
|
||||
|
||||
;; function to check if target letter valid step from current letter
|
||||
;; one-step function
|
||||
|
||||
;; now the function would have to be recursive
|
||||
(defun recursive-search-min-path (coords array end-coords)
|
||||
(if (equal coords end-coords)
|
||||
0
|
||||
(let* ((neighbour-coords (get-neighbors-in-array coords array))
|
||||
(cur-char (aref array (first coords) (second coords)))
|
||||
(valid-next-steps (remove-if-not
|
||||
(lambda (coords)
|
||||
(let ((next-step-char
|
||||
(aref array (first coords) (second coords))))
|
||||
(move-valid-p cur-char next-step-char)))
|
||||
neighbour-coords)))
|
||||
(if (not valid-next-steps)
|
||||
999999
|
||||
(progn
|
||||
(setf (aref array (first coords) (second coords)) #\%)
|
||||
(setq lengts-from-next-steps (mapcar
|
||||
(lambda (next-coords)
|
||||
(recursive-search-min-path next-coords array end-coords))
|
||||
valid-next-steps))
|
||||
(setf (aref array (first coords) (second coords)) cur-char)
|
||||
(1+ (apply #'min lengts-from-next-steps)))))))
|
||||
|
||||
(print (recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords))
|
||||
(recursive-search-min-path *day-12-start-coords *array* '(0 0))
|
||||
(recursive-search-min-path *day-12-start-coords *array* '(0 1))
|
||||
(recursive-search-min-path *day-12-start-coords *array* '(1 1))
|
||||
|
||||
;; yes. finally
|
||||
|
||||
(eq '(1 2) '(1 2))
|
||||
(apply #'min '(1 3 -1))
|
||||
(apply #'min '(-1))
|
||||
(apply #'min '())
|
||||
|
||||
(not '())
|
||||
(not '(1 2))
|
||||
|
||||
(defun search-min-path ()
|
||||
|
||||
(defun recursive-search-min-path (coords array end-coords accum-path)
|
||||
(if (equal coords end-coords)
|
||||
(return-from search-min-path accum-path)
|
||||
(let* ((neighbour-coords (get-neighbors-in-array coords array))
|
||||
(cur-char (aref array (first coords) (second coords)))
|
||||
(valid-next-steps (remove-if-not
|
||||
(lambda (coords)
|
||||
(let ((next-step-char
|
||||
(aref array (first coords) (second coords))))
|
||||
(move-valid-p cur-char next-step-char)))
|
||||
neighbour-coords)))
|
||||
(if (not valid-next-steps)
|
||||
999999
|
||||
(progn
|
||||
(format t "reaching coord ~a~%" coords)
|
||||
(setf (aref array (first coords) (second coords)) #\%)
|
||||
(setq lengts-from-next-steps (mapcar
|
||||
(lambda (next-coords)
|
||||
(recursive-search-min-path next-coords array end-coords (1+ accum-path)))
|
||||
valid-next-steps))
|
||||
(setf (aref array (first coords) (second coords)) cur-char)
|
||||
(1+ (apply #'min lengts-from-next-steps)))))))
|
||||
(recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords 0))
|
||||
|
||||
(print (recursive-search-min-path *day-12-start-coords *array* *day-12-end-coords))
|
||||
(print (search-min-path))
|
||||
|
||||
;; wait. i'm doing dfs here, right?
|
||||
;; for bfs i need to queue the next points. ugh
|
||||
|
||||
(defun bfs-search-min-path (next-points-to-check)
|
||||
(if (not next-points-to-check)
|
||||
-1 ; if exhausted reachable coords
|
||||
(let ((currently-checking (first next-points-to-check))
|
||||
(rest-to-check (rest next-points-to-check)))
|
||||
(destructuring-bind (coords accum-path) currently-checking
|
||||
(if (equal coords *day-12-end-coords)
|
||||
accum-path
|
||||
(let* ((neighbour-coords (get-neighbors-in-array coords *array*))
|
||||
(cur-char (aref *array* (first coords) (second coords)))
|
||||
(valid-next-steps (remove-if-not
|
||||
(lambda (coords)
|
||||
(let ((next-step-char
|
||||
(aref *array* (first coords) (second coords))))
|
||||
(move-valid-p cur-char next-step-char)))
|
||||
neighbour-coords)))
|
||||
|
||||
(format t "reaching coord ~a~%" coords)
|
||||
(setf (aref *array* (first coords) (second coords)) #\%)
|
||||
;; format is '((1 1) 4) - coords and lenght-up-to
|
||||
(setq next-steps-with-length (mapcar
|
||||
(lambda (next-coords)
|
||||
(list next-coords (1+ accum-path)))
|
||||
valid-next-steps))
|
||||
;; (setf (aref *array* (first coords) (second coords)) cur-char)
|
||||
;; (1+ (apply #'min lengts-from-next-steps))
|
||||
(bfs-search-min-path
|
||||
(concatenate 'list rest-to-check next-steps-with-length))))))))
|
||||
|
||||
;; so, with bfs there's no need to revert the previous chars?
|
||||
|
||||
(concatenate 'list '(12 3) '(5 4))
|
||||
(concatenate 'list '(12 3) '())
|
||||
|
||||
(bfs-search-min-path (list (list *day-12-start-coords 0)))
|
||||
*array*
|
||||
|
||||
(destructuring-bind (coords accum-path) '((1 2) 3)
|
||||
`(got ,coords and ,accum-path))
|
||||
|
||||
;;; PART 2
|
||||
|
||||
;; find shortest path from every point at elevation #\a
|
||||
|
||||
;; so, i'd need to reuse my function from different starting points
|
||||
;; and reset the array after each search
|
||||
|
||||
;; so. collect coords for all starting points
|
||||
;; hm, yeah, only difference with just starting with all of them - need to reset the array
|
||||
|
||||
(defparameter *day-12-2-starting-points '())
|
||||
|
||||
(destructuring-bind (rows cols) (array-dimensions *array*)
|
||||
(loop for row from 0 below rows do
|
||||
(loop for col from 0 below cols do
|
||||
(when (eq #\a (aref *array* row col))
|
||||
(push `((,row ,col) 0) *day-12-2-starting-points)))))
|
||||
|
||||
(defparameter *day-12-2-all-trail-lengts* nil)
|
||||
|
||||
(setq *day-12-2-all-trail-lengts*
|
||||
(loop for start-point in *day-12-2-starting-points
|
||||
collect (bfs-search-min-path (list start-point))
|
||||
do (restore-params)))
|
||||
|
||||
(first (sort *day-12-2-all-trail-lengts* #'<))
|
|
@ -0,0 +1,5 @@
|
|||
Sabqponm
|
||||
abcryxxl
|
||||
accszExk
|
||||
acctuvwj
|
||||
abdefghi
|
|
@ -0,0 +1,117 @@
|
|||
;;; https://jira.ringcentral.com/browse/ANY-13016
|
||||
|
||||
;; (defparameter *day-12-file-name* "day12-test.txt")
|
||||
(defparameter *day-12-file-name* "day12-input.txt")
|
||||
(defparameter *day-12-lines* nil)
|
||||
(defparameter *day-12-start-coords nil)
|
||||
(defparameter *day-12-end-coords nil)
|
||||
(defparameter *array* nil)
|
||||
|
||||
(defun restore-params ()
|
||||
(setq *day-12-lines*
|
||||
(mapcar (lambda (line) (cl-ppcre:split "" line)) (uiop:read-file-lines *day-12-file-name*)))
|
||||
(setq *array* (make-array (list (length *day-12-lines*) (length (first *day-12-lines*)))))
|
||||
|
||||
(destructuring-bind (rows cols) (array-dimensions *array*)
|
||||
(loop for row from 0 below rows do
|
||||
(loop for col from 0 below cols do
|
||||
(let* ((input-place-string (nth col (nth row *day-12-lines*)))
|
||||
(input-char (coerce input-place-string 'character)))
|
||||
(when (eq #\S input-char)
|
||||
(setq input-char #\a)
|
||||
(setq *day-12-start-coords (list row col))
|
||||
)
|
||||
(when (eq #\E input-char)
|
||||
(setq input-char #\z)
|
||||
(setq *day-12-end-coords (list row col))
|
||||
;; set end coords
|
||||
)
|
||||
(setf (aref *array* row col)
|
||||
input-char))))))
|
||||
(restore-params)
|
||||
|
||||
*array*
|
||||
(array-dimensions *array*)
|
||||
*day-12-start-coords
|
||||
*day-12-end-coords
|
||||
|
||||
;; yay.
|
||||
|
||||
(defun get-neighbors (row col)
|
||||
(list (list row (1- col))
|
||||
(list (1- row) col)
|
||||
(list row (1+ col))
|
||||
(list (1+ row) col)))
|
||||
|
||||
(defun coord-in-dimentions (coords array)
|
||||
(destructuring-bind (row col) coords
|
||||
(destructuring-bind (rows cols) (array-dimensions array)
|
||||
(and (>= row 0)
|
||||
(>= col 0)
|
||||
(< row rows)
|
||||
(< col cols)))))
|
||||
|
||||
(defun get-neighbors-in-array (coords array)
|
||||
(remove-if-not (lambda (coords) (when (coord-in-dimentions coords array) coords))
|
||||
(apply #'get-neighbors coords )))
|
||||
|
||||
(defun move-valid-p (cur-char next-char)
|
||||
(>= 1 (- (char-code next-char)
|
||||
(char-code cur-char))))
|
||||
|
||||
;; recursion
|
||||
|
||||
(defun bfs-search-min-path (next-points-to-check)
|
||||
(if (not next-points-to-check)
|
||||
999999 ; if exhausted reachable coords
|
||||
(let ((currently-checking (first next-points-to-check))
|
||||
(rest-to-check (rest next-points-to-check)))
|
||||
(destructuring-bind (coords accum-path) currently-checking
|
||||
(if (equal coords *day-12-end-coords)
|
||||
accum-path
|
||||
(let* ((neighbour-coords (get-neighbors-in-array coords *array*))
|
||||
(cur-char (aref *array* (first coords) (second coords)))
|
||||
(valid-next-steps (remove-if-not
|
||||
(lambda (coords)
|
||||
(let ((next-step-char
|
||||
(aref *array* (first coords) (second coords))))
|
||||
(move-valid-p cur-char next-step-char)))
|
||||
neighbour-coords)))
|
||||
|
||||
(format t "reaching coord ~a~%" coords)
|
||||
(setf (aref *array* (first coords) (second coords)) #\%)
|
||||
;; format is '((1 1) 4) - coords and lenght-up-to
|
||||
(setq next-steps-with-length (mapcar
|
||||
(lambda (next-coords)
|
||||
(list next-coords (1+ accum-path)))
|
||||
valid-next-steps))
|
||||
;; (setf (aref *array* (first coords) (second coords)) cur-char)
|
||||
;; (1+ (apply #'min lengts-from-next-steps))
|
||||
(bfs-search-min-path
|
||||
(concatenate 'list rest-to-check next-steps-with-length))))))))
|
||||
|
||||
(bfs-search-min-path (list (list *day-12-start-coords 0)))
|
||||
;; 339
|
||||
|
||||
;; PART 2
|
||||
|
||||
(defparameter *day-12-2-starting-points '())
|
||||
(defparameter *day-12-2-all-trail-lengts* nil)
|
||||
|
||||
(progn
|
||||
;; get starting points
|
||||
(destructuring-bind (rows cols) (array-dimensions *array*)
|
||||
(loop for row from 0 below rows do
|
||||
(loop for col from 0 below cols do
|
||||
(when (eq #\a (aref *array* row col))
|
||||
(push `((,row ,col) 0) *day-12-2-starting-points)))))
|
||||
|
||||
;; calculate path lengths from all starting points
|
||||
(setq *day-12-2-all-trail-lengts*
|
||||
(loop for start-point in *day-12-2-starting-points
|
||||
collect (bfs-search-min-path (list start-point))
|
||||
do (restore-params))))
|
||||
;; get shortest of them
|
||||
(first (sort *day-12-2-all-trail-lengts* #'<))
|
||||
|
||||
;; yay. the shortest of all was 332
|
Loading…
Reference in New Issue