Create day20.py
This commit is contained in:
parent
5591e3f9b8
commit
03661e6ed4
172
2020/Python/day20.py
Normal file
172
2020/Python/day20.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
from enum import Enum
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Side(Enum):
|
||||
UP = 1
|
||||
DOWN = 2
|
||||
LEFT = 4
|
||||
RIGHT = 8
|
||||
|
||||
|
||||
class Tile:
|
||||
def __init__(self, uid: str, image: list[list[str]]):
|
||||
self.uid = uid
|
||||
self.image = image
|
||||
self.up: Union[Tile, None] = None
|
||||
self.down: Union[Tile, None] = None
|
||||
self.left: Union[Tile, None] = None
|
||||
self.right: Union[Tile, None] = None
|
||||
|
||||
def flip_ud(self) -> 'Tile':
|
||||
cache = self.up
|
||||
self.up = self.down
|
||||
self.up = cache
|
||||
self.image = list(reversed(self.image))
|
||||
return self
|
||||
|
||||
def flip_lr(self) -> 'Tile':
|
||||
cache = self.left
|
||||
self.left = self.right
|
||||
self.right = cache
|
||||
for i in range(len(self.image)):
|
||||
self.image[i] = list(reversed(self.image[i]))
|
||||
return self
|
||||
|
||||
def rotate_l(self) -> 'Tile':
|
||||
new_image = []
|
||||
for i in range(len(self.image[0])):
|
||||
new_image.append([])
|
||||
for line in self.image:
|
||||
for i in range(len(line)):
|
||||
new_image[i].append(list(reversed(line))[i])
|
||||
self.image = new_image
|
||||
return self
|
||||
|
||||
def rotate_r(self) -> 'Tile':
|
||||
new_image = []
|
||||
for i in range(len(self.image[0])):
|
||||
new_image.append([])
|
||||
for line in reversed(self.image):
|
||||
for i in range(len(line)):
|
||||
new_image[i].append(line[i])
|
||||
self.image = new_image
|
||||
return self
|
||||
|
||||
def align_to(self, edge: str, side: Side):
|
||||
if edge not in self.get_all_edges():
|
||||
return
|
||||
rev = "".join(reversed(edge))
|
||||
if side == Side.UP:
|
||||
while "".join(self.image[0]) not in [edge, rev]:
|
||||
self.rotate_r()
|
||||
if "".join(self.image[0]) == rev:
|
||||
self.flip_lr()
|
||||
elif side == side.DOWN:
|
||||
while "".join(self.image[len(self.image)-1]) not in [edge, rev]:
|
||||
self.rotate_r()
|
||||
if "".join(self.image[len(self.image)-1]) == rev:
|
||||
self.flip_lr()
|
||||
elif side == side.LEFT:
|
||||
while "".join([line[0] for line in self.image]) not in [edge, rev]:
|
||||
self.rotate_r()
|
||||
if "".join([line[0] for line in self.image]) == rev:
|
||||
self.flip_ud()
|
||||
elif side == side.RIGHT:
|
||||
while "".join([line[len(self.image[0])-1] for line in self.image]) not in [edge, rev]:
|
||||
self.rotate_r()
|
||||
if "".join([line[len(self.image[0])-1] for line in self.image]) == rev:
|
||||
self.flip_ud()
|
||||
|
||||
def get_all_edges(self) -> list[str]:
|
||||
all_edges = []
|
||||
up = "".join(self.image[0])
|
||||
down = "".join(self.image[len(self.image)-1])
|
||||
left = "".join([line[0] for line in self.image])
|
||||
right = "".join([line[len(self.image[0])-1] for line in self.image])
|
||||
all_edges += [up, down, left, right, "".join(reversed(up)), "".join(reversed(down)), "".join(reversed(left)), "".join(reversed(right))]
|
||||
return all_edges
|
||||
|
||||
def count_connections(self) -> int:
|
||||
return sum([1 if x else 0 for x in [self.up, self.down, self.left, self.right]])
|
||||
|
||||
def print(self):
|
||||
print(f"Tile {self.uid}:")
|
||||
for line in self.image:
|
||||
print("".join(line))
|
||||
|
||||
def __str__(self):
|
||||
return f"Tile {self.uid}"
|
||||
|
||||
|
||||
def parse_data() -> list[Tile]:
|
||||
output = []
|
||||
current_img = [['.']]
|
||||
current_title = ""
|
||||
with open("input.txt") as file:
|
||||
for line in file:
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
if line[0] == 'T':
|
||||
output.append(Tile(current_title, current_img))
|
||||
current_title = line.split(" ")[1][:-1]
|
||||
current_img = []
|
||||
elif line[0] in ['#', '.']:
|
||||
current_img.append(list(line))
|
||||
output.append(Tile(current_title, current_img))
|
||||
return output[1:]
|
||||
|
||||
|
||||
def connect_tiles(data: list[Tile], already_done: set[str], tile: Tile):
|
||||
if tile.uid in already_done:
|
||||
return
|
||||
already_done.add(tile.uid)
|
||||
|
||||
up = "".join(tile.image[0])
|
||||
down = "".join(tile.image[len(tile.image) - 1])
|
||||
left = "".join([line[0] for line in tile.image])
|
||||
right = "".join([line[len(tile.image[0]) - 1] for line in tile.image])
|
||||
for other_tile in data:
|
||||
if other_tile.uid in already_done or tile.uid == other_tile.uid:
|
||||
continue
|
||||
other_edges = other_tile.get_all_edges()
|
||||
if up in other_edges:
|
||||
other_tile.align_to(up, Side.DOWN)
|
||||
tile.up = other_tile
|
||||
other_tile.down = tile
|
||||
elif down in other_edges:
|
||||
other_tile.align_to(down, Side.UP)
|
||||
tile.down = other_tile
|
||||
other_tile.up = tile
|
||||
elif left in other_edges:
|
||||
other_tile.align_to(left, Side.RIGHT)
|
||||
tile.left = other_tile
|
||||
other_tile.right = tile
|
||||
elif right in other_edges:
|
||||
other_tile.align_to(right, Side.LEFT)
|
||||
tile.right = other_tile
|
||||
other_tile.left = tile
|
||||
if tile.up:
|
||||
connect_tiles(data, already_done, tile.up)
|
||||
if tile.down:
|
||||
connect_tiles(data, already_done, tile.down)
|
||||
if tile.left:
|
||||
connect_tiles(data, already_done, tile.left)
|
||||
if tile.right:
|
||||
connect_tiles(data, already_done, tile.right)
|
||||
|
||||
|
||||
def solve_p1(data: list[Tile]) -> int:
|
||||
result = 1
|
||||
for tile in data:
|
||||
if tile.count_connections() == 2:
|
||||
result *= int(tile.uid)
|
||||
return result
|
||||
|
||||
|
||||
DATA = parse_data()
|
||||
connect_tiles(DATA, set(), DATA[0].flip_ud())
|
||||
print(solve_p1(DATA))
|
||||
|
Loading…
Reference in a new issue