Compare commits
5 Commits
1414bb26e7
...
6c482630c2
Author | SHA1 | Date |
---|---|---|
Tyrel Souza | 6c482630c2 | |
Tyrel Souza | 50d0429fc4 | |
Tyrel Souza | dcf50da61c | |
Tyrel Souza | 58f2b05590 | |
Tyrel Souza | 9611bfedf4 |
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@ import matrix
|
|||
import shared
|
||||
import scanf
|
||||
from dataclasses import dataclass
|
||||
from collections import defaultdict
|
||||
from collections import defaultdict, deque
|
||||
from typing import List, Dict
|
||||
from pprint import pprint
|
||||
import networkx as nx
|
||||
|
@ -89,7 +89,7 @@ class Part1:
|
|||
if valve.opened_at >= 0:
|
||||
pressure += valve.rate
|
||||
opened.append(valve.label)
|
||||
print(f"== Min {minute}:: {len(opened)} Valves {', '.join(opened)} are open, releasing {pressure} pressure")
|
||||
print(f"== Min {minute+1}:: {len(opened)} Valves {', '.join(opened)} are open, releasing {pressure} pressure")
|
||||
|
||||
def calculate_total_flow(self):
|
||||
total = 0
|
||||
|
@ -98,7 +98,46 @@ class Part1:
|
|||
total += valve.rate * (30 - valve.opened_at)
|
||||
return total
|
||||
|
||||
|
||||
def run(self):
|
||||
paths = defaultdict(lambda: -1)
|
||||
|
||||
# lbl, flow, time_left, visited
|
||||
q = deque([('AA', 0, self.minutes, set())])
|
||||
x = -1
|
||||
while q:
|
||||
x+=1
|
||||
# get recent nodes
|
||||
pos, flow, minutes_left, cur_path = q.popleft()
|
||||
|
||||
# find who we can reach in time
|
||||
reachable = [n for n in self.path_distances[pos]
|
||||
if n not in cur_path # not visited
|
||||
and self.path_distances[pos][n] < minutes_left]
|
||||
|
||||
hashable = frozenset(cur_path)
|
||||
if paths[hashable] < flow:
|
||||
paths[hashable] = flow
|
||||
|
||||
for r in reachable:
|
||||
d = self.path_distances[pos][r]
|
||||
r_flow = (minutes_left - d - 1) * self.valves[r].rate
|
||||
# add neighbor
|
||||
cur_path.add(r)
|
||||
q.append((r, flow + r_flow, minutes_left - d -1, cur_path))
|
||||
print("added",x,r)
|
||||
|
||||
print(paths.values())
|
||||
print(max(paths.values()))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _run(self):
|
||||
# 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
|
||||
|
@ -127,7 +166,7 @@ class Part1:
|
|||
if remaining <= 0:
|
||||
print("ran out of time")
|
||||
break
|
||||
self.do_tick(31-remaining)
|
||||
self.do_tick(30-remaining)
|
||||
|
||||
# CALCULATE PRIORITIES
|
||||
pris = priority(remaining)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import matrix
|
||||
import shared
|
||||
from dataclasses import dataclass
|
||||
from typing import Tuple
|
||||
from dataclasses import dataclass, field
|
||||
from functools import cached_property
|
||||
from typing import Tuple, List
|
||||
import operator
|
||||
|
||||
|
||||
|
@ -32,9 +33,10 @@ SQUARE = (
|
|||
(0,0),(0,1),
|
||||
)
|
||||
|
||||
ORDER = (('-',FLAT), ('+',CROSS), ('j',J), ('I',I), ('□',SQUARE))
|
||||
ORDER = (('-',FLAT), ('+',CROSS), ('j',J), ('I',I), ('o',SQUARE))
|
||||
|
||||
OPS = {'>':operator.add, '<':operator.sub}
|
||||
OFF = {'>': (0,1), '<':(0,-1)}
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -49,7 +51,11 @@ class Shape:
|
|||
def char(self):
|
||||
if self.moving:
|
||||
return '@'
|
||||
return '#'
|
||||
return self.at_rest_char
|
||||
|
||||
@property
|
||||
def at_rest_char(self):
|
||||
return ORDER[self.rock%5][0]
|
||||
|
||||
@property
|
||||
def str(self):
|
||||
|
@ -61,80 +67,73 @@ class Shape:
|
|||
|
||||
@property
|
||||
def coords(self):
|
||||
actual_coords = []
|
||||
for y,x in self.shape[1]:
|
||||
actual_coords.append((y+self.y,x+self.x))
|
||||
return actual_coords
|
||||
return [ (y+self.y,x+self.x) for y,x in self.shape[1]]
|
||||
|
||||
|
||||
# TODO: check left/right movement into an object
|
||||
|
||||
|
||||
def find_highest(shapes, default_height):
|
||||
if not shapes:
|
||||
return default_height
|
||||
all_y = []
|
||||
for s in shapes:
|
||||
for y,_ in s.coords:
|
||||
all_y.append(y)
|
||||
return min(all_y)
|
||||
#return min([y for s in shapes for y,_ in s.coords])
|
||||
return min([s.coords[0][0] for s in shapes[-20:]])
|
||||
#all_y = []
|
||||
#for s in shapes[-20:]:
|
||||
# all_y.append(s.coords[0][0])
|
||||
#return min(all_y)
|
||||
|
||||
def all_coords(shapes):
|
||||
coords = set()
|
||||
for s in shapes:
|
||||
for c in s.coords:
|
||||
coords.add(c)
|
||||
return coords
|
||||
|
||||
def collision_at(shapes, row, col, shape):
|
||||
if shape is None:
|
||||
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
|
||||
all_coords = set()
|
||||
|
||||
def collision_at(shapes, offset):
|
||||
if len(shapes) == 1:
|
||||
# Nothing to compare
|
||||
return False
|
||||
shape = shapes[-1]
|
||||
# Take in all existing coordinates
|
||||
for y,x in shape.coords:
|
||||
if (y+row,x+col) in all_coords(shapes[:-1]):
|
||||
breakpoint()
|
||||
if (y+offset[0],x+offset[1]) in all_coords:
|
||||
return True
|
||||
return False
|
||||
|
||||
def out_of_bounds(row, col, height, width, shape=None):
|
||||
def out_of_bounds(height, width, shapes, offset):
|
||||
shape = shapes[-1]
|
||||
if shape is None:
|
||||
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
|
||||
for y,x in shape:
|
||||
for y,x in shape.coords:
|
||||
#print(f"\t{row}+{y} > {height}\t", f"{col}+{x} > {width}\t", f"{col}+{x} < 0")
|
||||
if row+y > height-1:
|
||||
if y+offset[0] >= height:
|
||||
return True
|
||||
if col+x >= width:
|
||||
if x+offset[1] >= width:
|
||||
return True
|
||||
if col+x < 0:
|
||||
if x+offset[1] < 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
# @shared.profile
|
||||
@shared.profile
|
||||
def part1(rows):
|
||||
print(rows)
|
||||
instructions = [r for r in rows]
|
||||
height = 8
|
||||
#height = 2022*4+4
|
||||
height = 20
|
||||
height = 2022*4+4
|
||||
width = 7
|
||||
view = height - 20
|
||||
|
||||
rock = 0
|
||||
shapes = []
|
||||
spawning = True
|
||||
while rock < 2:
|
||||
while rock < 2022:
|
||||
if spawning:
|
||||
print("Spawn rock #", rock)
|
||||
# Add last rock's coords to all coords
|
||||
if shapes:
|
||||
for c in shapes[-1].coords:
|
||||
all_coords.add(c)
|
||||
X = 2
|
||||
Y = find_highest(shapes, height) - 4
|
||||
Y = find_highest(shapes, height) - 4
|
||||
shape = Shape(rock=rock, y=Y, x=X, shape=ORDER[rock%len(ORDER)])
|
||||
shapes.append(shape)
|
||||
spawning = False
|
||||
render(width, height, shapes)
|
||||
print("~"*20)
|
||||
#render(width, height, shapes)
|
||||
#print("~"*20)
|
||||
|
||||
|
||||
# loop through instructions
|
||||
|
@ -146,26 +145,21 @@ def part1(rows):
|
|||
|
||||
|
||||
# Try to move right/left
|
||||
print("Jet of gas pushes rock", next_move)
|
||||
|
||||
# TODO: make COLLISION_AT TAKE AN OFFSET
|
||||
next_x = OPS[next_move](shapes[-1].x, 1) # Try Move left or right
|
||||
if not out_of_bounds(shapes[-1].y, next_x, height, width, shapes[-1].offsets) and
|
||||
not collision_at(shapes, shapes[-1].y, next_x, shape):
|
||||
shapes[-1].x = next_x
|
||||
else:
|
||||
print("but nothing happens")
|
||||
next_offset = OFF[next_move]
|
||||
if not out_of_bounds(height,width, shapes, (0, next_offset[1])) and not collision_at(shapes, next_offset):
|
||||
shapes[-1].x += next_offset[1]
|
||||
|
||||
# check if hit bottom
|
||||
next_y = shapes[-1].y + 1
|
||||
if out_of_bounds(next_y, next_x, height, width, shapes[-1].offsets):
|
||||
print("rock comes to rest")
|
||||
next_offset = (1, next_offset[1])
|
||||
if out_of_bounds(height, width, shapes, (next_offset[0],0)):
|
||||
# hit bottom dont move down
|
||||
shapes[-1].moving = False
|
||||
spawning = True
|
||||
rock += 1
|
||||
continue
|
||||
|
||||
if collision_at(shapes, next_y, next_x, shape):
|
||||
if collision_at(shapes, (next_offset[0], 0)):
|
||||
# Hit another Block dont move down
|
||||
shapes[-1].moving = False
|
||||
spawning = True
|
||||
|
@ -173,14 +167,8 @@ def part1(rows):
|
|||
else:
|
||||
# can move down
|
||||
shapes[-1].y += 1
|
||||
print("rock falls one unit")
|
||||
|
||||
print("-"*15)
|
||||
render(width, height, shapes)
|
||||
|
||||
print(shapes[0], height, shapes[0].coords)
|
||||
|
||||
print("LAST ROCK COUNT", rock+1)
|
||||
#render(width, height, shapes)
|
||||
print(height - find_highest(shapes, height))
|
||||
|
||||
|
||||
|
@ -195,7 +183,7 @@ def render(width, height, shapes):
|
|||
|
||||
# @shared.profile
|
||||
def part2(rows):
|
||||
pass
|
||||
print("NAH BRO")
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
import matrix
|
||||
import shared
|
||||
from pprint import pprint
|
||||
from dataclasses import dataclass
|
||||
from typing import Set, Tuple
|
||||
from functools import cached_property
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cube:
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
neighbor_coords: Set[Tuple[int,int,int]] = None
|
||||
|
||||
@cached_property
|
||||
def xyz(self):
|
||||
return (self.x,self.y,self.z)
|
||||
|
||||
def set_neighbor_coords(self):
|
||||
self.neighbor_coords = get_neighbors(self.x,self.y,self.z)
|
||||
|
||||
def get_neighbors(x,y,z):
|
||||
# Generate the six neighbor_coords
|
||||
# Look at a die 6 to the left, 2 on top, one on right
|
||||
offsets = (
|
||||
(1,0,0), # 1
|
||||
(0,0,1), # 2
|
||||
(0,-1,0),# 3
|
||||
(0,1,0), # 4
|
||||
(0,0,-1),# 5
|
||||
(-1,0,0) # 6
|
||||
)
|
||||
neighbor_coords = set([(x+o[0], y+o[1], z+o[2]) for o in offsets])
|
||||
return neighbor_coords
|
||||
|
||||
def count_neighbor_coords(x,y,z):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# @shared.profile
|
||||
def part1(rows):
|
||||
cubes = {}
|
||||
for idx, (x,y,z) in enumerate(rows):
|
||||
cubes[(x,y,z)] = {'n':get_neighbors(x,y,z), 'not_me': tuple(map(tuple,rows[:idx] + rows[idx+1:]))}
|
||||
potential = len(cubes) * 6
|
||||
for coords, cube in cubes.items():
|
||||
for other in cube['not_me']:
|
||||
if other in cube['n']:
|
||||
potential -= 1
|
||||
print(potential)
|
||||
|
||||
|
||||
|
||||
def part2(rows):
|
||||
cubes = {}
|
||||
maxX,maxY,maxZ = 0,0,0
|
||||
for idx, (x,y,z) in enumerate(rows):
|
||||
cubes[(x,y,z)] = {'n':get_neighbors(x,y,z), 'not_me': set(map(tuple,rows[:idx] + rows[idx+1:]))}
|
||||
maxX = max(maxX,x)
|
||||
maxY = max(maxY,y)
|
||||
maxZ = max(maxZ,z)
|
||||
_cubes = frozenset(cubes.keys())
|
||||
|
||||
potential = len(cubes) * 6
|
||||
for coords, cube in cubes.items():
|
||||
for other in cube['not_me']:
|
||||
if other in cube['n']:
|
||||
potential -= 1
|
||||
|
||||
air = set()
|
||||
for x in range(0,maxX+1):
|
||||
for y in range(0,maxY+1):
|
||||
for z in range(0,maxZ+1):
|
||||
air.add((x,y,z))
|
||||
air -= _cubes # Remove all lava from air
|
||||
|
||||
for a in air:
|
||||
neighbors = get_neighbors(*a)
|
||||
if len(neighbors & _cubes)==6:
|
||||
#print(a, "====", neighbors & _cubes)
|
||||
potential -= 6
|
||||
|
||||
|
||||
# _ns = get_neighbors(x,y,z)
|
||||
# lava_neighbors = _ns & _cubes
|
||||
# if len(lava_neighbors) == 6:
|
||||
# potential -= 6
|
||||
print(potential)
|
||||
|
||||
|
||||
|
||||
# @shared.profile
|
||||
def _part2(rows):
|
||||
cubes = []
|
||||
|
||||
_lava = set()
|
||||
for row in rows:
|
||||
x,y,z = row
|
||||
maxX = max(maxX,x)
|
||||
maxY = max(maxY,y)
|
||||
maxZ = max(maxZ,z)
|
||||
cube = Cube(x=x,y=y,z=z)
|
||||
cube.set_neighbor_coords()
|
||||
cubes.append(cube)
|
||||
_lava.add((x,y,z))
|
||||
print(maxX,maxY,maxZ)
|
||||
|
||||
potential = len(cubes) * 6
|
||||
for idx in range(len(cubes)):
|
||||
cube = cubes[idx]
|
||||
others = cubes[:idx] + cubes[idx+1:]
|
||||
for other in others:
|
||||
if other.xyz in cube.neighbor_coords:
|
||||
potential -= 1
|
||||
|
||||
|
||||
air = []
|
||||
for x in range(0,maxX+1):
|
||||
for y in range(0,maxY+1):
|
||||
for z in range(0,maxZ+1):
|
||||
lava_count = 0
|
||||
if (x,y,z) in _lava:
|
||||
continue
|
||||
|
||||
# is air
|
||||
air_touching_lava = False
|
||||
for _n in _ns:
|
||||
if _n in _lava:
|
||||
lava_count += 1
|
||||
air_touching_lava = True
|
||||
|
||||
if air_touching_lava:
|
||||
air.append((x,y,z))
|
||||
|
||||
if lava_count == 6:
|
||||
potential -= 6
|
||||
|
||||
|
||||
print(potential, air)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
rows = [list(map(int,row.split(","))) for row in shared.load_rows(18)]
|
||||
with shared.elapsed_timer() as elapsed:
|
||||
part1(rows)
|
||||
print("🕒", elapsed())
|
||||
#rows = [map(int,row.split(",")) for row in shared.load_rows(18)]
|
||||
with shared.elapsed_timer() as elapsed:
|
||||
part2(rows)
|
||||
print("🕒", elapsed())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,13 @@
|
|||
2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
Loading…
Reference in New Issue