/ Python / 2017 / 14.py
14.py
 1  from lib import *
 2  
 3  input = read_input(2017, 14).strip()
 4  
 5  
 6  def knot(inp):
 7      lengths = [*map(ord, inp), 17, 31, 73, 47, 23]
 8      nums = [*range(256)]
 9      pos = 0
10      skip = 0
11  
12      def rev(a, b):
13          a %= len(nums)
14          b = (b - a) % len(nums)
15          nums[:] = nums[a:] + nums[:a]
16          nums[:b] = nums[:b][::-1]
17          nums[:] = nums[-a:] + nums[:-a]
18  
19      for _ in range(64):
20          for length in lengths:
21              rev(pos, pos + length)
22              pos += length + skip
23              skip += 1
24  
25      dense = []
26      for i in range(16):
27          x = 0
28          for j in range(16):
29              x ^= nums[i * 16 + j]
30          dense.append(x)
31      return "".join(f"{x:02x}" for x in dense)
32  
33  
34  out = 0
35  for i in range(128):
36      k = bin(int(knot(f"{input}-{i}"), 16))[2:].zfill(128)
37      out += k.count("1")
38  
39  print(out)
40  
41  
42  last = None
43  uf = UnionFind(128 * 128)
44  free = 0
45  for i in range(128):
46      k = bin(int(knot(f"{input}-{i}"), 16))[2:].zfill(128)
47      for j in range(128):
48          if k[j] != "1":
49              free += 1
50              continue
51          if i and last[j] == "1":
52              uf.merge((i - 1) * 128 + j, i * 128 + j)
53          if j and k[j - 1] == "1":
54              uf.merge(i * 128 + j - 1, i * 128 + j)
55      last = k
56  
57  groups = set()
58  for i in range(128 * 128):
59      groups.add(uf.find(i))
60  print(len(groups) - free)