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.
 
 

101 lines
3.3 KiB

#!/usr/bin/env python3
import sys
import numpy as np
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
if __name__ == '__main__':
tilestrings = open(sys.argv[1]).read().split('\n\n')
tiles = {}
for tile in tilestrings:
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)
sides = {}
for tid, tile in tiles.items():
for x in allSides(tile):
bits = toBits(x)
if bits not in sides: sides[bits] = []
sides[bits].append(tid)
sides = {k:v for k,v in sorted(sides.items(), key=lambda i: len(i[1]))}
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))
prod = 1
corner = None
for sid, single in singles.items():
if len(single) < 4:
prod *= sid
corner = sid
picture = [[None for x in range(12)] for x in range(12)]
matches = list(dict.fromkeys([x for side in allSides(tiles[corner]) for x in sides[toBits(side)]]))
matches.remove(corner)
for t in comb(tiles[corner]):
x, y = matches
x, y = tiles[x], tiles[y]
if matchRight(t,x) is not None and matchBot(t,y) is not None:
tiles[corner] = t
break
if matchRight(t,y) is not None and matchBot(t,x) is not None:
tiles[corner] = t
break
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]
print(picture)
pic = [[None for x in range(12)] for x in range(12)]
for i in range(len(picture)):
for j in range(len(picture[0])):
pic[i][j] = tiles[picture[i][j]]
print(pic)