python(day20): Do day 20
This commit is contained in:
parent
cc5bbc7260
commit
81caf181b2
|
@ -8,3 +8,4 @@ c64/tests/
|
|||
inputs/
|
||||
|
||||
.vim/
|
||||
.vscode
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
import fileinput
|
||||
from pprint import pprint
|
||||
import itertools
|
||||
from copy import deepcopy
|
||||
|
||||
N = 10
|
||||
|
||||
#
|
||||
# Parse the input
|
||||
#
|
||||
current_tile = None
|
||||
tiles = []
|
||||
for line in fileinput.input():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
if line.startswith("Tile "):
|
||||
if current_tile:
|
||||
assert len(current_tile) == N
|
||||
tiles.append((current_id, current_tile))
|
||||
current_id = int(line[5:-1])
|
||||
current_tile = []
|
||||
else:
|
||||
assert len(line) == N
|
||||
current_tile.append(list(line))
|
||||
|
||||
assert len(current_tile) == N
|
||||
tiles.append((current_id, current_tile))
|
||||
|
||||
|
||||
def aligns_right(left, right):
|
||||
return all(left[y][-1] == right[y][0] for y in range(len(left)))
|
||||
|
||||
|
||||
def aligns_bottom(top, bottom):
|
||||
return all(top[-1][x] == bottom[0][x] for x in range(len(top)))
|
||||
|
||||
|
||||
def aligns(apos, b):
|
||||
ax, ay = apos
|
||||
_, a = kek[(ax, ay)]
|
||||
if aligns_right(a, b):
|
||||
return 1, 0
|
||||
if aligns_right(b, a):
|
||||
return -1, 0
|
||||
if aligns_bottom(a, b):
|
||||
return 0, 1
|
||||
if aligns_bottom(b, a):
|
||||
return 0, -1
|
||||
return None
|
||||
|
||||
|
||||
def rotate(a):
|
||||
output = deepcopy(a)
|
||||
for y in range(len(a)):
|
||||
for x in range(len(a)):
|
||||
output[-1 - x][y] = a[y][x]
|
||||
return output
|
||||
|
||||
|
||||
def flip(a):
|
||||
output = [None] * len(a)
|
||||
for y in range(len(a)):
|
||||
output[y] = list(reversed(a[y]))
|
||||
return output
|
||||
|
||||
|
||||
def rotate_align(a_pos, b):
|
||||
"""
|
||||
Rotates and flips a and checks if it aligns for every possible orientation.
|
||||
"""
|
||||
if d := aligns(a_pos, b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := aligns(a_pos, bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := aligns(a_pos, b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := aligns(a_pos, bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := aligns(a_pos, b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := aligns(a_pos, bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := aligns(a_pos, b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := aligns(a_pos, bf):
|
||||
return bf, d
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
positions = {tiles[0][0]: ((0, 0), tiles[0][1])}
|
||||
kek = {(0, 0): tiles[0]}
|
||||
|
||||
while len(positions) != len(tiles):
|
||||
for a_id, _ in tiles:
|
||||
((a_x, a_y), a_tile) = positions.get(a_id, ((None, None), None))
|
||||
if not a_tile:
|
||||
continue
|
||||
|
||||
for b_id, b_tile in tiles:
|
||||
if b_id in positions or a_id == b_id:
|
||||
continue
|
||||
|
||||
transformed, dpos = rotate_align((a_x, a_y), b_tile)
|
||||
if dpos is not None:
|
||||
dx, dy = dpos
|
||||
b_x = a_x + dx
|
||||
b_y = a_y + dy
|
||||
positions[b_id] = (b_x, b_y), transformed
|
||||
kek[(b_x, b_y)] = b_id, transformed
|
||||
|
||||
min_y = min(y for ((_, y), _) in positions.values())
|
||||
max_y = max(y for ((_, y), _) in positions.values())
|
||||
min_x = min(x for ((x, _), _) in positions.values())
|
||||
max_x = max(x for ((x, _), _) in positions.values())
|
||||
|
||||
tilemap = {pos: (id, tile) for id, (pos, tile) in positions.items()}
|
||||
bl, _ = tilemap[(min_x, min_y)]
|
||||
br, _ = tilemap[(max_x, min_y)]
|
||||
tl, _ = tilemap[(min_x, max_y)]
|
||||
tr, _ = tilemap[(max_x, max_y)]
|
||||
print("Part 1:", tl * tr * bl * br)
|
||||
|
||||
|
||||
def is_snek(b, x, y):
|
||||
for (x_, y_) in (
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(4, 1),
|
||||
(5, 0),
|
||||
(6, 0),
|
||||
(7, 1),
|
||||
(10, 1),
|
||||
(11, 0),
|
||||
(12, 0),
|
||||
(13, 1),
|
||||
(16, 1),
|
||||
(17, 0),
|
||||
(18, 0),
|
||||
(18, -1),
|
||||
(19, 0),
|
||||
):
|
||||
try:
|
||||
if b[y_ + y][x_ + x] == ".":
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def find_sneks(b):
|
||||
sneks = []
|
||||
for (x, y) in itertools.product(range(8 * 12), repeat=2):
|
||||
if is_snek(b, x, y):
|
||||
print(x, y, "is snek")
|
||||
sneks.append((x, y))
|
||||
return sneks
|
||||
|
||||
|
||||
def rotate_find_sneks(b):
|
||||
if d := find_sneks(b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := find_sneks(bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := find_sneks(b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := find_sneks(bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := find_sneks(b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := find_sneks(bf):
|
||||
return bf, d
|
||||
|
||||
b = rotate(b)
|
||||
if d := find_sneks(b):
|
||||
return b, d
|
||||
bf = flip(b)
|
||||
if d := find_sneks(bf):
|
||||
return bf, d
|
||||
|
||||
|
||||
def remove_snek(snek):
|
||||
# :(
|
||||
(x, y) = snek
|
||||
for (x_, y_) in (
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(4, 1),
|
||||
(5, 0),
|
||||
(6, 0),
|
||||
(7, 1),
|
||||
(10, 1),
|
||||
(11, 0),
|
||||
(12, 0),
|
||||
(13, 1),
|
||||
(16, 1),
|
||||
(17, 0),
|
||||
(18, 0),
|
||||
(18, -1),
|
||||
(19, 0),
|
||||
):
|
||||
big_chungus[y + y_][x + x_] = '.'
|
||||
|
||||
|
||||
chungus = [["."] * 8 * (max_x - min_x + 1) for _ in range(8 * (max_y - min_y + 1))]
|
||||
for (x, y), (id, tile) in tilemap.items():
|
||||
x_ = (x - min_x) * 8
|
||||
y_ = (y - min_y) * 8
|
||||
for i, row in enumerate(tile[1:-1]):
|
||||
for j, c in enumerate(row[1:-1]):
|
||||
chungus[i + y_][j + x_] = c
|
||||
|
||||
# for y, row in enumerate(chungus):
|
||||
# print("".join(row))
|
||||
|
||||
big_chungus, sneks = rotate_find_sneks(chungus)
|
||||
for snek in sneks:
|
||||
remove_snek(snek)
|
||||
|
||||
part2 = 0
|
||||
for row in big_chungus:
|
||||
for c in row:
|
||||
if c == "#":
|
||||
part2 += 1
|
||||
print("Part 2:", part2)
|
Loading…
Reference in New Issue