Skip to content

Instantly share code, notes, and snippets.

@sciyoshi
Last active February 15, 2021 04:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sciyoshi/4a297cd965baad369f5f544029a10dbc to your computer and use it in GitHub Desktop.
Save sciyoshi/4a297cd965baad369f5f544029a10dbc to your computer and use it in GitHub Desktop.
import functools
import operator
import itertools
import networkx
import numpy as np
tiles = {}
for tiledata in open("inputs/day20").read().strip().split("\n\n"):
a, *tilelines = tiledata.splitlines()
num = int(a.strip(":").split()[1])
tiles[num] = np.array([[c == "#" for c in l] for l in tilelines], dtype=np.uint8)
def nptobin(s):
return int("".join([str(k) for k in s]), 2)
def get_borders(n):
return [nptobin(n[0]), nptobin(n[:, -1]), nptobin(n[-1]), nptobin(n[:, 0])]
def get_flips(tile):
res = tile
for f in [True, False]:
for i in range(4):
yield res
res = np.rot90(res)
res = np.flip(tile, 1)
borders = {}
for n, tile in tiles.items():
borders[n] = set.union(*[set(get_borders(fl)) for fl in get_flips(tile)])
grph = networkx.Graph()
for i, j in itertools.combinations(borders, 2):
if len(borders[i] & borders[j]) == 2:
grph.add_edge(i, j)
corners = [n for n in grph if len(grph[n]) == 2]
print("part1:", functools.reduce(operator.mul, corners))
def ext(pt):
used = set(tile for tile, _ in grd.values())
tile, img = grd[pt]
border = get_borders(img)
for nb in grph[tile]:
if nb not in used:
for fl in get_flips(tiles[nb]):
if get_borders(fl)[0] == border[2]:
grd[(pt[0] + 1, pt[1])] = (nb, fl)
if get_borders(fl)[3] == border[1]:
grd[(pt[0], pt[1] + 1)] = (nb, fl)
for fl in get_flips(tiles[corners[0]]):
grd = {}
grd[(0, 0)] = (corners[0], fl)
ext((0, 0))
if len(grd) == 3:
break
for i in range(12):
for j in range(12):
ext((i, j))
image = np.concatenate([np.concatenate([grd[i, j][1][1:-1, 1:-1] for j in range(12)], axis=1) for i in range(12)], axis=0)
monster_str = (
" # \n"
"# ## ## ###\n"
" # # # # # # ".splitlines()
)
monster = np.array([[c == "#" for c in l] for l in monster_str], dtype=np.uint8)
for image in get_flips(image):
count = 0
for i in range(image.shape[0] - monster.shape[0] + 1):
for j in range(image.shape[1] - monster.shape[1] + 1):
check = image[i : i + monster.shape[0], j : j + monster.shape[1]]
if (check & monster == monster).all():
count += 1
if count:
break
print("part 2:", int(np.sum(image) - count * np.sum(monster)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment