day 15 p.1: scanners and beacons, bad solution
This commit is contained in:
185
day15-scratch.lisp
Normal file
185
day15-scratch.lisp
Normal file
@@ -0,0 +1,185 @@
|
||||
;; https://adventofcode.com/2022/day/15
|
||||
;;
|
||||
;; oh, wow. i can already imagine the second part of the task
|
||||
;; so. for arrangements of (sensor closest-beacon)
|
||||
;; i need to figure out which points are out of rangle for all sensors?
|
||||
;; where "range" is distance between sensor and the closest-beacon
|
||||
;;
|
||||
;; so for each sensor also store distance, and each sensor should be able to answer query for point
|
||||
;; whether it disproves existence of a beacone there
|
||||
;; then for ( POINTS x SENSORS ) computations i'll be able to mark all points that aren't covered.
|
||||
;;
|
||||
;; doesn't seem like too much
|
||||
|
||||
(ql:quickload 'cl-ppcre)
|
||||
;; poor man's parsing
|
||||
(rest (mapcar (lambda (str)
|
||||
(parse-integer str :junk-allowed t))
|
||||
(cl-ppcre:split "="
|
||||
"Sensor at x=2, y=18: closest beacon is at x=-2, y=15")))
|
||||
|
||||
;; manhattan distance : https://en.wikipedia.org/wiki/Taxicab_geometry
|
||||
;; sum of abs of coord-diffs
|
||||
|
||||
(defclass point ()
|
||||
((x :initarg :x :reader x)
|
||||
(y :initarg :y :reader y)))
|
||||
|
||||
(defmethod print-object ((obj point) stream)
|
||||
(print-unreadable-object (obj stream :type t)
|
||||
(with-slots (x y)
|
||||
obj
|
||||
(format stream "x:~a y:~a" x y))))
|
||||
|
||||
(defparameter *test-point-1*
|
||||
(make-instance 'point :x 1 :y 19))
|
||||
|
||||
(defparameter *test-point-2*
|
||||
(make-instance 'point :x -2 :y -20))
|
||||
|
||||
(defmethod manh-dist ((one point) (two point))
|
||||
(+ (abs (- (x one) (x two)))
|
||||
(abs (- (y one) (y two)))))
|
||||
|
||||
(manh-dist *test-point-1* *test-point-2*)
|
||||
;; i guess this is right
|
||||
|
||||
(defclass sensor ()
|
||||
((self-coord :initarg :self :reader self-coord)
|
||||
(beacon-coord :initarg :beacon :reader beacon-coord)
|
||||
(covered-dist :initarg :dist :reader covered-dist)))
|
||||
|
||||
(defun make-sensor (sens-x sens-y beac-x beac-y)
|
||||
(let* ((sensor (make-instance 'point :x sens-x :y sens-y))
|
||||
(beacon (make-instance 'point :x beac-x :y beac-y))
|
||||
(dist (manh-dist sensor beacon)))
|
||||
(make-instance 'sensor :self sensor :beacon beacon :dist dist)))
|
||||
|
||||
(defmethod print-object ((obj sensor) stream)
|
||||
(print-unreadable-object (obj stream :type t)
|
||||
(with-slots (self-coord beacon-coord covered-dist)
|
||||
obj
|
||||
(format stream "at: ~a, linked to: ~a, covering dist: ~a"
|
||||
self-coord beacon-coord covered-dist))))
|
||||
|
||||
|
||||
(defparameter *test-sensor* (make-sensor 2 18 -2 15))
|
||||
|
||||
(defmethod can-have-unknown-beacon-p ((p point) (s sensor))
|
||||
(> (manh-dist p (self-coord s))
|
||||
(covered-dist s)))
|
||||
|
||||
(manh-dist *test-point-1* (self-coord *test-sensor*))
|
||||
(can-have-unknown-beacon-p *test-point-1* *test-sensor*)
|
||||
|
||||
(manh-dist *test-point-2* (self-coord *test-sensor*))
|
||||
(can-have-unknown-beacon-p *test-point-2* *test-sensor*)
|
||||
|
||||
;; ok. now read in all sensors?
|
||||
;; and then for line with specified 'y'
|
||||
;; and from leftmost to rightmost S or B for each point ask each sensor if possible
|
||||
;; to have an unknown beacon, if any says "no" - then no
|
||||
;; otherwise - count
|
||||
|
||||
(defparameter *day15-input-file* "day15-test.txt")
|
||||
|
||||
|
||||
(defun line-to-coords (line)
|
||||
(rest (mapcar (lambda (str)
|
||||
(parse-integer str :junk-allowed t))
|
||||
(cl-ppcre:split "=" line))))
|
||||
|
||||
(defparameter *day15-sensors-list* nil)
|
||||
(setq *day15-sensors-list*
|
||||
(mapcar (lambda (coords-list)
|
||||
(apply #'make-sensor coords-list))
|
||||
(mapcar #'line-to-coords (uiop:read-file-lines *day15-input-file*))))
|
||||
|
||||
;; next - find lovest x and highest x
|
||||
;; but then i guess i'd also want lovest and highest y overall
|
||||
|
||||
;; that's neat
|
||||
(loop
|
||||
for sensor in *day15-sensors-list*
|
||||
minimize (x (self-coord sensor)) into xs
|
||||
minimize (x (beacon-coord sensor)) into xs
|
||||
maximize (x (self-coord sensor)) into xm
|
||||
maximize (x (beacon-coord sensor)) into xm
|
||||
minimize (y (self-coord sensor)) into ys
|
||||
minimize (y (beacon-coord sensor)) into ys
|
||||
maximize (y (self-coord sensor)) into ym
|
||||
maximize (y (beacon-coord sensor)) into ym
|
||||
finally (return (list xs xm ys ym)))
|
||||
;; (-2 25 0 22)
|
||||
|
||||
;; now for line y=10 check all x and count how many -for-all- sensors allow new point
|
||||
|
||||
(defun all-sensors-allow-for-hidden-beacon (point sensors)
|
||||
(macroexpand `(and ,@(mapcar (lambda (sensor) (can-have-unknown-beacon-p point sensor))
|
||||
sensors))))
|
||||
|
||||
(defun all-sensors-allow-for-hidden-beacon (point sensors)
|
||||
(not (position nil (mapcar (lambda (sensor) (can-have-unknown-beacon-p point sensor))
|
||||
sensors))))
|
||||
|
||||
;; well, do i have to write my own function for AND ?
|
||||
(when (all-sensors-allow-for-hidden-beacon *test-point-2* *day15-sensors-list*)
|
||||
1)
|
||||
|
||||
(when (all-sensors-allow-for-hidden-beacon *test-point-1* *day15-sensors-list*)
|
||||
1)
|
||||
|
||||
;; count how many ARE covered
|
||||
(loop
|
||||
for x from -2 to 25
|
||||
count (not (all-sensors-allow-for-hidden-beacon
|
||||
(make-instance 'point :x x :y 10)
|
||||
*day15-sensors-list*)))
|
||||
|
||||
;; on the image it's from -2 and till 24, so should be 27, if counting 0
|
||||
;; well. we're counting posistions "wher beacon can't possibly exist"
|
||||
;; so removing points which _are_ beacons?
|
||||
;;
|
||||
;; and - range needs to be extended significantly, no?
|
||||
;; what would be enough?
|
||||
;; doubling into each direction?
|
||||
|
||||
(defmethod points-equal ((left point) (right point))
|
||||
(and (= (x left) (x right))
|
||||
(= (y left) (y right))))
|
||||
|
||||
|
||||
(points-equal (make-instance 'point :x 1 :y 1)
|
||||
(make-instance 'point :x 1 :y 1))
|
||||
|
||||
(defun possible-to-have-beacon (point sensors)
|
||||
(let ((all-checks
|
||||
(mapcar (lambda (sensor)
|
||||
(if (points-equal point (beacon-coord sensor))
|
||||
'known-sensor
|
||||
(can-have-unknown-beacon-p point sensor) ; single NIL means - not possible to have unknown
|
||||
))
|
||||
sensors)))
|
||||
(or (not (position nil all-checks)) ; nil if all sensors allow (said T) presense of unknown beacons
|
||||
(position 'known-sensor all-checks) ; exists known sensor
|
||||
)))
|
||||
;; beacon is possible : either sensor has beacon at that point
|
||||
;; or position is out of the sensor range
|
||||
;; but here's the thing. if sencor-beacon is at this point - need to short-circuit T
|
||||
|
||||
(possible-to-have-beacon *test-point-2* *day15-sensors-list*)
|
||||
|
||||
(possible-to-have-beacon *test-point-1* *day15-sensors-list*)
|
||||
|
||||
(possible-to-have-beacon (make-instance 'point :x -2 :y 15) *day15-sensors-list*)
|
||||
|
||||
;; i guess that works
|
||||
|
||||
;; count how many ARE covered
|
||||
(loop
|
||||
for x from -2 to 25
|
||||
count (not (possible-to-have-beacon
|
||||
(make-instance 'point :x x :y 10)
|
||||
*day15-sensors-list*)))
|
||||
|
||||
;; ok.
|
||||
Reference in New Issue
Block a user