advent-of-code/2022/python/day17.py
2022-12-17 11:00:16 -05:00

213 lines
4.8 KiB
Python

import matrix
import shared
from dataclasses import dataclass
from typing import Tuple
import operator
# ####
FLAT = ((0,0),(0,1),(0,2),(0,3))
# .#.
# ###
# .#.
CROSS = (
(-2,1),
(-1,0),(-1,1),(-1,2),
(0,1))
# ..#
# ..#
# ###
J = ( (-2,2),
(-1,2),
(0,0),(0,1),(0,2))
# #
# #
# #
# #
I = ((0,0),(-1,0),(-2,0),(-3,0))
# ##
# ##
SQUARE = (
(-1,0),(-1,1),
(0,0),(0,1),
)
ORDER = (('-',FLAT), ('+',CROSS), ('j',J), ('I',I), ('',SQUARE))
OPS = {'>':operator.add, '<':operator.sub}
@dataclass
class Shape:
rock:int
y:int
x:int
shape: Tuple[str,Tuple[Tuple[int,int]]] # ('j', ((0,0),....))
moving: bool = True
@property
def char(self):
if self.moving:
return '@'
return '#'
@property
def str(self):
return self.shape[0]
@property
def offsets(self):
return self.shape[1]
@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
# 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)
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")
# Take in all existing coordinates
for y,x in shape.coords:
if (y+row,x+col) in all_coords(shapes[:-1]):
breakpoint()
return True
return False
def out_of_bounds(row, col, height, width, shape=None):
if shape is None:
raise Exception("Please provide a list of coordinate offsets from Y,X to draw")
for y,x in shape:
#print(f"\t{row}+{y} > {height}\t", f"{col}+{x} > {width}\t", f"{col}+{x} < 0")
if row+y > height-1:
return True
if col+x >= width:
return True
if col+x < 0:
return True
return False
# @shared.profile
def part1(rows):
print(rows)
instructions = [r for r in rows]
height = 8
#height = 2022*4+4
width = 7
view = height - 20
rock = 0
shapes = []
spawning = True
while rock < 2:
if spawning:
print("Spawn rock #", rock)
X = 2
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)
# loop through instructions
try:
next_move = instructions.pop(0)
except IndexError:
instructions = [r for r in rows]
next_move = instructions.pop(0)
# 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")
# 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")
# hit bottom dont move down
shapes[-1].moving = False
spawning = True
rock += 1
if collision_at(shapes, next_y, next_x, shape):
# Hit another Block dont move down
shapes[-1].moving = False
spawning = True
rock += 1
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)
print(height - find_highest(shapes, height))
def render(width, height, shapes):
print("-"*15)
mx = matrix.matrix_of_size(width, height)
for s in shapes:
matrix.draw_shape_at(mx, s.y, s.x, s.offsets, s.char)
print(matrix.ppmx(mx,pad=False,space=False))
# @shared.profile
def part2(rows):
pass
def main():
rows = [row for row in shared.load_rows(17)][0]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
with shared.elapsed_timer() as elapsed:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()