/ Python / 2017 / 21.py
21.py
 1  from lib import *
 2  
 3  input = read_input(2017, 21)
 4  
 5  lines = input.splitlines()
 6  
 7  
 8  def rotate(p):
 9      return tuple("".join(p[j][i] for j in range(len(p))) for i in reversed(range(len(p[0]))))
10  
11  
12  rules = {}
13  pattern = ".#.", "..#", "###"
14  for line in lines:
15      a, b = [tuple(k.split("/")) for k in line.split(" => ")]
16      rules[a] = b
17  
18  
19  def find_rule(p):
20      for _ in range(4):
21          if p in rules:
22              return rules[p]
23          p = rotate(p)
24  
25      p = tuple(reversed(p))
26      for _ in range(4):
27          if p in rules:
28              return rules[p]
29          p = rotate(p)
30  
31  
32  def apply():
33      k = 3 if len(pattern) % 2 else 2
34      out = []
35      for i in range(len(pattern) // k):
36          b = []
37          for j in range(len(pattern) // k):
38              new = find_rule(tuple("".join(pattern[i * k + y][j * k + x] for x in range(k)) for y in range(k)))
39              b.append(new)
40          for line in zip(*b):
41              out.append("".join(line))
42      return tuple(out)
43  
44  
45  for _ in range(5):
46      pattern = apply()
47  
48  print(sum(line.count("#") for line in pattern))
49  
50  
51  rules = {}
52  pattern = ".#.", "..#", "###"
53  for line in lines:
54      a, b = [tuple(k.split("/")) for k in line.split(" => ")]
55      rules[a] = b
56  
57  
58  def find_rule(p):
59      for _ in range(4):
60          if p in rules:
61              return rules[p]
62          p = rotate(p)
63      p = tuple(reversed(p))
64      for _ in range(4):
65          if p in rules:
66              return rules[p]
67          p = rotate(p)
68  
69  
70  def apply():
71      k = 3 if len(pattern) % 2 else 2
72      out = []
73      for i in range(len(pattern) // k):
74          b = []
75          for j in range(len(pattern) // k):
76              new = find_rule(tuple("".join(pattern[i * k + y][j * k + x] for x in range(k)) for y in range(k)))
77              b.append(new)
78          for line in zip(*b):
79              out.append("".join(line))
80      return tuple(out)
81  
82  
83  for _ in range(18):
84      pattern = apply()
85  
86  print(sum(line.count("#") for line in pattern))