Compare commits

...

5 Commits

Author SHA1 Message Date
Tyrel Souza 6c482630c2 cleanup 2022-12-18 01:36:15 -05:00
Tyrel Souza 50d0429fc4 almost part 2 2022-12-18 00:57:30 -05:00
Tyrel Souza dcf50da61c Day18 part1 2022-12-18 00:28:24 -05:00
Tyrel Souza 58f2b05590 optimizations 2022-12-17 23:40:05 -05:00
Tyrel Souza 9611bfedf4 day17 part1 2022-12-17 23:09:54 -05:00
5 changed files with 2287 additions and 65 deletions

2025
2022/full/day18.txt Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

157
2022/python/day18.py Normal file
View File

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

13
2022/samples/day18.txt Normal file
View File

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