feat: solve day 20 part 1
This commit is contained in:
parent
4f1e08a310
commit
ec25382f66
1727
20/input.txt
Normal file
1727
20/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
149
20/main.py
Normal file
149
20/main.py
Normal file
@ -0,0 +1,149 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterator, Optional
|
||||
from math import floor
|
||||
|
||||
@dataclass
|
||||
class Tile:
|
||||
top: str
|
||||
left: str
|
||||
right: str
|
||||
bottom: str
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Tile"
|
||||
|
||||
TilesData = dict[int, Tile]
|
||||
TileGrid = list[list[Optional[tuple[int, Tile]]]]
|
||||
|
||||
def parse_tile(tile_data: str) -> tuple[int, Tile]:
|
||||
lines = tile_data.splitlines()
|
||||
id = int(lines[0][4:-1])
|
||||
top_edge = lines[1]
|
||||
right_edge = "".join(line[-1] for line in lines[1:])
|
||||
left_edge = "".join(line[0] for line in lines[1:])
|
||||
bottom_edge = lines[-1]
|
||||
return id, Tile(top_edge, left_edge, right_edge, bottom_edge)
|
||||
|
||||
def parse_input(filename: str) -> TilesData:
|
||||
tiles = {}
|
||||
with open(filename, "r") as f:
|
||||
content = f.read()
|
||||
for block in content.split("\n\n"):
|
||||
id, tile = parse_tile(block)
|
||||
tiles[id] = tile
|
||||
return tiles
|
||||
|
||||
def rotate_tile(tile) -> Tile:
|
||||
return Tile(
|
||||
top = tile.left[::-1],
|
||||
right = tile.top,
|
||||
bottom = tile.right[::-1],
|
||||
left = tile.bottom
|
||||
)
|
||||
|
||||
def flip_tile(tile) -> Tile:
|
||||
return Tile(
|
||||
top = tile.bottom,
|
||||
right = tile.right[::-1],
|
||||
bottom = tile.top,
|
||||
left = tile.left[::-1]
|
||||
)
|
||||
|
||||
def get_grid_size(tiles: TilesData) -> int:
|
||||
return floor(len(tiles)**0.5)
|
||||
|
||||
def get_rotated_tiles(tile: Tile) -> Iterator[Tile]:
|
||||
yield tile
|
||||
tile = rotate_tile(tile)
|
||||
yield tile
|
||||
tile = rotate_tile(tile)
|
||||
yield tile
|
||||
tile = rotate_tile(tile)
|
||||
yield tile
|
||||
|
||||
def get_tile_variants(tile: Tile) -> Iterator[Tile]:
|
||||
for t in get_rotated_tiles(tile):
|
||||
yield t
|
||||
|
||||
tile = flip_tile(tile)
|
||||
for t in get_rotated_tiles(tile):
|
||||
yield t
|
||||
|
||||
def is_tile_possible(grid: TileGrid, x: int, y: int, tile: Tile) -> bool:
|
||||
if x > 0:
|
||||
other_tile = grid[y][x-1]
|
||||
if other_tile and other_tile[1].right != tile.left:
|
||||
return False
|
||||
|
||||
if x < len(grid[0])-1:
|
||||
other_tile = grid[y][x+1]
|
||||
if other_tile and other_tile[1].left != tile.right:
|
||||
return False
|
||||
|
||||
if y > 0:
|
||||
other_tile = grid[y-1][x]
|
||||
if other_tile and other_tile[1].bottom != tile.top:
|
||||
return False
|
||||
|
||||
if y < len(grid)-1:
|
||||
other_tile = grid[y+1][x]
|
||||
if other_tile and other_tile[1].top != tile.bottom:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_possible_tiles(
|
||||
tiles_data: TilesData,
|
||||
used_tiles: list[int],
|
||||
grid: TileGrid,
|
||||
x: int,
|
||||
y: int
|
||||
) -> Iterator[tuple[int, Tile]]:
|
||||
for id in tiles_data.keys():
|
||||
if id not in used_tiles:
|
||||
for variant in get_tile_variants(tiles_data[id]):
|
||||
if is_tile_possible(grid, x, y, variant):
|
||||
yield id, variant
|
||||
|
||||
def solve(tiles_data: TilesData, grid: TileGrid, used_tiles: list[int]=[]) -> bool:
|
||||
for y in range(len(grid)):
|
||||
for x in range(len(grid[0])):
|
||||
if grid[y][x] == None:
|
||||
for id, tile in get_possible_tiles(tiles_data, used_tiles, grid, x, y):
|
||||
grid[y][x] = (id, tile)
|
||||
used_tiles.append(id)
|
||||
if solve(tiles_data, grid):
|
||||
return True
|
||||
used_tiles.pop()
|
||||
grid[y][x] = None
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def multiply_corners(grid: TileGrid) -> int:
|
||||
w = len(grid[0])
|
||||
h = len(grid)
|
||||
top_left = grid[0][0]
|
||||
top_right = grid[0][w-1]
|
||||
bottom_left = grid[h-1][0]
|
||||
bottom_right = grid[h-1][w-1]
|
||||
assert top_left
|
||||
assert top_right
|
||||
assert bottom_left
|
||||
assert bottom_right
|
||||
return top_left[0] * top_right[0] * bottom_right[0] * bottom_left[0]
|
||||
|
||||
def part1(tiles: TilesData) -> int:
|
||||
width = get_grid_size(tiles)
|
||||
|
||||
grid: TileGrid = []
|
||||
for _ in range(width):
|
||||
grid.append([None]*width)
|
||||
|
||||
solve(tiles, grid)
|
||||
|
||||
return multiply_corners(grid)
|
||||
|
||||
if __name__ == "__main__":
|
||||
tiles = parse_input("input.txt")
|
||||
print("part1: ", part1(tiles))
|
107
20/test.txt
Normal file
107
20/test.txt
Normal file
@ -0,0 +1,107 @@
|
||||
Tile 2311:
|
||||
..##.#..#.
|
||||
##..#.....
|
||||
#...##..#.
|
||||
####.#...#
|
||||
##.##.###.
|
||||
##...#.###
|
||||
.#.#.#..##
|
||||
..#....#..
|
||||
###...#.#.
|
||||
..###..###
|
||||
|
||||
Tile 1951:
|
||||
#.##...##.
|
||||
#.####...#
|
||||
.....#..##
|
||||
#...######
|
||||
.##.#....#
|
||||
.###.#####
|
||||
###.##.##.
|
||||
.###....#.
|
||||
..#.#..#.#
|
||||
#...##.#..
|
||||
|
||||
Tile 1171:
|
||||
####...##.
|
||||
#..##.#..#
|
||||
##.#..#.#.
|
||||
.###.####.
|
||||
..###.####
|
||||
.##....##.
|
||||
.#...####.
|
||||
#.##.####.
|
||||
####..#...
|
||||
.....##...
|
||||
|
||||
Tile 1427:
|
||||
###.##.#..
|
||||
.#..#.##..
|
||||
.#.##.#..#
|
||||
#.#.#.##.#
|
||||
....#...##
|
||||
...##..##.
|
||||
...#.#####
|
||||
.#.####.#.
|
||||
..#..###.#
|
||||
..##.#..#.
|
||||
|
||||
Tile 1489:
|
||||
##.#.#....
|
||||
..##...#..
|
||||
.##..##...
|
||||
..#...#...
|
||||
#####...#.
|
||||
#..#.#.#.#
|
||||
...#.#.#..
|
||||
##.#...##.
|
||||
..##.##.##
|
||||
###.##.#..
|
||||
|
||||
Tile 2473:
|
||||
#....####.
|
||||
#..#.##...
|
||||
#.##..#...
|
||||
######.#.#
|
||||
.#...#.#.#
|
||||
.#########
|
||||
.###.#..#.
|
||||
########.#
|
||||
##...##.#.
|
||||
..###.#.#.
|
||||
|
||||
Tile 2971:
|
||||
..#.#....#
|
||||
#...###...
|
||||
#.#.###...
|
||||
##.##..#..
|
||||
.#####..##
|
||||
.#..####.#
|
||||
#..#.#..#.
|
||||
..####.###
|
||||
..#.#.###.
|
||||
...#.#.#.#
|
||||
|
||||
Tile 2729:
|
||||
...#.#.#.#
|
||||
####.#....
|
||||
..#.#.....
|
||||
....#..#.#
|
||||
.##..##.#.
|
||||
.#.####...
|
||||
####.#.#..
|
||||
##.####...
|
||||
##..#.##..
|
||||
#.##...##.
|
||||
|
||||
Tile 3079:
|
||||
#.#.#####.
|
||||
.#..######
|
||||
..#.......
|
||||
######....
|
||||
####.#..#.
|
||||
.#...#.##.
|
||||
#.#####.##
|
||||
..#.###...
|
||||
..#.......
|
||||
..#.###...
|
Loading…
Reference in New Issue
Block a user