day20
This commit is contained in:
parent
bce004b604
commit
70a6f59cf9
|
|
@ -0,0 +1,323 @@
|
|||
from functools import reduce
|
||||
|
||||
|
||||
def read_tile(tile_text):
|
||||
tile_split = [l for l in tile_text.split('\n') if l != '']
|
||||
tile_id = int(tile_split[0][5:9])
|
||||
return tile_id, tile_split[1:]
|
||||
|
||||
|
||||
def read_tiles():
|
||||
with open('day20/input') as reader:
|
||||
tiles_as_text = [l for l in reader.read().split('\n\n') if l != '']
|
||||
|
||||
tiles = {}
|
||||
for tile in map(read_tile, tiles_as_text):
|
||||
tiles[tile[0]] = tile[1]
|
||||
return tiles
|
||||
|
||||
|
||||
def get_top_border(tile):
|
||||
return tile[0]
|
||||
|
||||
|
||||
def get_left_border(tile):
|
||||
return ''.join([l[0] for l in tile])
|
||||
|
||||
|
||||
def get_right_border(tile):
|
||||
return ''.join([l[-1] for l in tile])
|
||||
|
||||
def get_bottom_border(tile):
|
||||
return tile[-1]
|
||||
|
||||
def get_borders_without_flip(tile):
|
||||
return get_top_border(tile), get_bottom_border(tile), get_left_border(tile), get_right_border(tile)
|
||||
|
||||
|
||||
def flip_borders(borders):
|
||||
return map(lambda s: ''.join(list(reversed(s))), borders)
|
||||
|
||||
|
||||
def get_borders(tile):
|
||||
borders = get_borders_without_flip(tile)
|
||||
reversed_borders = flip_borders(borders)
|
||||
return [*borders, *reversed_borders]
|
||||
|
||||
|
||||
def get_all_tile_borders(tiles):
|
||||
tile_borders = {}
|
||||
for key, value in tiles.items():
|
||||
tile_borders[key] = get_borders(value)
|
||||
return tile_borders
|
||||
|
||||
|
||||
def find_corners(tiles):
|
||||
tile_borders = get_all_tile_borders(tiles)
|
||||
corner_parts = {}
|
||||
border_parts = {}
|
||||
inner_parts = {}
|
||||
for t_key, t_value in tile_borders.items():
|
||||
borders = list(t_value)
|
||||
for check_key, check_value in tile_borders.items():
|
||||
borders_to_remove = []
|
||||
if t_key == check_key:
|
||||
continue
|
||||
|
||||
for b in borders:
|
||||
if b in check_value:
|
||||
borders_to_remove.append(b)
|
||||
|
||||
for r in borders_to_remove:
|
||||
borders.remove(r)
|
||||
if len(borders) == 4:
|
||||
corner_parts[t_key] = borders
|
||||
elif len(borders) == 2:
|
||||
border_parts[t_key] = borders
|
||||
else:
|
||||
inner_parts[t_key] = borders
|
||||
return corner_parts, border_parts, inner_parts
|
||||
|
||||
|
||||
def rotate_right(tile_image):
|
||||
r_len = len(tile_image)
|
||||
c_len = len(tile_image[0])
|
||||
rotated = []
|
||||
for col in range(c_len):
|
||||
rotated.append(''.join([tile_image[row][col] for row in reversed(range(r_len))]))
|
||||
return rotated
|
||||
|
||||
|
||||
def flip_left_to_right_image(tile_image):
|
||||
r_len = len(tile_image)
|
||||
flipped = []
|
||||
for row in range(r_len):
|
||||
flipped.append(''.join(reversed(tile_image[row])))
|
||||
return flipped
|
||||
|
||||
|
||||
def is_top_border(tile, check_border):
|
||||
return get_top_border(tile) == check_border
|
||||
|
||||
|
||||
def is_left_border(tile, check_border):
|
||||
return get_left_border(tile) == check_border
|
||||
|
||||
|
||||
def top_left_border(tile, borders):
|
||||
return sum(map(lambda b: is_top_border(tile, b), borders)) == 1 and sum(map(lambda b: is_left_border(tile, b), borders)) == 1
|
||||
|
||||
|
||||
def top_border(tile, borders):
|
||||
return sum(map(lambda b: is_top_border(tile, b), borders)) == 1
|
||||
|
||||
|
||||
def orientation_corner_top_left(tile, borders):
|
||||
while not top_left_border(tile, borders):
|
||||
tile = rotate_right(tile)
|
||||
return tile
|
||||
|
||||
|
||||
def orientation_border_top(tile, borders):
|
||||
while not top_border(tile, borders):
|
||||
tile = rotate_right(tile)
|
||||
return tile
|
||||
|
||||
|
||||
def orientation_all_border_top(tiles, border_tiles):
|
||||
changed_orientation_borders = {}
|
||||
for key, value in border_tiles.items():
|
||||
border_tile_image = tiles[key]
|
||||
orientation_border_tile_image = orientation_border_top(border_tile_image, value)
|
||||
changed_orientation_borders[key] = orientation_border_tile_image
|
||||
return changed_orientation_borders
|
||||
|
||||
|
||||
def build_top_from_left(tiles, starting_title, border_tiles, corners):
|
||||
current = tiles[starting_title]
|
||||
current_right = get_right_border(current)
|
||||
changed_orientation_borders = orientation_all_border_top(tiles, border_tiles)
|
||||
border_keys = list(changed_orientation_borders.keys())
|
||||
|
||||
top = [starting_title]
|
||||
while True:
|
||||
found_next_key = None
|
||||
flip = False
|
||||
for bk in border_keys:
|
||||
if current_right == get_left_border(changed_orientation_borders[bk]):
|
||||
found_next_key = bk
|
||||
break
|
||||
if current_right == get_right_border(changed_orientation_borders[bk]):
|
||||
found_next_key = bk
|
||||
flip = True
|
||||
break
|
||||
|
||||
if found_next_key is not None:
|
||||
if flip:
|
||||
tiles[found_next_key] = flip_left_to_right_image(changed_orientation_borders[found_next_key])
|
||||
else:
|
||||
tiles[found_next_key] = changed_orientation_borders[found_next_key]
|
||||
|
||||
current_right = get_right_border(tiles[found_next_key])
|
||||
top.append(found_next_key)
|
||||
border_keys.remove(found_next_key)
|
||||
else:
|
||||
# top done, except last corner
|
||||
break
|
||||
|
||||
for c_key in corners.keys():
|
||||
if current_right in get_borders(tiles[c_key]):
|
||||
top.append(c_key)
|
||||
top_right_corner_tile = tiles[c_key]
|
||||
for i in range(4):
|
||||
if current_right != get_left_border(top_right_corner_tile):
|
||||
top_right_corner_tile = rotate_right(top_right_corner_tile)
|
||||
else:
|
||||
break
|
||||
|
||||
if current_right != get_left_border(top_right_corner_tile):
|
||||
top_right_corner_tile = flip_left_to_right_image(top_right_corner_tile)
|
||||
for i in range(4):
|
||||
if current_right != get_left_border(top_right_corner_tile):
|
||||
top_right_corner_tile = rotate_right(top_right_corner_tile)
|
||||
else:
|
||||
break
|
||||
tiles[c_key] = top_right_corner_tile
|
||||
break
|
||||
|
||||
return top
|
||||
|
||||
|
||||
def find_tile_for_bottom_border(tiles, bottom_border, remaining):
|
||||
found_key = None
|
||||
for r_key in remaining:
|
||||
if bottom_border in get_borders(tiles[r_key]):
|
||||
found_key = r_key
|
||||
found_tile = tiles[r_key]
|
||||
for i in range(4):
|
||||
if bottom_border != get_top_border(found_tile):
|
||||
found_tile = rotate_right(found_tile)
|
||||
else:
|
||||
break
|
||||
|
||||
if bottom_border != get_top_border(found_tile):
|
||||
found_tile = flip_left_to_right_image(found_tile)
|
||||
for i in range(4):
|
||||
if bottom_border != get_top_border(found_tile):
|
||||
found_tile = rotate_right(found_tile)
|
||||
else:
|
||||
break
|
||||
tiles[r_key] = found_tile
|
||||
break
|
||||
return found_key
|
||||
|
||||
|
||||
def build_image_from(tiles, image_tiles):
|
||||
tile_size = 10
|
||||
lines = []
|
||||
for rows in image_tiles:
|
||||
for t in range(tile_size-2):
|
||||
lines.append(''.join([tiles[col][t+1][1:-1] for col in rows]))
|
||||
return lines
|
||||
|
||||
|
||||
def build_image(tiles, corners, border_tiles, inner):
|
||||
corner_keys = list(corners.keys())
|
||||
first_corner_key = corner_keys[0]
|
||||
first_corner_tile = tiles[first_corner_key]
|
||||
first_corner_borders = corners[first_corner_key]
|
||||
del corners[first_corner_key]
|
||||
|
||||
first_corner_tile = orientation_corner_top_left(first_corner_tile, first_corner_borders)
|
||||
tiles[first_corner_key] = first_corner_tile
|
||||
|
||||
top_tiles = build_top_from_left(tiles, first_corner_key, border_tiles, corners)
|
||||
|
||||
width = len(top_tiles)
|
||||
height = len(tiles) // width
|
||||
|
||||
remaining = set(tiles.keys()).difference(set(top_tiles))
|
||||
|
||||
image_tiles = [top_tiles]
|
||||
|
||||
for h in range(height-1):
|
||||
row = []
|
||||
for w in range(width):
|
||||
cur_above_key = image_tiles[h][w]
|
||||
cur_above = tiles[cur_above_key]
|
||||
bottom_border = get_bottom_border(cur_above)
|
||||
|
||||
key = find_tile_for_bottom_border(tiles, bottom_border, remaining)
|
||||
remaining.remove(key)
|
||||
row.append(key)
|
||||
|
||||
image_tiles.append(row)
|
||||
|
||||
image = build_image_from(tiles, image_tiles)
|
||||
# image = flip_left_to_right_image(image)
|
||||
# image = rotate_right(rotate_right(rotate_right(image)))
|
||||
#
|
||||
# for i in image:
|
||||
# print(i)
|
||||
return image
|
||||
|
||||
|
||||
sea_monster = [' # ',
|
||||
'# ## ## ###',
|
||||
' # # # # # # ']
|
||||
|
||||
def sea_monster_as_offset():
|
||||
global sea_monster
|
||||
sea_monster_offset = []
|
||||
for row in range(len(sea_monster)):
|
||||
for col in range(len(sea_monster[row])):
|
||||
if sea_monster[row][col] == '#':
|
||||
sea_monster_offset.append((row, col))
|
||||
return sea_monster_offset
|
||||
|
||||
|
||||
def find_sea_monster(image, sea_monster_offsets):
|
||||
rows = len(image)
|
||||
cols = len(image[0])
|
||||
sm_rows = len(sea_monster)
|
||||
sm_cols = len(sea_monster[0])
|
||||
for row in range(rows - sm_rows):
|
||||
for col in range(cols - sm_cols):
|
||||
if all([image[row + offset[0]][col + offset[1]] in ('#', 'O') for offset in sea_monster_offsets]):
|
||||
for offset in sea_monster_offsets:
|
||||
# image[row + offset[0]][col + offset[1]] = 'O'
|
||||
temp = list(image[row + offset[0]])
|
||||
temp[col + offset[1]] = '0'
|
||||
image[row + offset[0]] = ''.join(temp)
|
||||
return image
|
||||
|
||||
|
||||
def check_all_orientations_for_sm(image, sea_monster_offsets):
|
||||
for i in range(4):
|
||||
image = find_sea_monster(image, sea_monster_offsets)
|
||||
image = rotate_right(image)
|
||||
image = flip_left_to_right_image(image)
|
||||
for i in range(4):
|
||||
image = find_sea_monster(image, sea_monster_offsets)
|
||||
image = rotate_right(image)
|
||||
return image
|
||||
|
||||
|
||||
tiles = read_tiles()
|
||||
|
||||
corners, borders, inner = find_corners(tiles)
|
||||
|
||||
res = reduce(lambda x, y: x * y, [key for key in corners.keys()])
|
||||
|
||||
print(res)
|
||||
|
||||
image = build_image(tiles, corners, borders, inner)
|
||||
sea_monster_offsets = sea_monster_as_offset()
|
||||
|
||||
image = check_all_orientations_for_sm(image, sea_monster_offsets)
|
||||
|
||||
res = 0
|
||||
for line in image:
|
||||
res += sum([c == '#' for c in line])
|
||||
|
||||
print(res)
|
||||
Loading…
Reference in New Issue