You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.2 KiB
130 lines
4.2 KiB
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
import numpy as np
|
|
#import matplotlib.pyplot as plt
|
|
|
|
def toBits(l): return sum(int(b=='#') * (2**i) for i,b in enumerate(l))
|
|
def allSides(tile):
|
|
a,b,c,d = tile[0, : ], tile[-1, : ], tile[:, 0], tile[:, -1]
|
|
e,f,g,h = tile[0, ::-1], tile[-1, ::-1], tile[::-1, 0], tile[::-1, -1]
|
|
return [a,b,c,d,e,f,g,h]
|
|
|
|
def comb(tile):
|
|
return [tile,
|
|
np.fliplr(tile),
|
|
np.rot90(tile),
|
|
np.rot90(np.rot90(tile)),
|
|
np.rot90(np.rot90(np.rot90(tile))),
|
|
np.fliplr(np.rot90(tile)),
|
|
np.fliplr(np.rot90(np.rot90(tile))),
|
|
np.fliplr(np.rot90(np.rot90(np.rot90(tile))))]
|
|
|
|
def getRight(tile): return toBits(tile[:,-1])
|
|
def getLeft(tile): return toBits(tile[:,0])
|
|
def getBot(tile): return toBits(tile[-1,:])
|
|
def getTop(tile): return toBits(tile[0,:])
|
|
|
|
def matchRight(tile1, tile2):
|
|
for t in comb(tile2):
|
|
if getRight(tile1) == getLeft(t): return t
|
|
def matchBot(tile1, tile2):
|
|
for t in comb(tile2):
|
|
if getBot(tile1) == getTop(t): return t
|
|
|
|
def parse_data(strings):
|
|
tiles = {}
|
|
for tile in strings:
|
|
tid, *data = tile.split('\n')
|
|
try: tid = tid.rstrip(':').split(' ')[1]
|
|
except IndexError: continue
|
|
grid = [[c for c in line] for line in data if len(line) >= 1]
|
|
tiles[int(tid)] = np.array(grid)
|
|
return tiles
|
|
|
|
def get_sides(tiles):
|
|
sides = {}
|
|
for tid, tile in tiles.items():
|
|
for bits in map(lambda x: toBits(x), allSides(tile)):
|
|
if bits not in sides: sides[bits] = []
|
|
sides[bits].append(tid)
|
|
return sides
|
|
|
|
def get_corners(tiles, sides):
|
|
singles = {}
|
|
for bits, xs in sides.items():
|
|
if len(xs) == 1: singles[xs[0]] = []
|
|
for sid in singles.keys():
|
|
matches = [x for side in allSides(tiles[sid]) for x in sides[toBits(side)]]
|
|
singles[sid] = list(dict.fromkeys(matches))
|
|
corners = []
|
|
for sid, single in singles.items():
|
|
if len(single) < 4: corners.append(sid)
|
|
return corners
|
|
|
|
def build_picture(tiles, sides, start):
|
|
picture = [[None for x in range(12)] for x in range(12)]
|
|
matches = [x for side in allSides(tiles[corner]) for x in sides[toBits(side)]]
|
|
matches = list(dict.fromkeys(matches))
|
|
matches.remove(corner)
|
|
for t in comb(tiles[corner]):
|
|
x, y = map(lambda v: tiles[v], matches)
|
|
if matchRight(t,x) is not None and matchBot(t,y) is not None: break
|
|
if matchRight(t,y) is not None and matchBot(t,x) is not None: break
|
|
else: tiles[corner] = t
|
|
picture[0][0] = corner
|
|
|
|
for i, p in enumerate(picture[0]):
|
|
s = sides[getRight(tiles[p])]
|
|
s.remove(p)
|
|
if len(s) > 0:
|
|
tiles[s[0]] = matchRight(tiles[p], tiles[s[0]])
|
|
picture[0][i+1] = s[0]
|
|
for j in range(1, len(picture)):
|
|
z = sides[getBot(tiles[p])]
|
|
z.remove(p)
|
|
if len(z) > 0:
|
|
tiles[z[0]] = matchBot(tiles[p], tiles[z[0]])
|
|
picture[j][i] = z[0]
|
|
p = z[0]
|
|
|
|
return picture
|
|
|
|
def countSM(pic, sm):
|
|
count = 0
|
|
y, x = pic.shape
|
|
ys, xs = sm.shape
|
|
for i in range(0, y-ys):
|
|
for j in range(0, x-xs):
|
|
if np.all(pic[i:i+ys,j:j+xs] | sm):
|
|
count += 1
|
|
return count
|
|
|
|
if __name__ == '__main__':
|
|
tiles = parse_data(open(sys.argv[1]).read().split('\n\n'))
|
|
sides = get_sides(tiles)
|
|
|
|
corner = get_corners(tiles, sides)[0]
|
|
p = build_picture(tiles, sides, corner)
|
|
print(p[0][0] * p[0][-1] * p[-1][0] * p[-1][-1])
|
|
|
|
pic = np.concatenate(tuple(np.concatenate(tuple(tiles[x][1:-1,1:-1] for x in r), axis=1) for r in p), axis=0)
|
|
grayscale = np.vectorize(lambda x: np.int8(x == "#"))(pic)
|
|
print(grayscale)
|
|
|
|
snake = \
|
|
[ " # "
|
|
, "# ## ## ###"
|
|
, " # # # # # # "
|
|
]
|
|
|
|
sneasnake = np.array([[c for c in line] for line in snake])
|
|
sneasnake = np.vectorize(lambda x: np.int8(x != "#"))(sneasnake)
|
|
|
|
for p in comb(grayscale):
|
|
print(countSM(p, sneasnake))
|
|
print(np.count_nonzero(grayscale) - 26 * 15)
|
|
|
|
# plt.show()
|
|
# plt.imshow(grayscale)
|
|
# plt.savefig("test.png")
|
|
|