day 14
This commit is contained in:
		
							
								
								
									
										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() | ||||
		Reference in New Issue
	
	Block a user