day 14
This commit is contained in:
parent
d23a4e136b
commit
7f557097c6
165
src/day14.py
Normal file
165
src/day14.py
Normal file
@ -0,0 +1,165 @@
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from cpl_core.console import Console
|
||||
from cpl_core.utils import String
|
||||
from cpl_query.enumerable import Enumerable
|
||||
from cpl_query.extension import List
|
||||
from cpl_core.pipes import *
|
||||
|
||||
from aoc.aoc import get_input
|
||||
|
||||
# global vars
|
||||
day = 14
|
||||
aoc_input = get_input(2022, day)
|
||||
test_input = """498,4 -> 498,6 -> 496,6
|
||||
503,4 -> 502,4 -> 502,9 -> 494,9
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Position:
|
||||
x: int = 0
|
||||
y: int = 0
|
||||
|
||||
|
||||
def build_rocks(grid: List[List[str]], paths: List[List[Position]], index_map: List[int]):
|
||||
for path in paths:
|
||||
last_pos = None
|
||||
for pos in path:
|
||||
if last_pos is None:
|
||||
last_pos = pos
|
||||
continue
|
||||
|
||||
x_bias = 1 if last_pos.x - pos.x > 0 else -1
|
||||
y_bias = 1 if last_pos.y - pos.y > 0 else -1
|
||||
vertical = List(int).extend(range(pos.y, last_pos.y + y_bias, y_bias))
|
||||
horizontal = List(int).extend(range(index_map.index_of(pos.x), index_map.index_of(last_pos.x) + x_bias, x_bias))
|
||||
|
||||
for y in vertical:
|
||||
for x in horizontal:
|
||||
grid[y][x] = '#'
|
||||
|
||||
last_pos = pos
|
||||
|
||||
|
||||
def draw(grid: List[List[Position]], pos: Position = None):
|
||||
Console.clear()
|
||||
draw_grid = grid.select(lambda x: x.copy()).copy()
|
||||
if pos is not None:
|
||||
draw_grid[pos.y][pos.x] = 'x'
|
||||
|
||||
Console.write_line()
|
||||
i = 0
|
||||
for i, row in enumerate(draw_grid):
|
||||
Console.write_line(f'{i:03d}', ''.join(row))
|
||||
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
def place_tile(grid: List[List[Position]], x: int, y: int):
|
||||
grid[y][x] = 'o'
|
||||
|
||||
if grid[y - 1][x] == '.' and grid[y - 1][x + 1] != '#':
|
||||
grid[y - 1][x + 1] = '.'
|
||||
|
||||
elif grid[y - 1][x + 1] == 'o':
|
||||
grid[y - 1][x + 1] = '.'
|
||||
|
||||
if grid[y - 1][x] != '#':
|
||||
grid[y - 1][x] = '.'
|
||||
|
||||
|
||||
def in_boundary(grid: List[List[Position]], x: int, y: int) -> bool:
|
||||
return 0 <= y < grid.count() and 0 <= x < grid.first().count()
|
||||
|
||||
|
||||
def is_blocked(grid: List[List[Position]], x: int, y: int) -> bool:
|
||||
if not in_boundary(grid, x, y):
|
||||
return True
|
||||
|
||||
return grid[y][x] == 'o' or grid[y][x] == '#'
|
||||
|
||||
|
||||
def simulate_sand(grid: List[List[Position]], index_map: List[int]):
|
||||
start = Position(index_map.index_of(500), 0)
|
||||
x = start.x
|
||||
y = start.y
|
||||
count = 0
|
||||
|
||||
can_continue = True
|
||||
while can_continue:
|
||||
# draw(grid, Position(x, y))
|
||||
|
||||
# if grid[y + 1][x] == '.':
|
||||
# y += 1
|
||||
# continue
|
||||
|
||||
if not is_blocked(grid, x, y + 1):
|
||||
y += 1
|
||||
|
||||
elif not in_boundary(grid, x, y + 1):
|
||||
break
|
||||
|
||||
elif not is_blocked(grid, x - 1, y + 1):
|
||||
x -= 1
|
||||
y += 1
|
||||
|
||||
elif not in_boundary(grid, x - 1, y + 1):
|
||||
break
|
||||
|
||||
elif not is_blocked(grid, x + 1, y + 1):
|
||||
x += 1
|
||||
y += 1
|
||||
|
||||
elif not in_boundary(grid, x + 1, y + 1):
|
||||
break
|
||||
|
||||
else:
|
||||
count += 1
|
||||
if x == start.x and y == start.y:
|
||||
break
|
||||
|
||||
grid[y][x] = 'o'
|
||||
x = start.x
|
||||
y = start.y
|
||||
|
||||
draw(grid)
|
||||
Console.write_line(count)
|
||||
|
||||
|
||||
def main(text: str, part2=False):
|
||||
if part2:
|
||||
dx = 500
|
||||
text += f'{min_pos.x - dx},{max_pos.y + 2} -> {max_pos.x + dx},{max_pos.y + 2}'
|
||||
|
||||
paths: List[List[Position]] = List(Position, text.splitlines()) \
|
||||
.select(lambda x: List(str, x.split(' -> ')).select(lambda y: Position(int(y.split(',')[0]), int(y.split(',')[1]))))
|
||||
|
||||
paths_x = paths.select_many(lambda x: x)
|
||||
min_pos.x = paths_x.min(lambda x: x.x)
|
||||
min_pos.y = paths_x.min(lambda x: x.y)
|
||||
max_pos.x = paths_x.max(lambda x: x.x)
|
||||
max_pos.y = paths_x.max(lambda x: x.y)
|
||||
|
||||
index_map = List.range(min_pos.x, paths_x.max(lambda x: x.x) + 1)
|
||||
grid = List.range(0, max_pos.y + (3 if part2 else 1)).select(
|
||||
lambda y: index_map.select(lambda x: '.'))
|
||||
|
||||
grid[0][index_map.index_of(500)] = '+'
|
||||
|
||||
build_rocks(grid, paths, index_map)
|
||||
# draw(grid)
|
||||
simulate_sand(grid, index_map)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Console.write_line(f'Advent of code day {day}')
|
||||
max_pos = Position(0, 0)
|
||||
min_pos = Position(0, 0)
|
||||
# main(test_input)
|
||||
# main(test_input, True)
|
||||
main(aoc_input)
|
||||
main(aoc_input, True)
|
||||
Console.write_line()
|
Loading…
Reference in New Issue
Block a user