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

#!/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")