day16 still working:
This commit is contained in:
parent
139b6d7e12
commit
d7a1aac178
@ -8,11 +8,11 @@ def part1(rows):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# @shared.profile
|
||||
def part2(rows):
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
rows = [row for row in shared.load_rows(15)]
|
||||
with shared.elapsed_timer() as elapsed:
|
||||
|
@ -66,15 +66,18 @@ def check_group(left, right):
|
||||
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
|
||||
for r in sorted(rows, key=functools.cmp_to_key(cmp), reverse=True):
|
||||
@ -88,8 +91,6 @@ def part2(rows):
|
||||
print(two * six)
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
rows = shared.load_rows(13)
|
||||
with shared.elapsed_timer() as elapsed:
|
||||
|
@ -23,7 +23,14 @@ def part1(rows):
|
||||
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]
|
||||
|
||||
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 = []
|
||||
@ -75,7 +82,13 @@ def part1(rows):
|
||||
|
||||
@shared.profile
|
||||
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)
|
||||
walls = {}
|
||||
_between_points = matrix.coords_between_points
|
||||
@ -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:
|
||||
|
@ -8,9 +8,11 @@ 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)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Sensor:
|
||||
sX: int
|
||||
@ -23,8 +25,10 @@ class Sensor:
|
||||
_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):
|
||||
@ -62,7 +66,6 @@ class Sensor:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def in_diamond(self):
|
||||
sX, sY = self.sX, self.sY
|
||||
up_lim = sY - self.distance
|
||||
@ -150,7 +153,9 @@ 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)
|
||||
@ -205,8 +210,10 @@ def part1(rows, sample=False):
|
||||
mx[y][x] = "S"
|
||||
print(matrix.ppmx(mx, pad=False, space=True))
|
||||
|
||||
|
||||
tuning = lambda y, x: y + (4000000 * x)
|
||||
|
||||
|
||||
def part2(rows, sample=False):
|
||||
sensors = []
|
||||
sensor_points = []
|
||||
@ -215,7 +222,9 @@ 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)
|
||||
@ -281,11 +290,13 @@ def part2(rows, sample=False):
|
||||
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():
|
||||
|
@ -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:
|
||||
@ -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:
|
||||
@ -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)
|
||||
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())
|
||||
|
||||
|
||||
|
||||
|
@ -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_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]
|
||||
|
||||
|
||||
def split_y_out(l):
|
||||
return [y for y, _ in l]
|
||||
|
||||
@ -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 :]
|
||||
@ -226,8 +236,6 @@ def coords_between_points(point1, point2):
|
||||
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]:
|
||||
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"))
|
||||
|
||||
|
||||
|
@ -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,19 +15,21 @@ 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)
|
||||
|
||||
|
||||
def load_rows(day):
|
||||
return [row for row in load(day)]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user