From d7a1aac178620e4ddc1b7d29957c7e2c262ae64c Mon Sep 17 00:00:00 2001 From: Tyrel Souza Date: Fri, 16 Dec 2022 22:07:17 -0500 Subject: [PATCH] day16 still working: --- 2022/python/_sample.py | 6 +- 2022/python/day13.py | 23 ++++---- 2022/python/day14.py | 88 ++++++++++++++++------------ 2022/python/day15.py | 129 ++++++++++++++++++++++------------------- 2022/python/day16.py | 119 +++++++++++++++++++++++-------------- 2022/python/matrix.py | 53 +++++++++-------- 2022/python/shared.py | 8 ++- 7 files changed, 247 insertions(+), 179 deletions(-) diff --git a/2022/python/_sample.py b/2022/python/_sample.py index 2337a89..0f81824 100644 --- a/2022/python/_sample.py +++ b/2022/python/_sample.py @@ -3,16 +3,16 @@ import shared import itertools import functools -#@shared.profile +# @shared.profile def part1(rows): pass - -#@shared.profile +# @shared.profile def part2(rows): pass + def main(): rows = [row for row in shared.load_rows(15)] with shared.elapsed_timer() as elapsed: diff --git a/2022/python/day13.py b/2022/python/day13.py index 85c2ccf..aad5ba3 100644 --- a/2022/python/day13.py +++ b/2022/python/day13.py @@ -14,7 +14,7 @@ def part1(rows): # print(f"== Pair {idx+1} ==") passes = check_group(left, right) if passes: - indexes.append(idx+1) + indexes.append(idx + 1) # if passes is True: # print(f"{idx+1} {matrix.colors.GREEN}{passes}{matrix.colors.ENDC}") # elif passes is False: @@ -26,7 +26,7 @@ def part1(rows): def check_group(left, right): if isinstance(left, list) and isinstance(right, list): - # if both items are lists, loop over both + # if both items are lists, loop over both for idx in range(min(len(left), len(right))): check = check_group(left[idx], right[idx]) # bubble up the int comparisons, or list length comparisons @@ -62,42 +62,43 @@ def check_group(left, right): # If the left integer is higher than the right integer, the inputs are not in the right order. elif left > right: return False - #Otherwise, the inputs are the same integer; continue checking the next part of the input. + # Otherwise, the inputs are the same integer; continue checking the next part of the input. elif left == right: return None + def part2(rows): two, six = 0, 0 rows = [eval(r) for r in rows if r] rows.append([[2]]) rows.append([[6]]) - def cmp(x, y): - return {True: 1,False: -1,}[check_group(x, y)] + return { + True: 1, + False: -1, + }[check_group(x, y)] - idx = 0 # ew 1 based lists, jeeeze AoC + idx = 0 # ew 1 based lists, jeeeze AoC for r in sorted(rows, key=functools.cmp_to_key(cmp), reverse=True): idx += 1 if r == [[2]]: two = idx if r == [[6]]: six = idx - break # will come 2nd logically, so we can break here to save time + break # will come 2nd logically, so we can break here to save time print(two * six) - - def main(): rows = shared.load_rows(13) with shared.elapsed_timer() as elapsed: part1(rows) print("🕒", elapsed()) with shared.elapsed_timer() as elapsed: - part2(rows) - print("🕒", elapsed()) + part2(rows) + print("🕒", elapsed()) if __name__ == "__main__": diff --git a/2022/python/day14.py b/2022/python/day14.py index db02f13..1eee15f 100644 --- a/2022/python/day14.py +++ b/2022/python/day14.py @@ -4,7 +4,7 @@ import itertools import functools -SAND_START = [0,500] +SAND_START = [0, 500] def find_bounds(lines): @@ -13,97 +13,110 @@ def find_bounds(lines): for line in lines: x.extend(matrix.split_x_out(line)) y.extend(matrix.split_y_out(line)) - return shared.minmax(y),shared.minmax(x) + return shared.minmax(y), shared.minmax(x) + - def part1(rows): def get_next(sand): - next_y = sand[0]+1 - dl = sand[1]-1 + next_y = sand[0] + 1 + dl = sand[1] - 1 d = sand[1] - dr = sand[1]+1 - return next_y, (dl,d,dr) - lines = [[list(reversed(list(map(int, point.split(","))))) for point in row.split(" -> ")] for row in rows] - (minY,maxY), (minX,maxX) = find_bounds(lines) - mx = matrix.matrix_of_size(maxX+2,maxY+2) + dr = sand[1] + 1 + return next_y, (dl, d, dr) + + lines = [ + [ + list(reversed(list(map(int, point.split(","))))) + for point in row.split(" -> ") + ] + for row in rows + ] + (minY, maxY), (minX, maxX) = find_bounds(lines) + mx = matrix.matrix_of_size(maxX + 2, maxY + 2) walls = [] for line in lines: - for x in range(len(line)-1): - coords = matrix.coords_between_points(line[x], line[x+1]) + for x in range(len(line) - 1): + coords = matrix.coords_between_points(line[x], line[x + 1]) walls.extend(coords) - for y,x in walls: + for y, x in walls: mx[y][x] = "#" mx[SAND_START[0]][SAND_START[1]] = "+" sands = [] try: - for sand_grains in range(900): # produce Sand one unit at a time + for sand_grains in range(900): # produce Sand one unit at a time last_grain = [] sand = SAND_START[:] - #print("starting sand", sand_grains+1, sand) + # print("starting sand", sand_grains+1, sand) while True: last_grain.append(sand[:]) next_y, (dl, d, dr) = get_next(sand) if mx[next_y][d] == 0: - #print(mx[next_y][d],"moving_down", end=' ') - #print("moving down") + # print(mx[next_y][d],"moving_down", end=' ') + # print("moving down") sand[0] = next_y elif mx[next_y][dl] == 0: - #print(mx[next_y][dl], "moving left", end=' ') - #print("moving left") + # print(mx[next_y][dl], "moving left", end=' ') + # print("moving left") sand[0] = next_y sand[1] = dl elif mx[next_y][dr] == 0: - #print(mx[next_y][dr], "moving right", end=' ') - #print("moving right") + # print(mx[next_y][dr], "moving right", end=' ') + # print("moving right") sand[0] = next_y sand[1] = dr else: mx[sand[0]][sand[1]] = "o" - #print(mx[next_y][dl], mx[next_y][d], mx[next_y][dr]) - #print("STOPPING", end=' ') + # print(mx[next_y][dl], mx[next_y][d], mx[next_y][dr]) + # print("STOPPING", end=' ') break - #matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2) + # matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2) except IndexError: sands.append(last_grain) - for y,x in sands[-1]: + for y, x in sands[-1]: mx[y][x] = "~" - #matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2) + # matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2) print("done", sand_grains) @shared.profile def part2(rows): - lines = [[list(reversed(list(map(int, point.split(","))))) for point in row.split(" -> ")] for row in rows] - (minY,maxY), (minX,maxX) = find_bounds(lines) + lines = [ + [ + list(reversed(list(map(int, point.split(","))))) + for point in row.split(" -> ") + ] + for row in rows + ] + (minY, maxY), (minX, maxX) = find_bounds(lines) walls = {} _between_points = matrix.coords_between_points for line in lines: - for x in range(len(line)-1): - coords = matrix.coords_between_points(line[x], line[x+1]) + for x in range(len(line) - 1): + coords = matrix.coords_between_points(line[x], line[x + 1]) for c in coords: walls[c] = "#" - for y,x in walls: - walls[(y,x)] = "#"# .add((y,x)) + for y, x in walls: + walls[(y, x)] = "#" # .add((y,x)) floor = maxY + 2 sand_grains = -1 while True: sand_grains += 1 - sand = [0,500] + sand = [0, 500] if tuple(sand) in walls: print("done", sand_grains) break while True: - next_y = sand[0]+1 - dl = sand[1]-1 - dr = sand[1]+1 + next_y = sand[0] + 1 + dl = sand[1] - 1 + dr = sand[1] + 1 if next_y == floor: # hit the floor - walls[tuple(sand)] = "#" # Draw stop + walls[tuple(sand)] = "#" # Draw stop break elif (next_y, sand[1]) not in walls: @@ -120,6 +133,7 @@ def part2(rows): walls[tuple(sand)] = "#" break + def main(): rows = [row for row in shared.load_rows(14)] with shared.elapsed_timer() as elapsed: diff --git a/2022/python/day15.py b/2022/python/day15.py index 327ed60..4455f17 100644 --- a/2022/python/day15.py +++ b/2022/python/day15.py @@ -8,8 +8,10 @@ from typing import Optional, List, Tuple from dataclasses import dataclass from collections import defaultdict -def cityblock(y1,x1, y2,x2): - return abs(y2-y1) + abs(x2-x1) + +def cityblock(y1, x1, y2, x2): + return abs(y2 - y1) + abs(x2 - x1) + @dataclass class Sensor: @@ -17,14 +19,16 @@ class Sensor: sY: int bX: int bY: int - limit: Tuple[int,int] = (0,0) + limit: Tuple[int, int] = (0, 0) _d: int = None - _edges: List[Tuple[int,int]]= None - _border: List[Tuple[int,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)})") + 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): @@ -37,15 +41,15 @@ class Sensor: @property def distance(self): if self._d is None: - self._d = cityblock(self.sY,self.sX, self.bY, self.bX) + self._d = cityblock(self.sY, self.sX, self.bY, self.bX) return self._d def distance_to(self, bY, bX): - return cityblock(self.sY,self.sX, bY, bX) + return cityblock(self.sY, self.sX, bY, bX) def on_line(self, y): - midpoint = (y,self.s[1]) - d = self.distance_to(*midpoint) + midpoint = (y, self.s[1]) + d = self.distance_to(*midpoint) if d > self.distance: return [] @@ -54,17 +58,16 @@ class Sensor: start = (y, midpoint[1] - need) end = (y, midpoint[1] + need) - return list(range(start[1],end[1]+1)) + return list(range(start[1], end[1] + 1)) - def in_range(self, bY,bX): - d = cityblock(self.sY,self.sX, bY, bX) + 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 + sX, sY = self.sX, self.sY up_lim = sY - self.distance dn_lim = sY + self.distance @@ -78,17 +81,17 @@ class Sensor: infliction = 1 height = -1 - for idx, x in enumerate(range(l[1],r[1]+1)): + for idx, x in enumerate(range(l[1], r[1] + 1)): height += infliction if (sY, x) == self.s: infliction = -1 - for y in range(sY-height, sY+height+1): - yield (y,x) + 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 + sX, sY = self.sX, self.sY up_lim = sY - self.distance dn_lim = sY + self.distance @@ -104,19 +107,19 @@ class Sensor: height = -1 edges = set() # to left -1 and right + 1 - for idx, x in enumerate(range(l[1],r[1]+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)) + 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 + sX, sY = self.sX, self.sY up_lim = sY - self.distance dn_lim = sY + self.distance @@ -132,12 +135,12 @@ class Sensor: height = -1 border = set() # to left -1 and right + 1 - for idx, x in enumerate(range(l[1]-1,r[1]+2)): + 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)) + border.add((sY - height, x)) + border.add((sY + height, x)) self._border = border return self._border @@ -150,19 +153,21 @@ def part1(rows, sample=False): xSet = set() ySet = set() for row in rows: - x,y,bx,by = scanf("Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", row) + x, y, bx, by = scanf( + "Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", row + ) xSet.add(x) xSet.add(bx) ySet.add(y) ySet.add(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) + 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.limit = (limLo, limHi) sensor_points.append(sensor.s) beacon_points.append(sensor.b) if sample: @@ -177,7 +182,7 @@ def part1(rows, sample=False): 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: @@ -187,25 +192,27 @@ def part1(rows, sample=False): if not sample: return - mx = matrix.matrix_of_size(maxX+1, maxY+1) + mx = matrix.matrix_of_size(maxX + 1, maxY + 1) for yx in ineligible_points: - y,x = yx + 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 + 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 + y, x = yx if y >= 0 and x >= 0: if y <= maxY and x <= maxX: mx[y][x] = "S" - print(matrix.ppmx(mx, pad=False,space=True)) + print(matrix.ppmx(mx, pad=False, space=True)) + + +tuning = lambda y, x: y + (4000000 * x) -tuning = lambda y,x: y + (4000000 * x) def part2(rows, sample=False): sensors = [] @@ -215,14 +222,16 @@ def part2(rows, sample=False): xSet = set() ySet = set() for row in rows: - x,y,bx,by = scanf("Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", row) + x, y, bx, by = scanf( + "Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", row + ) xSet.add(x) xSet.add(bx) ySet.add(y) ySet.add(by) - sensors.append(Sensor(sX=x,sY=y,bX=bx,bY=by)) - minX, maxX = min(xSet),max(xSet) - minY, maxY = min(ySet),max(ySet) + sensors.append(Sensor(sX=x, sY=y, bX=bx, bY=by)) + minX, maxX = min(xSet), max(xSet) + minY, maxY = min(ySet), max(ySet) for sensor in sensors: _ = sensor.edges() @@ -240,21 +249,21 @@ def part2(rows, sample=False): borders = defaultdict(int) for s in sensors: for yx in s.border(): - y,x = yx + 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)) + for (eY, eX) in borders.keys(): + # print("checking:",(eY,ex)) away_from = [] for idx, s in enumerate(sensors): - d = s.distance_to(eY,eX) + 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)) + TARGET = (eY, eX) + print(TARGET, tuning(eY, eX)) break if not sample: @@ -262,30 +271,32 @@ def part2(rows, sample=False): # """ PRINT OUTPUT """ - mx = matrix.matrix_of_size(maxX+1, maxY+1) + mx = matrix.matrix_of_size(maxX + 1, maxY + 1) for yx in ineligible_points: - y,x = yx + 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 + 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 + 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,]) - - + matrix.highlight( + mx, + blink_green=[ + TARGET, + ], + ) def main(): diff --git a/2022/python/day16.py b/2022/python/day16.py index 41db737..54c534f 100644 --- a/2022/python/day16.py +++ b/2022/python/day16.py @@ -3,9 +3,12 @@ import matrix import shared import scanf from dataclasses import dataclass +from collections import defaultdict from typing import List, Dict from pprint import pprint +import networkx as nx +from IPython.display import Image, display @dataclass class Valve: @@ -13,7 +16,7 @@ class Valve: rate: int tunnels: List[str] opened_at: int = -1 - potential: Dict[str,int] = None + potential: Dict[str, int] = None def set_potential(self, valves): self.potential = {} @@ -23,6 +26,7 @@ class Valve: def highest_potential(self): return max(self.potential, key=self.potential.get) + def parse(rows): valves = {} for row in rows: @@ -30,15 +34,15 @@ def parse(rows): right = right.replace("s ", "").lstrip() valve, rate = scanf.scanf("Valve %s has flow rate=%d; %*s %*s to", left) tunnels = right.split(", ") - valves[valve] = Valve(label=valve,rate=rate,tunnels=tunnels) + valves[valve] = Valve(label=valve, rate=rate, tunnels=tunnels) - for _,v in valves.items(): + for _, v in valves.items(): v.set_potential(valves) return valves def part1(rows, sample=False): - p1 = Part1(rows,sample, 30) + p1 = Part1(rows, sample, 30) p1.run() @@ -47,62 +51,93 @@ class Part1: self.rows = rows self.sample = sample self.valves = parse(rows) + self.nonzero = {v.label: v for _, v in self.valves.items() if v.rate > 0} self.cur = self.valves["AA"] self.tick = 1 self.minutes = minutes + self.g = nx.DiGraph() + self.path_distances = defaultdict(dict) + self.set_up_graph() + + def draw(self): + pdot = nx.drawing.nx_pydot.to_pydot(self.g) + pdot.write_png("15.png") + + def set_up_graph(self): + for lbl, v in self.valves.items(): + for t in v.tunnels: + # self.g.add_edge(lbl, t, {'weight':self.valves[t].rate}) + self.g.add_edge(lbl, t, weight=self.valves[t].rate) + all_keys = self.valves.keys() + for lbl, _ in self.valves.items(): + for other in all_keys: + if other == lbl: + continue + self.path_distances[lbl][other] = min([len(x) for x in nx.shortest_simple_paths(self.g, lbl, other)]) def do_tick(self, minute): - pressure = 0 + pressure = 0 opened = [] for _, valve in self.valves.items(): if valve.opened_at > 0: - continue - pressure += valve.rate - print(f"== Minute {minute} == [ {self.cur.label} ]") - print(f"\tValves {', '.join(opened)} are open, releasing {pressure} pressure") - - - def open_or_move(self): - #print(self.cur) - hi = self.cur.highest_potential() - potential_elsewhere = self.cur.potential - pe = potential_elsewhere[hi] - if pe > self.cur.rate: - #print(f"should move to {hi}") - self.move(hi) - elif self.cur.rate > pe: - print(f"should open {self.cur.label}") - self.open() - - def move(self, where): - self.tick += 1 - self.cur = self.valves[where] - print("\tMove to valve", where) - - def open(self): - if self.cur.opened_at >= 0 : - raise Exception("tried to open valve already opened") - self.tick += 1 - self.valves[self.cur.label].opened_at = self.tick - self.cur = self.valves[self.cur.label] - print(self.cur) + pressure += valve.rate + opened.append(valve.label) + print(f"== Min {minute}:: Valves {', '.join(opened)} are open, releasing {pressure} pressure") def calculate_total_flow(self): total = 0 for label, valve in self.valves.items(): - if valve.is_open: + if valve.opened_at > 0: total += valve.rate * (30 - valve.opened_at) return total def run(self): - for minute in range(1, self.minutes+1): - self.do_tick(minute) - self.open_or_move() + # Construct the graph with vertices & edges from the input + # Call a function to compute the distances between every pair of vertices + # Create a closed set containing all the valves with non-zero rates + # At each step, iterate over the remaining set of closed, non-zero valves + # - Subtract the distance from remaining minutes + # - Calculate the flow (rate * remaining minutes) + # - Remove the recently opened valve from the closed set (functionally), so the deeper levels won't consider it - print("total flow:") - print(self.calculate_total_flow()) + def priority(remaining): + _pris = [] + for _,n in self.nonzero.items(): + # (time_remaining - distance_to_valve - 1) * flow rate + pri = (remaining - self.path_distances[self.cur.label][n.label] - 1) * n.rate + _pris.append((n.label, pri)) + _pris = list(sorted(_pris, key=lambda x: x[1], reverse=True)) + return _pris + remaining = self.minutes + open_order = [] + while len(self.nonzero): + if remaining <= 0: + print("ran out of time") + break + self.do_tick(31-remaining) + pris = priority(remaining) + print(pris) + _pri, _ = pris.pop(0) + n = self.nonzero[_pri] + del self.nonzero[_pri] + open_order.append(n.label) + print("\tMoving to", n.label) + print("\tOpening ", n.label) + distance = self.path_distances[self.cur.label][n.label] + self.cur = n + self.cur.opened_at = self.minutes - (remaining + 1) + remaining -= distance # Move + remaining -= 1 # open + + + print(remaining) + print(open_order) + print("sample: 1651") + print("total flow:", self.calculate_total_flow()) + + def main(): sample = False @@ -114,7 +149,7 @@ def main(): part1(rows, sample) print("🕒", elapsed()) - #with shared.elapsed_timer() as elapsed: + # with shared.elapsed_timer() as elapsed: # part2(rows, sample) # print("🕒", elapsed()) diff --git a/2022/python/matrix.py b/2022/python/matrix.py index 19d20f3..23510d1 100644 --- a/2022/python/matrix.py +++ b/2022/python/matrix.py @@ -8,11 +8,13 @@ split_word_to_chr_list = lambda y: [w for w in y] split_word_to_int_list = lambda y: [int(w) for w in y] split_line_to_int_list = lambda y: [int(w) for w in y.split(" ") if w] + def split_x_out(l): - return [x for _,x in l] + return [x for _, x in l] + def split_y_out(l): - return [y for y,_ in l] + return [y for y, _ in l] class colors: @@ -154,7 +156,9 @@ def get_neighbor_coords(matrix, c, r, diagonals=True): return neighbors -def line_of_sight_coords(matrix, row, col, distance=None) -> Dict[str, List[Tuple[int, int]]]: +def line_of_sight_coords( + matrix, row, col, distance=None +) -> Dict[str, List[Tuple[int, int]]]: """ Takes a matrix, a row, and a column calculates the coordinates to the edge for all four cardinal directions @@ -168,8 +172,14 @@ def line_of_sight_coords(matrix, row, col, distance=None) -> Dict[str, List[Tupl row_ids = list(range(0, width)) if distance: - up_ids, down_ids = list(reversed(col_ids[:col])), col_ids[col + 1 :col+distance+1] - left_ids, right_ids = list(reversed(row_ids[:row])), row_ids[row + 1 :row+distance+1] + up_ids, down_ids = ( + list(reversed(col_ids[:col])), + col_ids[col + 1 : col + distance + 1], + ) + left_ids, right_ids = ( + list(reversed(row_ids[:row])), + row_ids[row + 1 : row + distance + 1], + ) else: up_ids, down_ids = list(reversed(col_ids[:col])), col_ids[col + 1 :] left_ids, right_ids = list(reversed(row_ids[:row])), row_ids[row + 1 :] @@ -200,8 +210,8 @@ def line_of_sight(mx, row, col, distance=None): def coords_between_points(point1, point2): - y1,x1 = point1 - y2,x2 = point2 + y1, x1 = point1 + y2, x2 = point2 coords = [] x = 0 @@ -209,23 +219,21 @@ def coords_between_points(point1, point2): if x2 < x1: y = point1[0] - for _x in range(x2, x1+1): - coords.append((y,_x)) + for _x in range(x2, x1 + 1): + coords.append((y, _x)) elif x1 < x2: y = point1[0] - for _x in range(x1, x2+1): - coords.append((y,_x)) + for _x in range(x1, x2 + 1): + coords.append((y, _x)) elif y2 < y1: x = point1[1] - for _y in range(y2, y1+1): - coords.append((_y,x)) + for _y in range(y2, y1 + 1): + coords.append((_y, x)) elif y1 < y2: x = point1[1] - for _y in range(y1, y2+1): - coords.append((_y,x)) + for _y in range(y1, y2 + 1): + coords.append((_y, x)) return coords - - def get_size(matrix): @@ -303,14 +311,13 @@ def ppmx(*matrices, pad=True, space=True, zero="."): out.append("".join([f(x) for x in c])) return "\n".join(out) -def view_matrix(matrix, y1,x1, y2,x2): - lines = ppmx(matrix, pad=0,space=0).split("\n") - for line in lines[y1:y2+1]: + +def view_matrix(matrix, y1, x1, y2, x2): + lines = ppmx(matrix, pad=0, space=0).split("\n") + for line in lines[y1 : y2 + 1]: print(line[x1:x2]) - - def highlight(matrix, red=[], green=[], blue=[], blink_green=[]): """ print a matrix of anything, Falsy values turns to `.` for clarity @@ -335,5 +342,3 @@ def highlight(matrix, red=[], green=[], blue=[], blink_green=[]): new = f"{colors.BLINK}{colors.GREEN}{mx[y][x]}{colors.ENDC}" mx[y][x] = new print(ppmx(mx, pad=False, space=True, zero="0")) - - diff --git a/2022/python/shared.py b/2022/python/shared.py index 5eef667..0f7c2e6 100644 --- a/2022/python/shared.py +++ b/2022/python/shared.py @@ -5,8 +5,8 @@ import cProfile import functools import pstats -def profile(func): +def profile(func): @functools.wraps(func) def inner(*args, **kwargs): profiler = cProfile.Profile() @@ -15,18 +15,20 @@ def profile(func): retval = func(*args, **kwargs) finally: profiler.disable() - with open('profile.out', 'w') as profile_file: + with open("profile.out", "w") as profile_file: stats = pstats.Stats(profiler, stream=profile_file) stats.print_stats() return retval return inner + spl = lambda y: [int(w) for w in y] def minmax(l): - return min(l),max(l) + return min(l), max(l) + def load_rows(day): return [row for row in load(day)]