소스 검색

2020/20v1

master
Roderic Day 4 년 전
부모
커밋
ef75dca8ea
1개의 변경된 파일132개의 추가작업 그리고 0개의 파일을 삭제
  1. +132
    -0
      y2020/p20.py

+ 132
- 0
y2020/p20.py 파일 보기

@@ -0,0 +1,132 @@
# flake8: noqa
import re
import collections
import itertools
import sys
import math

import toolkit


def apply(cell):
key, *fns = cell
string = tiles[key]
for fn in fns:
if fn is not None:
string = fn(string)
return string


def apply2(string, fns):
for fn in fns:
if fn is not None:
string = fn(string)
return string


def render(grid):
return '\n'.join(
'\n'.join(''.join([n[1:-1]
for n in ln])
for ln in zip(*[apply(cell).splitlines()[1:-1] for cell in row]))
for row in grid
)


def get_borders(content):
a, *_, b = content.splitlines()
c, *_, d = [''.join(ln) for ln in zip(*content.splitlines())]
return [a, b, c, d, a[::-1], b[::-1], c[::-1], d[::-1]]


def flipV(string):
return '\n'.join(ln for ln in string.splitlines()[::-1])


def flipH(string):
return '\n'.join(ln[::-1] for ln in string.splitlines())


def rot90(n):
def inner(string):
return toolkit.render({k * 1j ** n: v for k, v in toolkit.read_image(string)[0].items()})
return inner


text = sys.stdin.read().strip()
tiles = {}
borders = {}
for line in text.split('\n\n'):
title, content = line.split(':\n')
tid = int(title.split()[1])
tiles[tid] = content
borders[tid] = get_borders(content)


size = int(len(borders) ** 0.5)


adj = collections.defaultdict(set)
for (aid, A), (bid, B) in itertools.combinations(borders.items(), 2):
if set(A) & set(B):
adj[aid].add(bid)
adj[bid].add(aid)

corn = [v for v, ks in adj.items() if len(ks) == 2]

gids = [[None for _ in range(size)] for _ in range(size)]

gids[0][0] = corn[0]
gids[1][0], gids[0][1] = adj[gids[0][0]]
gids[1][1], = adj[gids[1][0]] & adj[gids[0][1]] - {gids[0][0]}

for x in range(2, size):
gids[0][x], = adj[gids[0][x - 1]] - {gids[0][x - 2], gids[1][x - 1]}
gids[1][x], = adj[gids[0][x]] & adj[gids[1][x - 1]] - {gids[0][x - 1]}

for y in range(2, size):
gids[y][0], = adj[gids[y - 1][0]] - {gids[y - 2][0], gids[y - 1][1]}
for x in range(1, size):
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)]))

for x in range(1, size):
goal = [ln[-1] for ln in apply(grid[0][x - 1]).splitlines()]
for chain in options:
if goal == [ln[0] for ln in apply(grid[0][x] + chain).splitlines()]:
grid[0][x] += chain
break

for y in range(1, size):
for x in range(size):
goal = apply(grid[y - 1][x]).splitlines()[-1]
for chain in options:
if goal == apply(grid[y][x] + chain).splitlines()[0]:
grid[y][x] += chain
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('#'))

Loading…
취소
저장