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

127 行
3.3KB

  1. # flake8: noqa
  2. import re
  3. import collections
  4. import itertools
  5. import sys
  6. import math
  7. from functools import reduce
  8. def render(grid):
  9. return '\n'.join(
  10. '\n'.join(''.join([n[1:-1] for n in ln])
  11. for ln in zip(*[grid[y, x].splitlines()[1:-1] for x in range(size)]))
  12. for y in range(size)
  13. )
  14. def get_borders(content):
  15. a, *_, b = content.splitlines()
  16. c, *_, d = [''.join(ln) for ln in zip(*content.splitlines())]
  17. return [a, b, c, d, a[::-1], b[::-1], c[::-1], d[::-1]]
  18. def transpose(string):
  19. return '\n'.join(''.join(ln) for ln in zip(*string.splitlines()))
  20. def flipV(string):
  21. return '\n'.join(ln for ln in string.splitlines()[::-1])
  22. def flipH(string):
  23. return '\n'.join(ln[::-1] for ln in string.splitlines())
  24. def rot90(string):
  25. return flipH(transpose(string))
  26. def noop(string):
  27. return string
  28. def variants(string):
  29. alts = [noop, flipH], [noop, flipV], [noop, transpose]
  30. for ops in itertools.product(*alts):
  31. yield reduce(lambda s, f: f(s), ops, string)
  32. def UD(A, B):
  33. return A.splitlines()[-1] == B.splitlines()[0]
  34. def LR(A, B):
  35. return UD(rot90(A), rot90(B))
  36. def search_in(source, target):
  37. source_lns = source.splitlines()
  38. target_lns = target.splitlines()
  39. h, w = len(target_lns), len(target_lns[0])
  40. out = []
  41. for y in range(len(source_lns)):
  42. for x in range(len(source_lns[0])):
  43. window = '\n'.join(ln[x:x + w] for ln in source_lns[y:y + h])
  44. if re.fullmatch(target, window):
  45. out.append((x, y))
  46. return out
  47. text = sys.stdin.read().strip()
  48. tiles = {}
  49. borders = {}
  50. for line in text.split('\n\n'):
  51. title, content = line.split(':\n')
  52. tid = int(title.split()[1])
  53. tiles[tid] = content
  54. borders[tid] = get_borders(content)
  55. size = int(len(tiles) ** 0.5)
  56. adj = collections.defaultdict(set)
  57. for (aid, A), (bid, B) in itertools.combinations(borders.items(), 2):
  58. if set(A) & set(B):
  59. adj[aid].add(bid)
  60. adj[bid].add(aid)
  61. corners = [v for v, ks in adj.items() if len(ks) == 2]
  62. print(math.prod(corners))
  63. gids = {}
  64. for y in range(size):
  65. for x in range(size):
  66. if (y, x) == (0, 0):
  67. gids[y, x] = corners[0]
  68. gids[1, 0], gids[0, 1] = adj[gids[0, 0]]
  69. gids[1, 1], = adj[gids[1, 0]] & adj[gids[0, 1]] - {gids[0, 0]}
  70. for x in range(2, size):
  71. gids[0, x], = adj[gids[0, x - 1]] - {gids[0, x - 2], gids[1, x - 1]}
  72. gids[1, x], = adj[gids[0, x]] & adj[gids[1, x - 1]] - {gids[0, x - 1]}
  73. for y in range(2, size):
  74. gids[y, 0], = adj[gids[y - 1, 0]] - {gids[y - 2, 0], gids[y - 1, 1]}
  75. for x in range(1, size):
  76. gids[y, x], = adj[gids[y, x - 1]] & adj[gids[y - 1, x]] - {gids[y - 1, x - 1]}
  77. grid = {(y, x): tiles[gids[y, x]] for x in range(size) for y in range(size)}
  78. grid[0, 0] = flipV(grid[0, 0])
  79. for y in range(size):
  80. for x in range(size):
  81. if (x, y) != (0, 0):
  82. grid[y, x], = (
  83. pic for pic in variants(grid[y, x])
  84. if ((y - 1, x) not in grid or UD(grid[y - 1, x], pic))
  85. and ((y, x - 1) not in grid or LR(grid[y, x - 1], pic))
  86. )
  87. monster = '''
  88. ..................#.
  89. #....##....##....###
  90. .#..#..#..#..#..#...
  91. '''[1:-1]
  92. src = render(grid)
  93. found = max([search_in(pic, monster) for pic in variants(src)], key=len)
  94. print(src.count('#') - len(found) * monster.count('#'))