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"
Beispiel #2
0
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
Beispiel #4
0
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
Beispiel #5
0
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)
Beispiel #6
0
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))
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
    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)
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
    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
Beispiel #16
0
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
Beispiel #17
0
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
Beispiel #18
0
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
Beispiel #19
0
def test_knot_hash(input_str: str, expected_hash_str: str):
    assert expected_hash_str == knot_hash(input_str)
Beispiel #20
0
    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)
Beispiel #21
0
def test_knot_hash(inp, exp):
    assert knot_hash(inp) == exp
Beispiel #22
0
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'))
Beispiel #23
0
#!/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):
Beispiel #24
0
#!/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]:
Beispiel #25
0
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)
Beispiel #26
0
def part_one(inp):
    return sum(sum(map(int, hex_to_bin(knot_hash(''.join((inp, '-{}'.format(i))))))) for i in range(128))
Beispiel #27
0
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))
Beispiel #28
0
        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)
Beispiel #29
0
        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('.')
Beispiel #30
0
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))
Beispiel #31
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)
Beispiel #32
0
"""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