|
|
|
|
|
|
|
|
import itertools |
|
|
import itertools |
|
|
import sys |
|
|
import sys |
|
|
import math |
|
|
import math |
|
|
|
|
|
from functools import reduce |
|
|
|
|
|
|
|
|
import toolkit |
|
|
import toolkit |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def apply(cell): |
|
|
def apply(cell): |
|
|
key, *fns = cell |
|
|
|
|
|
string = tiles[key] |
|
|
|
|
|
|
|
|
string, *fns = cell |
|
|
for fn in fns: |
|
|
for fn in fns: |
|
|
if fn is not None: |
|
|
if fn is not None: |
|
|
string = fn(string) |
|
|
string = fn(string) |
|
|
|
|
|
|
|
|
return '\n'.join( |
|
|
return '\n'.join( |
|
|
'\n'.join(''.join([n[1:-1] |
|
|
'\n'.join(''.join([n[1:-1] |
|
|
for n in ln]) |
|
|
for n in ln]) |
|
|
for ln in zip(*[apply(cell).splitlines()[1:-1] for cell in row])) |
|
|
|
|
|
for row in grid |
|
|
|
|
|
|
|
|
for ln in zip(*[apply(grid[y, x]).splitlines()[1:-1] for x in range(size)])) |
|
|
|
|
|
for y in range(size) |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return inner |
|
|
return inner |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def noop(string): |
|
|
|
|
|
return string |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def variants(string): |
|
|
|
|
|
alts = [noop, flipH], [noop, flipV], [noop, rot90(1), rot90(2), rot90(3)] |
|
|
|
|
|
for ops in itertools.product(*alts): |
|
|
|
|
|
yield reduce(lambda s, f: f(s), ops, string), ops |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search_in(source, target): |
|
|
|
|
|
source_lns = source.splitlines() |
|
|
|
|
|
target_lns = target.splitlines() |
|
|
|
|
|
h, w = len(target_lns), len(target_lns[0]) |
|
|
|
|
|
out = [] |
|
|
|
|
|
for y in range(len(source_lns)): |
|
|
|
|
|
for x in range(len(source_lns[0])): |
|
|
|
|
|
window = '\n'.join(ln[x:x + w] for ln in source_lns[y:y + h]) |
|
|
|
|
|
if re.fullmatch(target, window): |
|
|
|
|
|
out.append((x, y)) |
|
|
|
|
|
return out |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
text = sys.stdin.read().strip() |
|
|
text = sys.stdin.read().strip() |
|
|
tiles = {} |
|
|
tiles = {} |
|
|
borders = {} |
|
|
borders = {} |
|
|
|
|
|
|
|
|
tid = int(title.split()[1]) |
|
|
tid = int(title.split()[1]) |
|
|
tiles[tid] = content |
|
|
tiles[tid] = content |
|
|
borders[tid] = get_borders(content) |
|
|
borders[tid] = get_borders(content) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size = int(len(borders) ** 0.5) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size = int(len(tiles) ** 0.5) |
|
|
|
|
|
|
|
|
adj = collections.defaultdict(set) |
|
|
adj = collections.defaultdict(set) |
|
|
for (aid, A), (bid, B) in itertools.combinations(borders.items(), 2): |
|
|
for (aid, A), (bid, B) in itertools.combinations(borders.items(), 2): |
|
|
if set(A) & set(B): |
|
|
if set(A) & set(B): |
|
|
adj[aid].add(bid) |
|
|
adj[aid].add(bid) |
|
|
adj[bid].add(aid) |
|
|
adj[bid].add(aid) |
|
|
|
|
|
|
|
|
corn = [v for v, ks in adj.items() if len(ks) == 2] |
|
|
corn = [v for v, ks in adj.items() if len(ks) == 2] |
|
|
|
|
|
print(math.prod(corn)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gids = [[None for _ in range(size)] for _ in range(size)] |
|
|
gids = [[None for _ in range(size)] for _ in range(size)] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gids[y][x], = adj[gids[y][x - 1]] & adj[gids[y - 1][x]] - {gids[y - 1][x - 1]} |
|
|
gids[y][x], = adj[gids[y][x - 1]] & adj[gids[y - 1][x]] - {gids[y - 1][x - 1]} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid = [[(gids[y][x],) for x in range(size)] for y in range(size)] |
|
|
|
|
|
grid[0][0] += (flipV,) |
|
|
|
|
|
|
|
|
|
|
|
options = list(itertools.product([None, flipH], [None, flipV], [None] + [rot90(n) for n in range(3)])) |
|
|
options = list(itertools.product([None, flipH], [None, flipV], [None] + [rot90(n) for n in range(3)])) |
|
|
|
|
|
|
|
|
|
|
|
grid = {(y, x): (tiles[gids[y][x]],) for x in range(size) for y in range(size)} |
|
|
|
|
|
grid[0, 0] = (flipV(grid[0, 0][0]),) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for x in range(1, size): |
|
|
for x in range(1, size): |
|
|
goal = [ln[-1] for ln in apply(grid[0][x - 1]).splitlines()] |
|
|
|
|
|
|
|
|
goal = [ln[-1] for ln in apply(grid[0, x - 1]).splitlines()] |
|
|
for chain in options: |
|
|
for chain in options: |
|
|
if goal == [ln[0] for ln in apply(grid[0][x] + chain).splitlines()]: |
|
|
|
|
|
grid[0][x] += chain |
|
|
|
|
|
|
|
|
if goal == [ln[0] for ln in apply(grid[0, x] + chain).splitlines()]: |
|
|
|
|
|
grid[0, x] += chain |
|
|
break |
|
|
break |
|
|
|
|
|
|
|
|
for y in range(1, size): |
|
|
for y in range(1, size): |
|
|
for x in range(size): |
|
|
for x in range(size): |
|
|
goal = apply(grid[y - 1][x]).splitlines()[-1] |
|
|
|
|
|
|
|
|
goal = apply(grid[y - 1, x]).splitlines()[-1] |
|
|
for chain in options: |
|
|
for chain in options: |
|
|
if goal == apply(grid[y][x] + chain).splitlines()[0]: |
|
|
|
|
|
grid[y][x] += chain |
|
|
|
|
|
|
|
|
if goal == apply(grid[y, x] + chain).splitlines()[0]: |
|
|
|
|
|
grid[y, x] += chain |
|
|
break |
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
monster = ''' # |
|
|
|
|
|
# ## ## ### |
|
|
|
|
|
# # # # # # ''' |
|
|
|
|
|
kuk, W, H = toolkit.read_image(monster) |
|
|
|
|
|
goal = re.compile(toolkit.render(kuk).replace('\n', '').replace(' ', '.')) |
|
|
|
|
|
|
|
|
|
|
|
cnt = 0 |
|
|
|
|
|
for chain in options: |
|
|
|
|
|
grody = apply2(render(grid), chain) |
|
|
|
|
|
grok = [list(line) for line in grody.splitlines()] |
|
|
|
|
|
for y in range(len(grok) - H): |
|
|
|
|
|
for x in range(len(grok[0]) - W): |
|
|
|
|
|
sample = ''.join(''.join(grok[y + dy][x + dx] for dx in range(W)) for dy in range(H)) |
|
|
|
|
|
cnt += bool(goal.fullmatch(sample)) |
|
|
|
|
|
if cnt: |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
print(grody) |
|
|
|
|
|
print(grody.count('#') - cnt * monster.count('#')) |
|
|
|
|
|
|
|
|
monster = ''' |
|
|
|
|
|
..................#. |
|
|
|
|
|
#....##....##....### |
|
|
|
|
|
.#..#..#..#..#..#... |
|
|
|
|
|
'''[1:-1] |
|
|
|
|
|
src = render(grid) |
|
|
|
|
|
found = max([search_in(pic, monster) for pic, _ in variants(src)], key=len) |
|
|
|
|
|
print(src.count('#') - len(found) * monster.count('#')) |