您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

133 行
3.4KB

  1. # flake8: noqa
  2. import re
  3. import collections
  4. import itertools
  5. import sys
  6. import math
  7. import toolkit
  8. def apply(cell):
  9. key, *fns = cell
  10. string = tiles[key]
  11. for fn in fns:
  12. if fn is not None:
  13. string = fn(string)
  14. return string
  15. def apply2(string, fns):
  16. for fn in fns:
  17. if fn is not None:
  18. string = fn(string)
  19. return string
  20. def render(grid):
  21. return '\n'.join(
  22. '\n'.join(''.join([n[1:-1]
  23. for n in ln])
  24. for ln in zip(*[apply(cell).splitlines()[1:-1] for cell in row]))
  25. for row in grid
  26. )
  27. def get_borders(content):
  28. a, *_, b = content.splitlines()
  29. c, *_, d = [''.join(ln) for ln in zip(*content.splitlines())]
  30. return [a, b, c, d, a[::-1], b[::-1], c[::-1], d[::-1]]
  31. def flipV(string):
  32. return '\n'.join(ln for ln in string.splitlines()[::-1])
  33. def flipH(string):
  34. return '\n'.join(ln[::-1] for ln in string.splitlines())
  35. def rot90(n):
  36. def inner(string):
  37. return toolkit.render({k * 1j ** n: v for k, v in toolkit.read_image(string)[0].items()})
  38. return inner
  39. text = sys.stdin.read().strip()
  40. tiles = {}
  41. borders = {}
  42. for line in text.split('\n\n'):
  43. title, content = line.split(':\n')
  44. tid = int(title.split()[1])
  45. tiles[tid] = content
  46. borders[tid] = get_borders(content)
  47. size = int(len(borders) ** 0.5)
  48. adj = collections.defaultdict(set)
  49. for (aid, A), (bid, B) in itertools.combinations(borders.items(), 2):
  50. if set(A) & set(B):
  51. adj[aid].add(bid)
  52. adj[bid].add(aid)
  53. corn = [v for v, ks in adj.items() if len(ks) == 2]
  54. gids = [[None for _ in range(size)] for _ in range(size)]
  55. gids[0][0] = corn[0]
  56. gids[1][0], gids[0][1] = adj[gids[0][0]]
  57. gids[1][1], = adj[gids[1][0]] & adj[gids[0][1]] - {gids[0][0]}
  58. for x in range(2, size):
  59. gids[0][x], = adj[gids[0][x - 1]] - {gids[0][x - 2], gids[1][x - 1]}
  60. gids[1][x], = adj[gids[0][x]] & adj[gids[1][x - 1]] - {gids[0][x - 1]}
  61. for y in range(2, size):
  62. gids[y][0], = adj[gids[y - 1][0]] - {gids[y - 2][0], gids[y - 1][1]}
  63. for x in range(1, size):
  64. gids[y][x], = adj[gids[y][x - 1]] & adj[gids[y - 1][x]] - {gids[y - 1][x - 1]}
  65. grid = [[(gids[y][x],) for x in range(size)] for y in range(size)]
  66. grid[0][0] += (flipV,)
  67. options = list(itertools.product([None, flipH], [None, flipV], [None] + [rot90(n) for n in range(3)]))
  68. for x in range(1, size):
  69. goal = [ln[-1] for ln in apply(grid[0][x - 1]).splitlines()]
  70. for chain in options:
  71. if goal == [ln[0] for ln in apply(grid[0][x] + chain).splitlines()]:
  72. grid[0][x] += chain
  73. break
  74. for y in range(1, size):
  75. for x in range(size):
  76. goal = apply(grid[y - 1][x]).splitlines()[-1]
  77. for chain in options:
  78. if goal == apply(grid[y][x] + chain).splitlines()[0]:
  79. grid[y][x] += chain
  80. break
  81. monster = ''' #
  82. # ## ## ###
  83. # # # # # # '''
  84. kuk, W, H = toolkit.read_image(monster)
  85. goal = re.compile(toolkit.render(kuk).replace('\n', '').replace(' ', '.'))
  86. cnt = 0
  87. for chain in options:
  88. grody = apply2(render(grid), chain)
  89. grok = [list(line) for line in grody.splitlines()]
  90. for y in range(len(grok) - H):
  91. for x in range(len(grok[0]) - W):
  92. sample = ''.join(''.join(grok[y + dy][x + dx] for dx in range(W)) for dy in range(H))
  93. cnt += bool(goal.fullmatch(sample))
  94. if cnt:
  95. break
  96. print(grody)
  97. print(grody.count('#') - cnt * monster.count('#'))