From 190382eddc1749a090f2db90c6ce4e3d7d2ebd39 Mon Sep 17 00:00:00 2001 From: efim Date: Fri, 16 Dec 2022 12:13:37 +0000 Subject: [PATCH] day 15 p.1: scanners and beacons, bad solution --- day15-input.txt | 33 ++++++++ day15-scratch.lisp | 185 +++++++++++++++++++++++++++++++++++++++++++++ day15-test.txt | 14 ++++ day15.lisp | 114 ++++++++++++++++++++++++++++ 4 files changed, 346 insertions(+) create mode 100644 day15-input.txt create mode 100644 day15-scratch.lisp create mode 100644 day15-test.txt create mode 100644 day15.lisp diff --git a/day15-input.txt b/day15-input.txt new file mode 100644 index 0000000..e6a6df5 --- /dev/null +++ b/day15-input.txt @@ -0,0 +1,33 @@ +Sensor at x=2302110, y=2237242: closest beacon is at x=2348729, y=1239977 +Sensor at x=47903, y=2473047: closest beacon is at x=-432198, y=2000000 +Sensor at x=2363579, y=1547888: closest beacon is at x=2348729, y=1239977 +Sensor at x=3619841, y=520506: closest beacon is at x=2348729, y=1239977 +Sensor at x=3941908, y=3526118: closest beacon is at x=3772294, y=3485243 +Sensor at x=3206, y=1564595: closest beacon is at x=-432198, y=2000000 +Sensor at x=3123411, y=3392077: closest beacon is at x=2977835, y=3592946 +Sensor at x=3279053, y=3984688: closest beacon is at x=2977835, y=3592946 +Sensor at x=2968162, y=3938490: closest beacon is at x=2977835, y=3592946 +Sensor at x=1772120, y=2862246: closest beacon is at x=2017966, y=3158243 +Sensor at x=3283241, y=2619168: closest beacon is at x=3172577, y=2521434 +Sensor at x=2471642, y=3890150: closest beacon is at x=2977835, y=3592946 +Sensor at x=3163348, y=3743489: closest beacon is at x=2977835, y=3592946 +Sensor at x=2933313, y=2919047: closest beacon is at x=3172577, y=2521434 +Sensor at x=2780640, y=3629927: closest beacon is at x=2977835, y=3592946 +Sensor at x=3986978, y=2079918: closest beacon is at x=3998497, y=2812428 +Sensor at x=315464, y=370694: closest beacon is at x=-550536, y=260566 +Sensor at x=3957316, y=3968366: closest beacon is at x=3772294, y=3485243 +Sensor at x=2118533, y=1074658: closest beacon is at x=2348729, y=1239977 +Sensor at x=3494855, y=3378533: closest beacon is at x=3772294, y=3485243 +Sensor at x=2575727, y=210553: closest beacon is at x=2348729, y=1239977 +Sensor at x=3999990, y=2813525: closest beacon is at x=3998497, y=2812428 +Sensor at x=3658837, y=3026912: closest beacon is at x=3998497, y=2812428 +Sensor at x=1551619, y=1701155: closest beacon is at x=2348729, y=1239977 +Sensor at x=2625855, y=3330422: closest beacon is at x=2977835, y=3592946 +Sensor at x=3476946, y=2445098: closest beacon is at x=3172577, y=2521434 +Sensor at x=2915568, y=1714113: closest beacon is at x=2348729, y=1239977 +Sensor at x=729668, y=3723377: closest beacon is at x=-997494, y=3617758 +Sensor at x=3631681, y=3801747: closest beacon is at x=3772294, y=3485243 +Sensor at x=2270816, y=3197807: closest beacon is at x=2017966, y=3158243 +Sensor at x=3999999, y=2810929: closest beacon is at x=3998497, y=2812428 +Sensor at x=3978805, y=3296024: closest beacon is at x=3772294, y=3485243 +Sensor at x=1054910, y=811769: closest beacon is at x=2348729, y=1239977 diff --git a/day15-scratch.lisp b/day15-scratch.lisp new file mode 100644 index 0000000..7561a4f --- /dev/null +++ b/day15-scratch.lisp @@ -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. diff --git a/day15-test.txt b/day15-test.txt new file mode 100644 index 0000000..a612424 --- /dev/null +++ b/day15-test.txt @@ -0,0 +1,14 @@ +Sensor at x=2, y=18: closest beacon is at x=-2, y=15 +Sensor at x=9, y=16: closest beacon is at x=10, y=16 +Sensor at x=13, y=2: closest beacon is at x=15, y=3 +Sensor at x=12, y=14: closest beacon is at x=10, y=16 +Sensor at x=10, y=20: closest beacon is at x=10, y=16 +Sensor at x=14, y=17: closest beacon is at x=10, y=16 +Sensor at x=8, y=7: closest beacon is at x=2, y=10 +Sensor at x=2, y=0: closest beacon is at x=2, y=10 +Sensor at x=0, y=11: closest beacon is at x=2, y=10 +Sensor at x=20, y=14: closest beacon is at x=25, y=17 +Sensor at x=17, y=20: closest beacon is at x=21, y=22 +Sensor at x=16, y=7: closest beacon is at x=15, y=3 +Sensor at x=14, y=3: closest beacon is at x=15, y=3 +Sensor at x=20, y=1: closest beacon is at x=15, y=3 diff --git a/day15.lisp b/day15.lisp new file mode 100644 index 0000000..317ba55 --- /dev/null +++ b/day15.lisp @@ -0,0 +1,114 @@ +;; https://adventofcode.com/2022/day/15 + +(ql:quickload 'cl-ppcre) + +(defparameter *day15-input-file* "day15-test.txt") + +(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)))) + +(defmethod points-equal ((left point) (right point)) + (and (= (x left) (x right)) + (= (y left) (y 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)))) + + +(defmethod can-have-unknown-beacon-p ((p point) (s sensor)) + (> (manh-dist p (self-coord s)) + (covered-dist s))) + +(defun line-to-coords (line) + (rest (mapcar (lambda (str) + (parse-integer str :junk-allowed t)) + (cl-ppcre:split "=" line)))) + +(defun get-sensors-list (input-file-name) + (mapcar (lambda (coords-list) + (apply #'make-sensor coords-list)) + (mapcar #'line-to-coords (uiop:read-file-lines input-file-name)))) + +(defun get-limits (sensors-list) + (loop + for sensor in 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)))) + +(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 + ))) + +(defun count-certainly-not-beacons (input-file-name) + (let ((sensors (get-sensors-list input-file-name))) + (destructuring-bind (min-x max-x min-y max-y) + (get-limits sensors) + (let ((to-add-x (abs (- max-x min-x))) + ;; (to-check-y 10) + (to-check-y 2000000) + ) + (loop + for x from (- min-x to-add-x) to (+ max-x to-add-x) + count (not (possible-to-have-beacon + (make-instance 'point :x x :y to-check-y) + sensors)) + do (format t "iterating for x:~a y:~a~%" x to-check-y)))))) + +(count-certainly-not-beacons "day15-test.txt") +(count-certainly-not-beacons "day15-input.txt") + +;; well, that's just too slow +;; how do i rewrite it to make it faster? +;; i guess i could exclude the sensors which are too far away from the list? +;; +;; well, optimization here that we move by 1 point toward or away from sensor +;; so, we can kind of calculate when we'll be in it's range? +;; * in what amount of steps +;; ** whoa, org colors +;; +;; so. + +;; PART 2 - just start search overnight? +;; for 0 to 4.000.000 by x and y? +;; and collect all such possible x and y? +;; nope, even if it were 5 minutes for 16mil, +;; so 2 minutes per 4 mil, then multiply by 4M - more than a day. +;; think better