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

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

View File

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

View File

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

View File

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

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

View File

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

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