373 lines
14 KiB
Common Lisp
373 lines
14 KiB
Common Lisp
;;; 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.
|