選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

p20.py 3.3KB

5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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('#'))