def test_knot_hash(): assert knot_hash(arr256, "1,2,3") == "3efbe78a8d82f29979031a4aa0b16a9d" assert knot_hash(arr256, "") == "a2582a3a0e66e6e86e3812dcb672a272" assert knot_hash(arr256, "AoC 2017") == "33efeb34ea91902bb2f59c9920caa6cd" assert knot_hash(arr256, "1,2,4") == "63960835bcdc130f0b66d7ff4f6a5a8e" assert knot_hash( arr256, "102, 255, 99, 252, 200, 24, 219, 57, 103, 2, 226, 254, 1, 0, 69, 216" ) == "wat"
def part_1(data: aoc.Data): data = data.rstrip() blocks = '' for i in range(128): row = knot_hash(f'{data}-{i}') blocks += ''.join([bin(int(x, 16))[2:].zfill(4) for x in row]) return blocks.count('1')
def get_grid(inp): grid = [] for i in range(128): h = knot_hash(inp + '-' + str(i)) digits = ''.join([format(int(d, 16), '04b') for d in dense_hash(h)]) grid.append(list(digits)) return grid
def build_list(prefix_string, size): bin_list = [] for index in range(size): key_str = prefix_string + '-' + str(index) hex_str = day10.knot_hash(key_str) bin_list.append(hextobinary(hex_str)) return bin_list
def part_2(data: aoc.Data): data = data.rstrip() blocks = [] for i in range(128): row = knot_hash(f'{data}-{i}') blocks.append(''.join([bin(int(x, 16))[2:].zfill(4) for x in row])) processed = set() components = [] for x, y in product(range(128), range(128)): if (x, y) in processed or blocks[y][x] == '0': continue frontier = deque([(x, y)]) seen = set() while frontier: x, y = frontier.popleft() if (x, y) in seen: continue seen.add((x, y)) neighbours = [ (dx, dy) for (dx, dy) in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] if (dx, dy) not in seen and 0 <= dx < 128 and 0 <= dy < 128 and blocks[dy][dx] == '1' ] frontier.extend(neighbours) components.append(seen) processed.update(seen) return len(components)
def solve(puzzle_input): grid = np.zeros((128, 128), dtype=int) for row in range(128): hash_input = '{0}-{1}'.format(puzzle_input, row) hash = knot_hash(hash_input) grid[row, :] = [int(char) for char in hash_to_binary(hash)] print('squares in grid', np.count_nonzero(grid)) # Keep track of all blocks that have been grouped grouped_blocks = set() # Keep a dictionary of groups groups = {} # Get the row and column indices of the blocks rows, cols = np.where(grid == 1) group_id = 0 # For each block we have, find all blocks in it's group for i in range(len(rows)): block = rows[i], cols[i] # Skip this block if it's already been grouped if block not in grouped_blocks: # Find all blocks in the group group = make_block_group(block, grid) # Add the group to the groups dict groups[group_id] = group group_id += 1 # Add the blocks in the newest group to # the set of grouped blocks grouped_blocks |= set(group) print('Number of groups', len(groups))
def generate_grid(s): grid = [] for i in range(128): h = knot_hash(s + '-' + str(i)) row = list(''.join(['{0:04b}'.format(int(c, 16)) for c in h])) grid.append(row) return grid
def occupation_grid(inp, rows=128): """Return a list of strings containing 0 or 1 which represents the occupation grid.""" grid = [] for row in range(rows): string = inp + '-' + str(row) grid.append(''.join( [bin(int(c, 16))[2:].zfill(4) for c in knot_hash(string)])) return grid
def build(self, key): state = [] for i in range(128): row_key = f'{key}-{i}' row_hash = knot_hash(row_key) row = self._hex_to_binary(row_hash) state.append(list(row)) return Grid(state)
def part1(inp): grid = [] total = 0 for row in range(128): hexstr = knot_hash('{}-{}'.format(inp, row)) binstr = ''.join('{:04b}'.format(int(d, 16)) for d in hexstr) grid.append(binstr) total += sum(d == '1' for d in binstr) return total, grid
def create_disk(data): tmp = set() for y in range(128): hash_str = knot_hash('{}-{}'.format(data, y)) h = int(hash_str, 16) row = "{:0128b}".format(h) for x, c in enumerate(row): if c == '1': tmp.add((x, y)) return tmp
def squares_used(key: str) -> int: """Count the number of squares used for defragmentation. >>> squares_used('flqrgnkx') 8108 """ used = 0 for n in range(128): hkey = "%s-%d" % (key, n) knot = knot_hash(hkey) for c in knot: b = bin(int(c, 16)) used += b.count("1") return used
def regions(key: str) -> int: """Count the number of regions in the disk data. >>> regions('flqrgnkx') 1242 """ # First build the whole disk data. Internally, we'll use "." for empty # squares (0 bits in the hashes), "#" for used squares that are not yet # counted in a region, and "@" for squares that are already counted in a # region. disk = [] for n in range(128): knot = knot_hash("%s-%d" % (key, n)) bits = bin(int(knot, 16))[2:] bits = ("0" * (128 - len(bits))) + bits bits = bits.replace("0", ".").replace("1", "#") disk.append(list(bits)) # Some helpers… def _show(N=128): for n in range(N): print("".join(disk[n][:N])) def find_uncounted() -> typing.Tuple[int, int]: for y, x in it.product(range(128), repeat=2): if disk[y][x] == "#": return (x, y) return (-1, -1) def fill(x, y): if disk[y][x] != "#": return disk[y][x] = "@" others = ((x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)) for nx, ny in others: if 0 <= nx < 128 and 0 <= ny < 128 and disk[ny][nx] == "#": fill(nx, ny) # Now count the regions! regions = 0 ux, uy = find_uncounted() while ux >= 0 and uy >= 0: regions += 1 # print("\n\nREGION %d (start: %d, %d)" % (regions, ux, uy)) fill(ux, uy) # _show(8) ux, uy = find_uncounted() return regions
def __init__(self, seed, exporter=None): # Initialize grid print("Populating blocks...") self.blocks = { y: sparse(hex_to_bits(knot_hash('%s-%d' % (seed, y))), 0) for y in xrange(128) } # Group the blocks print("Grouping blocks...") self.num_groups = 0 exporter.start(self) for (y, row) in self.blocks.iteritems(): for (x, group) in row.iteritems(): if group == 0: exporter.next(self) self.num_groups += 1 self.flood(x, y, self.num_groups, exporter.flood)
def solve2(puzzle_input): grid = [[0 for x in range(128)] for y in range(128)] region = 1 for i, l in enumerate(puzzle_input): binary_string = to_binary(knot_hash(l)) for j, c in enumerate(binary_string): if c == "1": grid[i][j] = "#" else: grid[i][j] = "." for y in range(len(grid)): # print("x: ", x) for x in range(len(grid[y])): if not flood_fill(grid, x, y, str(region)): continue region += 1 return region - 1
def hash(key): hashed_grid = [] for i in range(128): hash_key = [ ord(char) for char in "{0}-{1}".format(key, i) ] \ + [17, 31, 73, 47, 23] row = list(range(256)) curr, skip = 0, 0 for _ in range(64): row, curr, skip = day10.knot_hash(hash_key, row, curr, skip) dense = day10.dense_hash(row) hex_rep = day10.hex_dense(dense) line = [] for x in hex_rep: line.extend([int(x) for x in "{:04b}".format(int(x, 16))]) hashed_grid.append(line) return hashed_grid
def part_two(inp): grid = [list(map(lambda x: bool(int(x)), hex_to_bin(knot_hash(''.join((inp, '-{}'.format(i))))))) for i in range(128)] def map_out_region(grid, x, y, reg): for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)): nx = max(min(127, x+dx), 0) ny = max(min(127, y+dy), 0) if grid[nx][ny] is True: grid[nx][ny] = reg map_out_region(grid, nx, ny, reg) ctr = 0 for x in range(128): for y in range(128): if grid[x][y] is True: grid[x][y] = ctr map_out_region(grid, x, y, ctr) ctr += 1 return ctr
def sum_bits(key): bits = 0 for ii in range(128): kh = knot_hash('{0}-{1}'.format(key, ii)) bits += sum(bin(int(c, 16)).count('1') for c in kh) return bits
def test_knot_hash(input_str: str, expected_hash_str: str): assert expected_hash_str == knot_hash(input_str)
return x >= 0 and x < 128 def dfs(y, x): global bin_hashes if (not in_bounds(y)) or (not in_bounds(x)) or bin_hashes[y][x] == 0: return bin_hashes[y][x] = 0 dfs(y - 1, x) dfs(y + 1, x) dfs(y, x - 1) dfs(y, x + 1) key = "jzgqcdpd" bin_hashes = [] for i in range(128): bin_hash = "" for x in day10.knot_hash(key + '-' + str(i)): bin_hash += "{0:04b}".format(int(x, 16)) bin_hashes.append([int(x) for x in bin_hash]) print(sum([h.count(1) for h in bin_hashes])) regions = 0 for y in range(128): for x in range(128): if bin_hashes[y][x] == 1: regions += 1 dfs(y, x) print(regions)
def test_knot_hash(inp, exp): assert knot_hash(inp) == exp
from day10 import knot_hash print(knot_hash('test')) def hex_to_bin(s): mapping = { '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111' } output = '' for a in s: output += mapping[a] return output print(hex_to_bin('a0c2017'))
#!/usr/bin/env python3 # this is basically day 10 + day 12 import day10 I = 'uugsqrei' # Input # Part 1 G = [] cpt = 0 for i in range(128): h = day10.knot_hash('%s-%d' % (I, i)) L = bin(int(h, 16))[2:].zfill(128) G.append(L) cpt += L.count('1') print(cpt) # Part 2 def dfs(i, j): seen[i][j] = True for (vi, vj) in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= vi < 128 and 0 <= vj < 128 and G[vi][ vj] == '1' and not seen[vi][vj]: dfs(vi, vj) seen = [[False] * 128 for _ in range(128)] cpt = 0 for i in range(128):
#!/usr/bin/env python3 # this is basically day 10 + day 12 import day10 I = 'uugsqrei' # Input # Part 1 G = [] cpt = 0 for i in range(128): h = day10.knot_hash('%s-%d' % (I,i)) L = bin(int(h,16))[2:].zfill(128) G.append(L) cpt += L.count('1') print(cpt) # Part 2 def dfs(i,j): seen[i][j] = True for (vi,vj) in [(i-1,j),(i+1,j),(i,j-1),(i,j+1)]: if 0<=vi<128 and 0<=vj<128 and G[vi][vj]=='1' and not seen[vi][vj]: dfs(vi,vj) seen = [[False]*128 for _ in range(128)] cpt = 0 for i in range(128): for j in range(128): if G[i][j]=='1' and not seen[i][j]:
def knot_hash(line): l = day10.process([ord(x) for x in line.strip()] + [17, 31, 73, 47, 23], rounds=64) return day10.knot_hash(l)
def part_one(inp): return sum(sum(map(int, hex_to_bin(knot_hash(''.join((inp, '-{}'.format(i))))))) for i in range(128))
from day10 import knot_hash input = open('./Inputs/day14.txt').read().strip() count = regions = 0 grid = [[0 for x in range(128)] for y in range(128)] for i in range(128): hash = knot_hash(input + '-' + str(i)) # https://stackoverflow.com/a/4859937 binary = bin(int(hash, 16))[2:].zfill(128) grid[i] = list(map(int, binary)) count += sum(grid[i]) print("Part 1:", count) for x in range(len(grid)): for y in range(len(grid[x])): if not grid[x][y]: continue regions += 1 # DFS frontier = [(x, y)] while len(frontier): i, j = frontier.pop() if not grid[i][j]: continue grid[i][j] = 0 # Search surrounding if within bounds if i > 0: frontier.append((i - 1, j)) if i < 127: frontier.append((i + 1, j))
return grp, chk if up > 0 and up not in global_checked: group, global_checked = recursive_add(up, group, global_checked) if index % length != length - 1 and right not in global_checked: group, global_checked = recursive_add(right, group, global_checked) if down < length * length and down not in global_checked: group, global_checked = recursive_add(down, group, global_checked) if index % length != 0 and left not in global_checked: group, global_checked = recursive_add(left, group, global_checked) return group, global_checked if __name__ == '__main__': key = 'jzgqcdpd' knot_hashes = [knot_hash(key + '-' + str(i)) for i in range(0, 128)] bin_hashes = ["{:0128b}".format(int(s, 16)) for s in knot_hashes] joined_hashes = "".join(bin_hashes) groups = list() checked = set() for k, v in enumerate(joined_hashes): if k not in checked and v == '1': new_group = [k] new_group, checked = add_neighbors(k, new_group, checked, joined_hashes) groups.append(new_group) print 'part 1:', joined_hashes.count('1') print 'part 2:', len(groups)
s = '' for r in col: s += '{:4}'.format(r) print(s) input = 'flqrgnkx' input = 'nbysizxe' sq_used = 0 grid = [] for col in range(128): row = '' for c in day10.knot_hash('{}-{}'.format(input, col)): b_string = bin(int(c, base=16) + 16) #print(b_string[-1-3:]) row += b_string[-1 - 3:] print(row) grid.append([]) for i in range(len(row)): if row[i] == '1': grid[col].append('#') sq_used += 1 else: grid[col].append('.')
from day10 import knot_hash from utils import neighbors4 import numpy as np input_str = "wenycdww" # input_str = "flqrgnkx" grid = np.zeros((128, 128)) for idx in range(128): string_to_hash = "{}-{}".format(input_str, idx) hexstr = knot_hash(string_to_hash) binary_row = "{:0128b}".format(int(hexstr, 16)) grid[idx, :] = np.array(list(binary_row)).astype(np.uint8) print(np.sum(grid)) def flood_fill(grid, row, col, marked_grid, cur_region): marked_grid[row, col] = cur_region for nr, nc in neighbors4((row, col)): if grid[nr, nc] and not marked_grid[nr, nc]: marked_grid[nr, nc] = cur_region flood_fill(grid, nr, nc, marked_grid, cur_region) tgrid = np.pad(grid, (1,1), 'constant', constant_values=(0,0))
def build_matrix(indata): hashes = [knot_hash(indata + "-" + str(k)) for k in range(128)] rows = ["".join([bin(int(y, 16))[2:].zfill(4) for y in x]) for x in hashes] return "\n".join(rows)
"""Advent of Code Day 14: Disk Defragmentation""" from day10 import knot_hash import numpy as np key = "hwlqcszp" grid = np.zeros((128, 128), dtype=int) # Part 1 # Each knot hash (128 bits) corresponds to a single row in the 128x128 grid for row in range(128): inp = key + "-" + str(row) # Input to knot hash out = knot_hash(inp) # Convert hex digit to padded binary grid[row, :] = list(''.join( [bin(int(digit, base=16)).lstrip("0b").zfill(4) for digit in out])) print("Number of squares used:", grid.sum()) # Part 2 def map_region(i, j, label): """Map out region: recursively search neighbours until we reach a neighbour without any neighbours.""" grid[i, j] = label for l, m in [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]: if 0 <= l <= 127 and 0 <= m <= 127: # Ignore out-of-bounds/wrapping if grid[l, m] == 1: map_region(l, m, label) regions = 0