Browse Source

2020/20

master
Roderic Day 4 years ago
parent
commit
97e242d4ff
1 changed files with 45 additions and 39 deletions
  1. +45
    -39
      y2020/p20.py

+ 45
- 39
y2020/p20.py View File

# flake8: noqa
import re
import collections import collections
import functools
import itertools import itertools
import sys
import math import math
from functools import reduce
import re
import sys




def render(grid): def render(grid):
return '\n'.join(
'\n'.join(''.join([n[1:-1] for n in ln])
for ln in zip(*[grid[y, x].splitlines()[1:-1] for x in range(size)]))
for y in range(size)
)
lines = []
for y in range(size):
groups = [tiles[grid[y, x]].splitlines()[1:-1] for x in range(size)]
for lns in zip(*groups):
lines.append(''.join(ln[1:-1] for ln in lns))
return '\n'.join(lines)



def get_borders(content): def get_borders(content):
a, *_, b = content.splitlines() a, *_, b = content.splitlines()
def variants(string): def variants(string):
alts = [noop, flipH], [noop, flipV], [noop, transpose] alts = [noop, flipH], [noop, flipV], [noop, transpose]
for ops in itertools.product(*alts): for ops in itertools.product(*alts):
yield reduce(lambda s, f: f(s), ops, string)
yield functools.reduce(lambda s, f: f(s), ops, string)




def UD(A, B): def UD(A, B):
return out return out




def reconcile(A, B, condition):
tiles[A], tiles[B] = next(
(X, Y)
for X, Y in itertools.product(variants(tiles[A]), variants(tiles[B]))
if condition(X, Y)
)


text = sys.stdin.read().strip() text = sys.stdin.read().strip()
tiles = {} tiles = {}
borders = {} borders = {}
print(math.prod(corners)) print(math.prod(corners))




gids = {}
for y in range(size):
for x in range(size):
if (y, x) == (0, 0):
gids[y, x] = corners[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 = {(y, x): tiles[gids[y, x]] for x in range(size) for y in range(size)}
grid[0, 0] = flipV(grid[0, 0])
for y in range(size):
for x in range(size):
if (x, y) != (0, 0):
grid[y, x], = (
pic for pic in variants(grid[y, x])
if ((y - 1, x) not in grid or UD(grid[y - 1, x], pic))
and ((y, x - 1) not in grid or LR(grid[y, x - 1], pic))
)

A = min(corners)
B, C = adj.pop(A)

grid = {(y, x): None for x in range(size) for y in range(size)}
grid[0, 0] = A
grid[0, 1] = B
grid[1, 0] = C
reconcile(A, B, condition=LR)
reconcile(A, C, condition=UD)

seen = {A, B, C}
for z in range(2, 2 * size - 1):
# determine new pieces from intersection between 2 neighbors
for y, x in {(y, z - y) for y in range(1, z)}.intersection(grid):
U, L = (y - 1, x), (y, x - 1)
grid[y, x], = adj[grid[U]] & adj[grid[L]] - seen
reconcile(grid[L], grid[y, x], condition=LR)
seen.add(grid[y, x])

# determine new piece from only one alternative left
for y, x in {(0, z), (z, 0)}.intersection(grid):
opts = {(y - 1, x): UD, (y, x - 1): LR}
P, fn = next(p for p in opts.items() if p[0] in grid)
grid[y, x], = adj[grid[P]] - seen
reconcile(grid[P], grid[y, x], condition=fn)
seen.add(grid[y, x])


monster = ''' monster = '''
..................#. ..................#.

Loading…
Cancel
Save