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