day16 still working:
This commit is contained in:
parent
139b6d7e12
commit
d7a1aac178
@ -8,11 +8,11 @@ def part1(rows):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# @shared.profile
|
# @shared.profile
|
||||||
def part2(rows):
|
def part2(rows):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
rows = [row for row in shared.load_rows(15)]
|
rows = [row for row in shared.load_rows(15)]
|
||||||
with shared.elapsed_timer() as elapsed:
|
with shared.elapsed_timer() as elapsed:
|
||||||
|
@ -66,15 +66,18 @@ def check_group(left, right):
|
|||||||
elif left == right:
|
elif left == right:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def part2(rows):
|
def part2(rows):
|
||||||
two, six = 0, 0
|
two, six = 0, 0
|
||||||
rows = [eval(r) for r in rows if r]
|
rows = [eval(r) for r in rows if r]
|
||||||
rows.append([[2]])
|
rows.append([[2]])
|
||||||
rows.append([[6]])
|
rows.append([[6]])
|
||||||
|
|
||||||
|
|
||||||
def cmp(x, y):
|
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):
|
for r in sorted(rows, key=functools.cmp_to_key(cmp), reverse=True):
|
||||||
@ -88,8 +91,6 @@ def part2(rows):
|
|||||||
print(two * six)
|
print(two * six)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
rows = shared.load_rows(13)
|
rows = shared.load_rows(13)
|
||||||
with shared.elapsed_timer() as elapsed:
|
with shared.elapsed_timer() as elapsed:
|
||||||
|
@ -23,7 +23,14 @@ def part1(rows):
|
|||||||
d = sand[1]
|
d = sand[1]
|
||||||
dr = sand[1] + 1
|
dr = sand[1] + 1
|
||||||
return next_y, (dl, d, dr)
|
return next_y, (dl, d, dr)
|
||||||
lines = [[list(reversed(list(map(int, point.split(","))))) for point in row.split(" -> ")] for row in 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)
|
(minY, maxY), (minX, maxX) = find_bounds(lines)
|
||||||
mx = matrix.matrix_of_size(maxX + 2, maxY + 2)
|
mx = matrix.matrix_of_size(maxX + 2, maxY + 2)
|
||||||
walls = []
|
walls = []
|
||||||
@ -75,7 +82,13 @@ def part1(rows):
|
|||||||
|
|
||||||
@shared.profile
|
@shared.profile
|
||||||
def part2(rows):
|
def part2(rows):
|
||||||
lines = [[list(reversed(list(map(int, point.split(","))))) for point in row.split(" -> ")] for row in 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)
|
(minY, maxY), (minX, maxX) = find_bounds(lines)
|
||||||
walls = {}
|
walls = {}
|
||||||
_between_points = matrix.coords_between_points
|
_between_points = matrix.coords_between_points
|
||||||
@ -120,6 +133,7 @@ def part2(rows):
|
|||||||
walls[tuple(sand)] = "#"
|
walls[tuple(sand)] = "#"
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
rows = [row for row in shared.load_rows(14)]
|
rows = [row for row in shared.load_rows(14)]
|
||||||
with shared.elapsed_timer() as elapsed:
|
with shared.elapsed_timer() as elapsed:
|
||||||
|
@ -8,9 +8,11 @@ from typing import Optional, List, Tuple
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
def cityblock(y1, x1, y2, x2):
|
def cityblock(y1, x1, y2, x2):
|
||||||
return abs(y2 - y1) + abs(x2 - x1)
|
return abs(y2 - y1) + abs(x2 - x1)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Sensor:
|
class Sensor:
|
||||||
sX: int
|
sX: int
|
||||||
@ -23,8 +25,10 @@ class Sensor:
|
|||||||
_border: List[Tuple[int, int]] = None
|
_border: List[Tuple[int, int]] = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (f"Sensor(sX={self.sX}, sY={self.sY}, bX={self.bX},"
|
return (
|
||||||
f"bY={self.bY}, d={self._d}, edges={len(self._edges)}, borders={len(self._borders)})")
|
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
|
@property
|
||||||
def s(self):
|
def s(self):
|
||||||
@ -62,7 +66,6 @@ class Sensor:
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def in_diamond(self):
|
def in_diamond(self):
|
||||||
sX, sY = self.sX, self.sY
|
sX, sY = self.sX, self.sY
|
||||||
up_lim = sY - self.distance
|
up_lim = sY - self.distance
|
||||||
@ -150,7 +153,9 @@ def part1(rows, sample=False):
|
|||||||
xSet = set()
|
xSet = set()
|
||||||
ySet = set()
|
ySet = set()
|
||||||
for row in rows:
|
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(x)
|
||||||
xSet.add(bx)
|
xSet.add(bx)
|
||||||
ySet.add(y)
|
ySet.add(y)
|
||||||
@ -205,8 +210,10 @@ def part1(rows, sample=False):
|
|||||||
mx[y][x] = "S"
|
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):
|
def part2(rows, sample=False):
|
||||||
sensors = []
|
sensors = []
|
||||||
sensor_points = []
|
sensor_points = []
|
||||||
@ -215,7 +222,9 @@ def part2(rows, sample=False):
|
|||||||
xSet = set()
|
xSet = set()
|
||||||
ySet = set()
|
ySet = set()
|
||||||
for row in rows:
|
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(x)
|
||||||
xSet.add(bx)
|
xSet.add(bx)
|
||||||
ySet.add(y)
|
ySet.add(y)
|
||||||
@ -281,11 +290,13 @@ def part2(rows, sample=False):
|
|||||||
if y <= maxY and x <= maxX:
|
if y <= maxY and x <= maxX:
|
||||||
mx[y][x] = "S"
|
mx[y][x] = "S"
|
||||||
|
|
||||||
|
|
||||||
mx[TARGET[0]][TARGET[1]] = "!"
|
mx[TARGET[0]][TARGET[1]] = "!"
|
||||||
matrix.highlight(mx, blink_green=[TARGET,])
|
matrix.highlight(
|
||||||
|
mx,
|
||||||
|
blink_green=[
|
||||||
|
TARGET,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -3,9 +3,12 @@ import matrix
|
|||||||
import shared
|
import shared
|
||||||
import scanf
|
import scanf
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from collections import defaultdict
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
import networkx as nx
|
||||||
|
|
||||||
|
from IPython.display import Image, display
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Valve:
|
class Valve:
|
||||||
@ -23,6 +26,7 @@ class Valve:
|
|||||||
def highest_potential(self):
|
def highest_potential(self):
|
||||||
return max(self.potential, key=self.potential.get)
|
return max(self.potential, key=self.potential.get)
|
||||||
|
|
||||||
|
|
||||||
def parse(rows):
|
def parse(rows):
|
||||||
valves = {}
|
valves = {}
|
||||||
for row in rows:
|
for row in rows:
|
||||||
@ -47,60 +51,91 @@ class Part1:
|
|||||||
self.rows = rows
|
self.rows = rows
|
||||||
self.sample = sample
|
self.sample = sample
|
||||||
self.valves = parse(rows)
|
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.cur = self.valves["AA"]
|
||||||
self.tick = 1
|
self.tick = 1
|
||||||
self.minutes = minutes
|
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):
|
def do_tick(self, minute):
|
||||||
pressure = 0
|
pressure = 0
|
||||||
opened = []
|
opened = []
|
||||||
for _, valve in self.valves.items():
|
for _, valve in self.valves.items():
|
||||||
if valve.opened_at > 0:
|
if valve.opened_at > 0:
|
||||||
continue
|
|
||||||
pressure += valve.rate
|
pressure += valve.rate
|
||||||
print(f"== Minute {minute} == [ {self.cur.label} ]")
|
opened.append(valve.label)
|
||||||
print(f"\tValves {', '.join(opened)} are open, releasing {pressure} pressure")
|
print(f"== Min {minute}:: Valves {', '.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)
|
|
||||||
|
|
||||||
def calculate_total_flow(self):
|
def calculate_total_flow(self):
|
||||||
total = 0
|
total = 0
|
||||||
for label, valve in self.valves.items():
|
for label, valve in self.valves.items():
|
||||||
if valve.is_open:
|
if valve.opened_at > 0:
|
||||||
total += valve.rate * (30 - valve.opened_at)
|
total += valve.rate * (30 - valve.opened_at)
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
for minute in range(1, self.minutes+1):
|
# Construct the graph with vertices & edges from the input
|
||||||
self.do_tick(minute)
|
# Call a function to compute the distances between every pair of vertices
|
||||||
self.open_or_move()
|
# 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:")
|
def priority(remaining):
|
||||||
print(self.calculate_total_flow())
|
_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())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,9 +8,11 @@ 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_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]
|
split_line_to_int_list = lambda y: [int(w) for w in y.split(" ") if w]
|
||||||
|
|
||||||
|
|
||||||
def split_x_out(l):
|
def split_x_out(l):
|
||||||
return [x for _, x in l]
|
return [x for _, x in l]
|
||||||
|
|
||||||
|
|
||||||
def split_y_out(l):
|
def split_y_out(l):
|
||||||
return [y for y, _ in l]
|
return [y for y, _ in l]
|
||||||
|
|
||||||
@ -154,7 +156,9 @@ def get_neighbor_coords(matrix, c, r, diagonals=True):
|
|||||||
return neighbors
|
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
|
Takes a matrix, a row, and a column
|
||||||
calculates the coordinates to the edge for all four cardinal directions
|
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))
|
row_ids = list(range(0, width))
|
||||||
|
|
||||||
if distance:
|
if distance:
|
||||||
up_ids, down_ids = list(reversed(col_ids[:col])), col_ids[col + 1 :col+distance+1]
|
up_ids, down_ids = (
|
||||||
left_ids, right_ids = list(reversed(row_ids[:row])), row_ids[row + 1 :row+distance+1]
|
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:
|
else:
|
||||||
up_ids, down_ids = list(reversed(col_ids[:col])), col_ids[col + 1 :]
|
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 :]
|
left_ids, right_ids = list(reversed(row_ids[:row])), row_ids[row + 1 :]
|
||||||
@ -226,8 +236,6 @@ def coords_between_points(point1, point2):
|
|||||||
return coords
|
return coords
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_size(matrix):
|
def get_size(matrix):
|
||||||
height = len(matrix)
|
height = len(matrix)
|
||||||
width = len(matrix[0])
|
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]))
|
out.append("".join([f(x) for x in c]))
|
||||||
return "\n".join(out)
|
return "\n".join(out)
|
||||||
|
|
||||||
|
|
||||||
def view_matrix(matrix, y1, x1, y2, x2):
|
def view_matrix(matrix, y1, x1, y2, x2):
|
||||||
lines = ppmx(matrix, pad=0, space=0).split("\n")
|
lines = ppmx(matrix, pad=0, space=0).split("\n")
|
||||||
for line in lines[y1 : y2 + 1]:
|
for line in lines[y1 : y2 + 1]:
|
||||||
print(line[x1:x2])
|
print(line[x1:x2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def highlight(matrix, red=[], green=[], blue=[], blink_green=[]):
|
def highlight(matrix, red=[], green=[], blue=[], blink_green=[]):
|
||||||
"""
|
"""
|
||||||
print a matrix of anything, Falsy values turns to `.` for clarity
|
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}"
|
new = f"{colors.BLINK}{colors.GREEN}{mx[y][x]}{colors.ENDC}"
|
||||||
mx[y][x] = new
|
mx[y][x] = new
|
||||||
print(ppmx(mx, pad=False, space=True, zero="0"))
|
print(ppmx(mx, pad=False, space=True, zero="0"))
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import cProfile
|
|||||||
import functools
|
import functools
|
||||||
import pstats
|
import pstats
|
||||||
|
|
||||||
def profile(func):
|
|
||||||
|
|
||||||
|
def profile(func):
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def inner(*args, **kwargs):
|
def inner(*args, **kwargs):
|
||||||
profiler = cProfile.Profile()
|
profiler = cProfile.Profile()
|
||||||
@ -15,19 +15,21 @@ def profile(func):
|
|||||||
retval = func(*args, **kwargs)
|
retval = func(*args, **kwargs)
|
||||||
finally:
|
finally:
|
||||||
profiler.disable()
|
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 = pstats.Stats(profiler, stream=profile_file)
|
||||||
stats.print_stats()
|
stats.print_stats()
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
spl = lambda y: [int(w) for w in y]
|
spl = lambda y: [int(w) for w in y]
|
||||||
|
|
||||||
|
|
||||||
def minmax(l):
|
def minmax(l):
|
||||||
return min(l), max(l)
|
return min(l), max(l)
|
||||||
|
|
||||||
|
|
||||||
def load_rows(day):
|
def load_rows(day):
|
||||||
return [row for row in load(day)]
|
return [row for row in load(day)]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user