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