Advent-of-Code/day18-scratch.lisp

167 lines
6.0 KiB
Common Lisp

;; ;; https://adventofcode.com/2022/day/18
;; so, 1x1x1 cubes on grid, given by x-y-z coords,
;; so each line is 1 cube.
;;
;; my guess is 1,1,1 is cube [0,1]x[0,1]x[0,1]
;; and 2,1,1 is cube [1,2]x[0,1]x[0,1]
;;
;; for cubes to have "joint" side - two dimentions should be totally same
;;
;; so, could do what? put into 3d array?
;; have 3 hash tables?
;;
;; allright, looking at discussions already.
;; i "could" consider these as graph nodes, but what would be the edges?
;;
;; the 3d array would be 'connectivity' matrix
;; then i'd want what ? go through all the nodes.
;; and for each node know how many neighbors it has.
;; that would directly transform into how many sides are open.
;; ok, i guess
(defparameter *day-18-test-input*
(mapcar
(lambda (line)
(mapcar #'parse-integer (cl-ppcre:split "," line)))
(uiop:read-file-lines "day18-test.txt")))
(setq *day-18-test-input* (coords-from-input "day18-test.txt"))
;; so. init array and fill with nodes
;; figure out maximal values?
(loop
for (x y z) in *day-18-test-input*
maximize x into xs
maximize y into ys
maximize z into zs
finally (return (list xs ys zs)))
;; => (3 3 6)
(defparameter *day-18-test-graph-connectivity*
(make-array '(4 4 7) :initial-element 0))
;; fill the array with nodes
(loop
for (x y z) in *day-18-test-input*
do (setf (aref *day-18-test-graph-connectivity* x y z) 1))
;; and now would have to do full scan? that's not very fun =/
;; well, it's not quite what a connectivity matrix is, isn't it?
;; connectivity has 1 in (i j) if from node i to node j there's edge
;; and it current case we have only 1 unit length connections.
;; here's that
(neighbors-for '(2 2 2) *day-18-test-graph-connectivity*)
(neighbors-for '(1 1 1) *day-18-test-graph-connectivity*)
(neighbors-for '(2 3 5) *day-18-test-graph-connectivity*)
;; and now to iterate over all of the array?
;; how'd i do safer aref?
;; well, i guess ok.
(apply #'aref *day-18-test-graph-connectivity* '(2 3 5))
;; this is first time i see something like this
;; how to use that correctly though?
;; so, last value must be a list, and all values are appended
;; so just numbers and nil in the end would work?
;; and more importatntly passing array as just self works.
;; and splitting points as two lists should work, right?
(apply #'aref *day-18-test-graph-connectivity* 2 3 '(5))
;; no, it doesn't, only one by one with last thing as list
;; now loop over all elements as ask amount of neighbors and sum 6-neighbors?
(loop for x from 0 to 3 sum
(loop for y from 0 to 3 sum
(loop for z from 0 to 6
when (= 1 (aref *day-18-test-graph-connectivity* x y z))
summing (- 6
(length (neighbors-for (list x y z)
*day-18-test-graph-connectivity*)))
;; into the-sum
;; collecting (list x y z)
;; into nodes
;; finally (return (list the-sum nodes))
)
))
;; => (42 ((0 0 0) (0 0 1) (0 0 2) (0 0 3) (0 0 4) (0 0 5) (0 0 6)))
(neighbors-for '(2 2 2) *day-18-test-graph-connectivity*)
;; well it's not quite so pliant to use multiple 'summing 'collecting 'max 'into
;; when working with nested loops then
;; for those cases DO macro? =C
(count-open-sides *day-18-test-graph-connectivity*)
;; now for my own input?
(defparameter *day-18-input-coords* nil)
(setq *day-18-input-coords*
(coords-from-input "day18-input.txt"))
(defparameter *day-18-input-connectivity*
(make-array (find-maxes *day-18-input-coords*) :initial-element 0))
(fill-connectivity-array *day-18-input-coords* *day-18-input-connectivity*)
(count-open-sides *day-18-input-connectivity*)
;; now. how could i only include surface area
;; did i need to model points as what?
;;
;; well, i could start with 0th layer. there's no stone there, only air
;; and start filling with 2
;; then count for all points as previously, but only neighbors which are 2
;; i guess
;; so. start at '(0 0 0)
;; then get neighbors, filter those that are 0
;; put into queue / list - actually dfs is good enough, so just recurse?
(point-at-is '(0 0 0) *day-18-test-graph-connectivity* 0)
(point-at-is '(0 0 0) *day-18-test-graph-connectivity* 2)
(fill-outside-with-2 '(0 0 0) *day-18-test-graph-connectivity*)
;; this seems to work.
;; now i want to cound only outside that contacts 2?
;; so, same cound but look for neighbors 2 and count them, not 6 - stone-neighbors
(count-open-sides-to-outside *day-18-test-graph-connectivity*)
;; well, now i need to add 1 to all sides
(setq *day-18-test-input*
(coords-from-input "day18-test.txt"))
(setq *day-18-test-graph-connectivity*
(make-array (find-maxes *day-18-test-input*) :initial-element 0))
(fill-connectivity-array *day-18-test-input* *day-18-test-graph-connectivity*)
(fill-outside-with-2 '(0 0 0) *day-18-test-graph-connectivity*)
(count-open-sides-to-outside *day-18-test-graph-connectivity*)
;; and now it's 58
;; so, let's cound for full input?
;;; part 2
(setq *day-18-input-coords*
(coords-from-input "day18-input.txt"))
(setq *day-18-input-connectivity*
(make-array (find-maxes *day-18-input-coords*) :initial-element 0))
(fill-connectivity-array *day-18-input-coords* *day-18-input-connectivity*)
(fill-outside-with-2 '(0 0 0) *day-18-input-connectivity*)
(count-open-sides-to-outside *day-18-input-connectivity*)
;; 2484 - not correct, too low
;; there's 1 at the edge of the array. whoops. so there are 0s in the input?
;; yep. so now what, shift all by 1? and add one more +1 to the find max?
;; hahaha, this is stupid.
;; but let's do it
(coords-from-input "day18-test.txt") ; yep. +1
;; 2490