Browse Source

Day 14

master
Chris Smith 6 years ago
parent
commit
4ffc067aeb
6 changed files with 72 additions and 39 deletions
  1. 1
    0
      .gitignore
  2. 3
    34
      10.py
  3. 2
    5
      12.py
  4. 15
    0
      14.py
  5. 1
    0
      data/14.txt
  6. 50
    0
      shared.py

+ 1
- 0
.gitignore View File

@@ -1 +1,2 @@
1 1
 .idea
2
+__pycache__

+ 3
- 34
10.py View File

@@ -1,40 +1,9 @@
1
-import functools
2
-import itertools
3
-import operator
4
-
5
-
6
-def reverse_slice(input, start, length):
7
-    output = list(input)
8
-    for i, pos in enumerate(range(start, start + length)):
9
-        output[pos % len(output)] = input[(start + length - i - 1) % len(output)]
10
-    return output
11
-
12
-
13
-def do_rounds(lengths, count=1):
14
-    position, skip, data = 0, 0, list(range(256))
15
-    for _ in range(count):
16
-        for length in lengths:
17
-            data = reverse_slice(data, position, length)
18
-            position += length + skip
19
-            skip += 1
20
-    return data
21
-
22
-
23
-def group(n, iterable):
24
-    # https://docs.python.org/3.1/library/itertools.html#recipes
25
-    args = [iter(iterable)] * n
26
-    return itertools.zip_longest(*args)
27
-
1
+from shared import knot_hash, knot_hash_rounds
28 2
 
29 3
 with open('data/10.txt', 'r') as file:
30 4
     lengths = list(map(int, file.readline().strip().split(',')))
31
-    data = do_rounds(lengths)
5
+    data = knot_hash_rounds(lengths)
32 6
     print(f'Part one: {data[0]*data[1]}')
33 7
 
34
-
35 8
 with open('data/10.txt', 'r') as file:
36
-    lengths = list(map(ord, file.readline().strip())) + [17, 31, 73, 47, 23]
37
-    sparse_hash = do_rounds(lengths, 64)
38
-    dense_hash = [functools.reduce(operator.xor, g) for g in group(16, sparse_hash)]
39
-    # Yo dawg, I heard you like f-strings, so we put an f-string in your f-string.
40
-    print(f'Part two: {"".join(f"{c:02x}" for c in dense_hash)}')
9
+    print(f'Part two: {knot_hash(file.readline().strip())}')

+ 2
- 5
12.py View File

@@ -1,13 +1,10 @@
1
-import functools
1
+from shared import add_connected_components
2 2
 
3 3
 with open('data/12.txt', 'r') as file:
4 4
     sets = []
5 5
     pipes = list(map(lambda l: l.strip().replace(' <-> ', ', ').split(', '), file.readlines()))
6 6
     for pipe in pipes:
7
-        overlapping = [s for s in sets if any(program in s for program in pipe)]
8
-        for overlap in overlapping:
9
-            sets.remove(overlap)
10
-        sets.append(functools.reduce(set.union, overlapping, set(pipe)))
7
+        add_connected_components(sets, pipe)
11 8
 
12 9
     print(f'Part one: {len(next(s for s in sets if "0" in s))}')
13 10
     print(f'Part two: {len(sets)}')

+ 15
- 0
14.py View File

@@ -0,0 +1,15 @@
1
+import functools
2
+
3
+from shared import knot_hash, add_connected_components
4
+
5
+with open('data/14.txt', 'r') as file:
6
+    seed = file.readline().strip()
7
+    grid = [bin(int(knot_hash(f'{seed}-{i}'), 16))[2:].zfill(128) for i in range(128)]
8
+    print(f'Part one: {sum(row.count("1") for row in grid)}')
9
+
10
+    regions = []
11
+    for y, row in enumerate(grid):
12
+        for x, cell in enumerate(row):
13
+            if cell == '1':
14
+                add_connected_components(regions, [(x-1, y), (x, y-1), (x+1, y), (x, y+1)], {(x, y)})
15
+    print(f'Part two: {len(regions)}')

+ 1
- 0
data/14.txt View File

@@ -0,0 +1 @@
1
+vbqugkhl

+ 50
- 0
shared.py View File

@@ -0,0 +1,50 @@
1
+import functools
2
+import itertools
3
+import operator
4
+
5
+
6
+def reverse_slice(input, start, length):
7
+    """Reverses a slice of the input list, wrapping around if necessary."""
8
+    output = list(input)
9
+    for i, pos in enumerate(range(start, start + length)):
10
+        output[pos % len(output)] = input[(start + length - i - 1) % len(output)]
11
+    return output
12
+
13
+
14
+def knot_hash_rounds(lengths, count=1):
15
+    """Applies a number of rounds of the knot hash algorithm (see day 10)."""
16
+    position, skip, data = 0, 0, list(range(256))
17
+    for _ in range(count):
18
+        for length in lengths:
19
+            data = reverse_slice(data, position, length)
20
+            position += length + skip
21
+            skip += 1
22
+    return data
23
+
24
+
25
+def group(n, iterable):
26
+    """Collates the iterable into groups n items long."""
27
+    # https://docs.python.org/3.1/library/itertools.html#recipes
28
+    args = [iter(iterable)] * n
29
+    return itertools.zip_longest(*args)
30
+
31
+
32
+def knot_hash(seed):
33
+    """The knot has algorithm (day 10). Output is a hex string."""
34
+    lengths = list(map(ord, seed.strip())) + [17, 31, 73, 47, 23]
35
+    sparse_hash = knot_hash_rounds(lengths, 64)
36
+    dense_hash = [functools.reduce(operator.xor, g) for g in group(16, sparse_hash)]
37
+    return "".join(f"{c:02x}" for c in dense_hash)
38
+
39
+
40
+def add_connected_components(sets, links, to_add=None):
41
+    """
42
+    Updates the given collection of sets to include a new group of connected components.
43
+
44
+    Existing sets that overlap with the given `links` are removed and conjoined into a new superset along with the
45
+    `to_add` items specified. If `to_add` is not specified then the `links` are added in their place.
46
+    """
47
+    overlapping = [s for s in sets if any(link in s for link in links)]
48
+    for overlap in overlapping:
49
+        sets.remove(overlap)
50
+    sets.append(functools.reduce(set.union, overlapping, set(to_add if to_add is not None else links)))

Loading…
Cancel
Save