;;; https://www.youtube.com/watch?v=aGedUxTAfBk ;; tree is visible if from one of 4 directions there are only trees that are "strictly lower" ;; the computation reuse - if we checked the tree on the top before, and it's visible from top and lower - then currnt is visible ;; but if it's not visible from top, then we need to know which tree covered it up, to calculate whether current tree is taller than that. ;; ;; so. i'd want to i think this time actually use classes. to store visibility from the directions. ;; or rather for each tree store the highest tree towards the enge in the direction. ;; and would be possible to calculate visibility into a direction then ;; ;; so. have a class with hash-table of DIRECTION -> tallest-in-that-direction ;; i suppose can be done without storing this data. just go through the line against the checking direction, and store last tallest tree in var ;; could store visibility in the shared 2d array (loop :for i :across (vector 1 2 3 4) :do (print (* 5 i))) (coerce (list 1 2 3 4) 'vector) (require 'cl-ppcre) (cl-ppcre:split "" "hello") (coerce (mapcar #'parse-integer (cl-ppcre:split "" "30373" )) 'vector) ;; (defparameter *file-name* "day8-test-input.txt") (defparameter *file-name* "day8-input.txt") (progn (defparameter *trees-2d-vector* (let ((rows-accumulation ())) (with-open-file (in *file-name*) (loop for line = (read-line in nil nil) while line do (push (coerce (mapcar #'parse-integer (cl-ppcre:split "" line)) 'vector) rows-accumulation) ) (coerce (reverse rows-accumulation) 'vector)))) (defparameter *trees-rownum* (length *trees-2d-vector*)) (defparameter *trees-colnum* (length (aref *trees-2d-vector* 0)))) *trees-2d-vector* ;; (aref *trees-2d-vector* 3 0) ; error (let ((arr (make-array '(2 3)))) (setf (aref arr 1 1) "hello") arr) ; but can't access row at a time. ; ugh. ;; now. i'd want visibility matrix. with true on edges and false inside ;; then loop over lines / rows against the direction ;; store previous max height, if current is bigger - store it as previous max visible and ;; put visible into the shared matrix ;; ;; then do iteration against all directions, only updating table to true (ql:quickload "iterate") (use-package 'iterate) (defparameter *tree-vis-matr* (let* ((rows-count (length *trees-2d-vector*)) (cols-count (length (aref *trees-2d-vector* 0))) (visibility-matrix (make-array (list rows-count cols-count) :initial-element nil))) (iterate:iter (for rownum from 0 to (1- rows-count)) (iterate:iter (for colnum from 0 to (1- cols-count)) (if (or (= rownum 0) (= rownum (1- rows-count)) (= colnum 0) (= colnum (1- cols-count))) (setf (aref visibility-matrix rownum colnum) 'T)))) ;; cool ;; (loop ;; for rownum from 0 to (1- rows-count) ;; for colnum from 0 to (1- cols-count) ;; when (or (= rownum 0) ;; (= rownum (1- rows-count)) ;; (= colnum 0) ;; (= colnum (1- cols-count))) ;; do (progn ;; (setf (aref visibility-matrix rownum colnum) "hello") ;; )) ;; (setf (aref visibility-matrix 1 1) "hello") visibility-matrix)) ;; now for i j if (loop for rownum from 0 to 3 for colnum from 0 to 4 ;; when (or (= rownum 0) ;; (= rownum (1- rows-count)) ;; (= colnum 0) ;; (= colnum (1- cols-count))) collect rownum) (iterate:iter (for i from 1 to 5) (print i)) (iterate:iter (for i from 5 downto 1) (print i)) (iterate:iter (for item in '(1 2 3)) (print item)) ;; so. now i have visibility matrix wihch is 2d, ;; to store which trees are "visible" ;; and also i have Vector(Vectors) for tree sizes, for iteration. ;; ;; now ideally I'd be able to code these iterations in a compact way. ;; but i'm just ugh ;; no, just no. let's of iterations which i'm not sure how to generalize ;; and need to share state, upleasant ;; (defun nextPoint (row col direction) ;; (case direction ;; ('UP (list row (1- col))) ;; ('DOWN (list row (1+ col))) ;; ('LEFT (list (1- row) col)) ;; ('RIGHT (list (1+ row) col)))) ;; (nextpoint 1 1 'up) ;; (nextpoint 1 1 'left) ;; (nextpoint 1 1 'right) ;; (nextpoint 1 1 'down) ;; (apply #'nextpoint '(1 1 down)) ;; (apply #'+ '(1 2 3)) (defun gen-line-coords (startRow startCol rowNum colNum direction) (flet ((row-col-valid (row col) (and (>= row 0) (>= col 0) (< row rowNum) (< col colNum))) (nextPoint (row col) (case direction ('LEFT (list row (1- col))) ('RIGHT (list row (1+ col))) ('UP (list (1- row) col)) ('DOWN (list (1+ row) col))))) (let ((coords-collected ())) (do ((coords (list startRow startCol) (apply #'nextpoint coords))) ((not (apply #'row-col-valid coords)) (reverse coords-collected)) (push coords coords-collected))))) (gen-line-coords 0 0 4 5 'down) (gen-line-coords 0 0 4 5 'right) (gen-line-coords 3 4 4 5 'up) (gen-line-coords 2 4 4 5 'left) (apply #'gen-line-coords '(0 0 4 5 down)) ;; well, looks like this works ;; and then generic iteration on these coordinates? ;; store previous max tree. ;; if current is bigger than previous max - store it as previous max and put T into vix.matrix ;; i really dislike this task so far. (defparameter *test-line-coords* (gen-line-coords 1 0 4 5 'right)) (let ((biggest-tree-so-far -1)) (loop for coords in *test-line-coords* do (let* ((rownum (first coords)) (colnum (second coords)) (row (aref *trees-2d-vector* rownum)) (tree-size (aref row colnum))) (if (< biggest-tree-so-far tree-size) (progn (setq biggest-tree-so-far tree-size) (setf (aref *tree-vis-matr* rownum colnum) 't)))))) *test-line-coords* *trees-2d-vector* *tree-vis-matr* (aref *tree-vis-matr* 1 1) ;; well it kinda worked. ;; now i need to get all possible line-coords, with desired directions ;; and then run for each of these ;; and then - count amount of T in the resulting matr ;; getting all possible direction line-coords ;; (progn (defparameter *trees-right-line-coords* (loop for startRow from 0 below *trees-rownum* collect (gen-line-coords startRow 0 *trees-rownum* *trees-colnum* 'right))) (defparameter *trees-left-line-coords* (loop for startRow from 0 below *trees-rownum* collect (gen-line-coords startRow (1- *trees-colnum*) *trees-rownum* *trees-colnum* 'left))) (defparameter *trees-right-down-coords* (loop for startCol from 0 below *trees-colnum* collect (gen-line-coords 0 startCol *trees-rownum* *trees-colnum* 'down))) (defparameter *trees-right-up-coords* (loop for startCol from 0 below *trees-colnum* collect (gen-line-coords (1- *trees-rownum*) startCol *trees-rownum* *trees-colnum* 'up))) (defparameter *trees-all-line-coords* (concatenate 'list *trees-right-line-coords* *trees-left-line-coords* *trees-right-down-coords* *trees-right-up-coords*)) ;;; iterate over all col-lines (loop for coord-line in *trees-all-line-coords* do (let ((biggest-tree-so-far -1)) (loop for coords in coord-line do (let* ((rownum (first coords)) (colnum (second coords)) (row (aref *trees-2d-vector* rownum)) (tree-size (aref row colnum))) (if (< biggest-tree-so-far tree-size) (progn (setq biggest-tree-so-far tree-size) (setf (aref *tree-vis-matr* rownum colnum) 't))))))) *tree-vis-matr* ;; counting amount of 'T in the visibility matrix (let ((running-sum 0)) (iterate:iter (for rownum from 0 to (1- *trees-rownum*)) (iterate:iter (for colnum from 0 to (1- *trees-colnum*)) (if (aref *tree-vis-matr* rownum colnum) (incf running-sum 1)))) running-sum)) ;;; wow, 1835 was the right answer. urrgh ;;; now to the second part ;; and that's totally different thing now. ;; i guess i could use my "col-line" to get coords to check from the tree ;; for each tree take tail of coord line into each direction ;; and count how long to the first tree of at least same height. *trees-2d-vector* (defparameter *test-tree-coords* '(2 2)) (defparameter *test-line-coords* (gen-line-coords 3 3 4 5 'right)) (cdr *test-line-coords*) (eval `(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* 'right)) (defparameter *test-tree-direction-cols* (mapcar #'cdr (mapcar #'eval (mapcar (lambda (direction) `(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* ,direction) ) '('right 'down 'left 'up))))) (defun tree-size-by-coords (coords) (aref (aref *trees-2d-vector* (first coords)) (second coords))) (tree-size-by-coords '(1 1) ) (print (mapcar (lambda (coord-line) (mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*)) (defun take-while (list pred) (loop for elt in list while (funcall pred elt) collect elt)) (take-while '(1 2 3 3 3 4 5 6) (lambda (n) (>= 3 n))) ;; it's not it. ugh. why it's so hard. ;; how can i find index of first inclusion of element in list. ;; i guess i could do strict less than and add 1? no. (take-while '(1 2 3 3 3 4 5 6) (lambda (n) (> 3 n))) ;; and then if list i got not equal to initial list - add 1 because we dropped something? ;; UGH! ;; should be a better way. (do* ((start-tree-size (tree-size-by-coords '(3 3))) (coords-direction (car *test-tree-direction-cols*) (cdr coords-direction)) (coord (car coords-direction) (car coords-direction)) (coord-tree-size (tree-size-by-coords coord) (tree-size-by-coords coord)) (count 0 (1+ count))) ((or (not coords-direction) (> coord-tree-size start-tree-size)) (if ((= coord-tree-size start-tree-size) (1+ count) count)))) ;; i'm incredibly frustrated ;; more that an hour on trying to get initial part of list until first inclusion of target element. ;; horrible ;; ok. this monstrocity (let ((self 3) (found-self nil)) (loop for elt in '(1 2 2 3 1 5 1) while (and (not found-self) (>= self elt)) collect elt if (= elt self) do (setq found-self 't))) (defun my-get-prefix (trees-heights self-height) (let ((self self-height) (found-self nil)) (loop for elt in trees-heights while (not found-self) collect elt if (>= elt self) do (setq found-self 't)))) (my-get-prefix '(3 3 1 5 1 2) 4) (my-get-prefix '() 6) ;; ok. let's map that on top of other shit (print (mapcar (lambda (height-list) (length (my-get-prefix height-list 3))) (mapcar (lambda (coord-line) (mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*))) ;; and this was all inconsequential because for 3 seeing 3 and seing 5 is same end ;; so i could have used take-while with strict condition. ;; in any way would have needed to add 1? ;; will modify my ugly function, making it uglier, cool ;; ;; now need to multiply them and call that with correct coords for all inner trees. ;; this is pain. ;;; returning to calculating the directions from each tree *trees-2d-vector* (defparameter *test-tree-coords* '(4 2)) (defparameter *test-line-coords* (gen-line-coords 3 3 4 5 'right)) (defparameter *test-tree-direction-cols* (mapcar #'cdr (mapcar #'eval (mapcar (lambda (direction) `(gen-line-coords ,@*test-tree-coords* *trees-rownum* *trees-colnum* ,direction) ) '('right 'down 'left 'up))))) (defun get-tree-direction-cols (tree-coords) (mapcar #'cdr (mapcar #'eval (mapcar (lambda (direction) `(gen-line-coords ,@tree-coords *trees-rownum* *trees-colnum* ,direction) ) '('right 'down 'left 'up)))) ) (defun tree-size-by-coords (coords) (aref (aref *trees-2d-vector* (first coords)) (second coords))) (tree-size-by-coords '(1 1) ) (print (mapcar (lambda (coord-line) (mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*)) (print (mapcar (lambda (height-list) (length (my-get-prefix height-list 3))) (mapcar (lambda (coord-line) (mapcar #'tree-size-by-coords coord-line)) *test-tree-direction-cols*))) (apply #'* '(1 2 2 0)) (let ((cur-max -1)) (iterate:iter (for row from 1 to (1- *trees-rownum*)) (iterate:iter (for col from 1 to (1- *trees-colnum*)) (let* ((cur-tree-height (tree-size-by-coords (list row col))) (cur-tree-lines (get-tree-direction-cols (list row col))) (cur-tree-lines-tree-heights (mapcar (lambda (coord-line) (mapcar #'tree-size-by-coords coord-line)) cur-tree-lines)) (cur-tree-visibilities (mapcar (lambda (height-list) (length (my-get-prefix height-list cur-tree-height))) cur-tree-lines-tree-heights)) (cur-tree-score (apply #'* cur-tree-visibilities))) (if (> cur-tree-score cur-max) (setq cur-max cur-tree-score))))) cur-max) ;; wow. i got an aswer 8 ;; now try to recalculate this horrible thing with actual input.