day16 still working:

This commit is contained in:
Tyrel Souza 2022-12-16 22:07:17 -05:00
parent 139b6d7e12
commit d7a1aac178
7 changed files with 247 additions and 179 deletions

View File

@ -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:

View File

@ -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:
@ -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__":

View File

@ -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:

View File

@ -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,14 +41,14 @@ 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])
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:
@ -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():

View File

@ -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,60 +51,91 @@ 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
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())
@ -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())

View File

@ -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,25 +219,23 @@ 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):
height = len(matrix)
width = len(matrix[0])
@ -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"))

View File

@ -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)]