From a8ffeb0f4cfc6eecafdb1d536ec698e4560f3c13 Mon Sep 17 00:00:00 2001 From: Tyrel Souza Date: Thu, 15 Dec 2022 14:33:20 -0500 Subject: [PATCH] day15 part 2, wow slowww --- 2022/python/day15.py | 163 +++++++++++++++++++++++++++++++++++------- 2022/python/matrix.py | 2 +- 2 files changed, 139 insertions(+), 26 deletions(-) diff --git a/2022/python/day15.py b/2022/python/day15.py index 978f20b..391e079 100644 --- a/2022/python/day15.py +++ b/2022/python/day15.py @@ -4,14 +4,10 @@ import sys from pprint import pprint import shared from scanf import scanf -from typing import Optional +from typing import Optional, List, Tuple from dataclasses import dataclass +from collections import defaultdict - - -LIMIT = 4000000 - -#def fuckoff_ill_do_my_own_cityblock(y1,x1, y2,x2): def cityblock(y1,x1, y2,x2): return abs(y2-y1) + abs(x2-x1) @@ -21,7 +17,14 @@ class Sensor: sY: int bX: int bY: int + limit: Tuple[int,int] = (0,0) _d: int = None + _edges: List[Tuple[int,int]]= None + _border: List[Tuple[int,int]]= None + + def __str__(self): + return (f"Sensor(sX={self.sX}, sY={self.sY}, bX={self.bX}," + f"bY={self.bY}, d={self._d}, edges={len(self._edges)}, borders={len(self._borders)})") @property def s(self): @@ -53,6 +56,13 @@ class Sensor: return list(range(start[1],end[1]+1)) + def in_range(self, bY,bX): + d = cityblock(self.sY,self.sX, bY, bX) + if self.d < d: + return False + return True + + def in_diamond(self): sX,sY = self.sX, self.sY up_lim = sY - self.distance @@ -75,6 +85,62 @@ class Sensor: for y in range(sY-height, sY+height+1): yield (y,x) + def edges(self): + if self._edges: + return self._edges + sX,sY = self.sX, self.sY + up_lim = sY - self.distance + dn_lim = sY + self.distance + + le_lim = sX - self.distance + ri_lim = sX + self.distance + + u = (up_lim, sX) + d = (dn_lim, sX) + l = (sY, le_lim) + r = (sY, ri_lim) + + infliction = 1 + height = -1 + edges = set() + # to left -1 and right + 1 + for idx, x in enumerate(range(l[1],r[1]+1)): + height += infliction + if (sY, x) == self.s: + infliction = -1 + edges.add((sY-height,x)) + edges.add((sY+height,x)) + self._edges = edges + return self._edges + + def border(self): + if self._border: + return self._border + sX,sY = self.sX, self.sY + up_lim = sY - self.distance + dn_lim = sY + self.distance + + le_lim = sX - self.distance + ri_lim = sX + self.distance + + u = (up_lim, sX) + d = (dn_lim, sX) + l = (sY, le_lim) + r = (sY, ri_lim) + + infliction = 1 + height = -1 + border = set() + # to left -1 and right + 1 + for idx, x in enumerate(range(l[1]-1,r[1]+2)): + height += infliction + if (sY, x) == self.s: + infliction = -1 + border.add((sY-height,x)) + border.add((sY+height,x)) + self._border = border + return self._border + def part1(rows, sample=False): sensors = [] @@ -89,11 +155,14 @@ def part1(rows, sample=False): xSet.add(bx) ySet.add(y) ySet.add(by) - sensors.append(Sensor(sX=x,sY=y,bX=bx,bY=by)) + sensors.append(Sensor(sX=x,sY=y,bX=bx,bY=by,limit=(0,0))) minX, maxX = min(xSet),max(xSet) minY, maxY = min(ySet),max(ySet) + limLo = min(minX,minY) + limHi = max(maxX,maxY) for sensor in sensors: + sensor.limit = (limLo,limHi) sensor_points.append(sensor.s) beacon_points.append(sensor.b) if sample: @@ -136,13 +205,13 @@ def part1(rows, sample=False): mx[y][x] = "S" print(matrix.ppmx(mx, pad=False,space=True)) +tuning = lambda y,x: y + (4000000 * x) -tuning = lambda y,x: y + (LIMIT * x) - -def part2(rows): +def part2(rows, sample=False): sensors = [] sensor_points = [] beacon_points = [] + ineligible_points = set() xSet = set() ySet = set() for row in rows: @@ -156,22 +225,66 @@ def part2(rows): minY, maxY = min(ySet),max(ySet) for sensor in sensors: + _ = sensor.edges() + _ = sensor.border() + sensor_points.append(sensor.s) beacon_points.append(sensor.b) + if sample: + for yx in sensor.in_diamond(): + ineligible_points.add(yx) - #coord_range = (0, LIMIT) - coord_range = (0, 20) + L = 4000000 + if sample: + L = 20 - - ineligible = set() + borders = defaultdict(int) for s in sensors: - coll = s.on_line(CHECK_ROW) - ineligible.update(coll) - - count_ignoring_current_beacons = 0 - for i in ineligible: - if (CHECK_ROW, i) not in beacon_points: - count_ignoring_current_beacons += 1 - print(count_ignoring_current_beacons, "with removing beacons, final answer") + for yx in s.border(): + y,x = yx + if y > 0 and y <= L and x > 0 and x <= L: + borders[yx] += 1 + + TARGET = None + for (eY,eX) in borders.keys(): + #print("checking:",(eY,ex)) + away_from = [] + for idx, s in enumerate(sensors): + d = s.distance_to(eY,eX) + if d > s.distance: + away_from.append(s.s) + if len(away_from) == len(sensors): + TARGET = (eY,eX) + print(TARGET, tuning(eY,eX)) + break + + if not sample: + return + + mx = matrix.matrix_of_size(maxX+1, maxY+1) + for yx in ineligible_points: + y,x = yx + if y >= 0 and x >= 0: + if y <= maxY and x <= maxX: + mx[y][x] = "#" + + for yx in beacon_points: + y,x = yx + if y >= 0 and x >= 0: + if y <= maxY and x <= maxX: + mx[y][x] = "B" + + for yx in sensor_points: + y,x = yx + if y >= 0 and x >= 0: + if y <= maxY and x <= maxX: + mx[y][x] = "S" + + + mx[TARGET[0]][TARGET[1]] = "!" + matrix.highlight(mx, blink_green=[TARGET,]) + + + def main(): sample = False @@ -183,9 +296,9 @@ def main(): part1(rows, sample) print("🕒", elapsed()) - #with shared.elapsed_timer() as elapsed: - # part2(rows) - # print("🕒", elapsed()) + with shared.elapsed_timer() as elapsed: + part2(rows, sample) + print("🕒", elapsed()) if __name__ == "__main__": diff --git a/2022/python/matrix.py b/2022/python/matrix.py index c2edb50..19d20f3 100644 --- a/2022/python/matrix.py +++ b/2022/python/matrix.py @@ -334,6 +334,6 @@ def highlight(matrix, red=[], green=[], blue=[], blink_green=[]): for (y, x) in blink_green: new = f"{colors.BLINK}{colors.GREEN}{mx[y][x]}{colors.ENDC}" mx[y][x] = new - ppmx(mx, pad=False, space=True, zero="0") + print(ppmx(mx, pad=False, space=True, zero="0"))