Exemple #1
0
        if opcode == 5 or opcode == 6:
            if opcode == 5:
                if params[0] != 0: 
                    i = params[1]
                    continue
            elif opcode == 6:
                if params[0] == 0:
                    i = params[1]
                    continue
        # ~~ end special cases ~~
        else:
            if m == 1:  # write
                intcode[intcode[i+n+m]] = operation(*params)
            elif m == 0:
                operation(*params)
        i += n + m + 1
    return intcode


assert extract_opcode(1002) == 2
assert extract_opcode(1001) == 1


# same tests from day 2 (should be backwards compatible)
assert tuple(run_program([1,0,0,0,99])) == (2,0,0,0,99)
assert tuple(run_program([2,3,0,3,99])) == (2,3,0,6,99)
assert tuple(run_program([2,4,4,5,99,0])) == (2,4,4,5,99,9801)
assert tuple(run_program([1,1,1,4,99,5,6,0,99])) == (30,1,1,4,2,5,6,0,99)

input_data = [int(n) for n in helper.read_day(5).split(",")]
run_program(input_data)
Exemple #2
0
"""Advent of Code Day 19: A Series of Tubes"""
 
import helper
import numpy as np

input_data = helper.read_day(19)

def traverse_diagram(input_data):
    # Convert data to a numpy grid (easier to index into)
    grid = np.array([list(line) for line in input_data.splitlines()])

    curr = '|'  # Start from '|' on first line
    row, col = 0, np.where(grid[0,:] == '|')[0][0]
    face = 'S'  # Compass direction
    path = []
    steps = 0

    while True:
        steps += 1
        if face == 'S': row += 1
        elif face == 'N': row -= 1
        elif face == 'W': col -= 1
        elif face == 'E': col += 1
        curr = grid[row, col]

        if curr == '+':
            # Which direction to turn into? Check non-empty adjacent cells.
            if face == 'N' or face == 'S':
                face = 'E' if grid[row, col+1] != ' ' else 'W'
            elif face == 'E' or face == 'W':
                face = 'S' if grid[row+1, col] != ' ' else 'N'
Exemple #3
0
        sum_weight = []
        for child in curr["children"]:
            sum_weight.append(self.get_total_weight(child))
        # Children are unbalanced / find index of unbalanced child
        if len(set(sum_weight)) > 1:
            i = [
                sum_weight.index(w) for w in list(set(sum_weight))
                if sum_weight.count(w) == 1
            ][0]
            j = [
                sum_weight.index(w) for w in list(set(sum_weight))
                if sum_weight.count(w) > 1
            ][0]
            wrong_weight = sum_weight[i] - sum_weight[j]
            wrong_node = curr["children"][i]
            return self.find_unbalanced(wrong_node)
        return node


data = helper.read_day(7).splitlines()
tower = TowerGraph()
for row in data:
    # Collect alphanumeric pieces (ignore cruft)
    node, weight, *children = re.findall("\w+", row)
    tower.add_node(node, weight)
    tower.add_children(node, children)
root = tower.find_root(node)

# Check balance
print(tower.find_unbalanced(root))
Exemple #4
0

def parse_firewall(inp):
    """Parse input file to firewall data (dictionary)."""
    firewall = {}
    inp = inp.splitlines()
    for layer in inp:
        depth, rng = map(int, layer.split(": "))
        firewall[depth] = rng
    return firewall


# Part 1
# Simulate packet stepping through firewall.

firewall = parse_firewall(helper.read_day(13).strip())
severity = 0
time = 0
for step in range(max(firewall) + 1):
    # Get caught if:  time % ((firewall[step]-1)*2) == 0 where
    # (firewall[step]-1)*2 is the number of moves to complete one cycle of
    # going down and up the range of a layer. Equals 0 since we are travelling
    # on the tops of each layer.
    if step in firewall and time % ((firewall[step] - 1) * 2) == 0:
        severity += step * firewall[step]
    time += 1

print(severity)

# Part 2
# Brute-force this by restarting the simulation with increased delay each time
Exemple #5
0
                cancelled = True
            else:
                count_garbage += 1
        else:
            if c == "{":  # Open group
                depth += 1
                score += depth
            elif c == "}":  # Close group
                depth -= 1
            elif c == "<":
                in_garbage = True
    return (score, count_garbage)


# Test Part 1
assert score("{}")[0] == 1
assert score("{{{}}}")[0] == 6
assert score("{{},{}}")[0] == 5
assert score("{<a>,<a>,<a>,<a>}")[0] == 1
assert score("{{<ab>},{<ab>},{<ab>},{<ab>}}")[0] == 9
assert score("{{<a!>},{<a!>},{<a!>},{<ab>}}")[0] == 3

# Test Part 2
assert score("<>")[1] == 0
assert score("<random characters>")[1] == 17
assert score("<<<<>")[1] == 3
assert score("<!!!>>")[1] == 0
assert score("""<{o"i!a,<{i<a>""")[1] == 10

stream = helper.read_day(9).strip()
print(score(stream))
Exemple #6
0
def enumerate_patterns(grid):
    """Given a base grid pattern, enumerates over the rest of the patterns 
    attainable by flip/rotates and returns the set."""
    pat_set = set()
    tmp = grid[:, :]
    for rot in range(4):
        tmp = tmp.T[:, ::-1]  # 90deg rotation
        pat_set.add(grid_to_pattern(tmp[:, :]))
        # Horizontal and vertical flips
        pat_set.add(grid_to_pattern(tmp[::-1, :]))
        pat_set.add(grid_to_pattern(tmp[:, ::-1]))
    return pat_set


# Parse enhancement guide
input_file = helper.read_day(21).strip().splitlines()
guide = {}
for line in input_file:
    inp, out = line.split(' => ')
    # Consider all rotations / flips in input
    equivs = enumerate_patterns(pattern_to_grid(inp))
    for pat in equivs:
        guide[pat] = out

# Enhance loop
grid = pattern_to_grid(".#./..#/###")
pixels_on = []
for step in range(18):
    # Split grid into subgrids
    out_subs = []
    for sub in split_grid(grid):
Exemple #7
0
import helper
import re
from collections import defaultdict, deque

# Parse input as graph
# Store graph as a dictionary of lists (adjacency list)
graph = defaultdict(list)
inp = helper.read_day(12).strip().splitlines()
for line in inp:
    ids = list(map(int, re.findall("\w+", line)))
    for i in ids[1:]:
        graph[ids[0]].append(i)

# Part 1
# How many programs are in the group with program ID 0?
# Use Breadth-First Search, starting with node 0.

def bfs(g, s):
    """Breadth-first search for graph g, starting at node s.
    Returns a set of traversed nodes."""
    q = deque([s])
    discovered = set([s])
    while len(q) > 0:
        curr = q.popleft()
        for neigh in g[curr]:    
            if neigh not in discovered:
                discovered.add(neigh)
                q.append(neigh)
    return discovered

nodes = bfs(graph, 0)
Exemple #8
0
"""Advent of Code 2017 Day 5: A Maze of Twisty Trampolines, All Alike""" 

import helper

def jump(jumps, offset):
    """Given jump array and offset function, compute number of jumps."""
    jumps = jumps.copy()  # Copy to avoid modifying list
    idx = 0  # current location
    prev = 0  # previous location
    count = 0  # number of jumps so far
    while not (idx >= len(jumps) or idx < 0):
        prev = idx
        idx += jumps[idx]  # Jump to new position
        count += 1
        jumps[prev] += offset(jumps[prev])  # Shift previous position
    return count

# Offset functions for part 1 & 2
offset_p1 = lambda offset: 1
offset_p2 = lambda offset: -1 if offset >= 3 else 1

assert jump([0,3,0,1,-3], offset_p1) == 5
assert jump([0,3,0,1,-3], offset_p2) == 10

# Try for actual input
input_data = list(map(int, helper.read_day(5).splitlines()))
print("Part 1:", jump(input_data, offset_p1))
print("Part 2:", jump(input_data, offset_p2))
Exemple #9
0
    - keep track of every point along the path for each wire
    - find set of points that intersect w1 and w2
    - calculate manhatten distance for each and return lowest
    """
    w1, w1_lowest_steps = get_points_on_wire_path(w1.split(","))
    w2, w2_lowest_steps = get_points_on_wire_path(w2.split(","))
    intersections = w1.intersection(w2)
    intersections.discard((0, 0))  # ignore output port
    # Part 1: sort all intersection points by Manhattan distance and return lowest
    closest_point = sorted(intersections, key=manhattan)[0]
    # Part 2: sort by lowest combined step count
    fewest_steps_point = sorted(
        intersections,
        key=lambda p: w1_lowest_steps[p] + w2_lowest_steps[p])[0]

    return (manhattan(closest_point), w1_lowest_steps[fewest_steps_point] +
            w2_lowest_steps[fewest_steps_point])


assert get_closest_and_nearest_intersections(
    "R75,D30,R83,U83,L12,D49,R71,U7,L72",
    "U62,R66,U55,R34,D71,R55,D58,R83") == (159, 610)

assert get_closest_and_nearest_intersections(
    "R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51",
    "U98,R91,D20,R16,D67,R40,U7,R15,U6,R7") == (135, 410)

input_wires = helper.read_day(3).splitlines()
output = get_closest_and_nearest_intersections(*input_wires)
print("Part 1:", output[0])
print("Part 2:", output[1])
Exemple #10
0
    curr, skip = 0, 0
    for i in range(64):
        lst, curr, skip = hash_round(lst, lengths, curr, skip)
    # Get dense hash by taking blocks of numbers
    dense = []
    for i in range(16):
        xor = 0
        for j in range(16):
            xor ^= lst[i * 16 + j]
        dense.append(xor)
    # Convert 16 numbers to hex string
    knothash = ''.join([hex(num)[2:].zfill(2) for num in dense])
    return (knothash)


assert hash_round([0, 1, 2, 3, 4], [3, 4, 1, 5])[0][0:2] == [3, 4]

assert knot_hash("") == "a2582a3a0e66e6e86e3812dcb672a272"
assert knot_hash("AoC 2017") == "33efeb34ea91902bb2f59c9920caa6cd"
assert knot_hash("1,2,3") == "3efbe78a8d82f29979031a4aa0b16a9d"
assert knot_hash("1,2,4") == "63960835bcdc130f0b66d7ff4f6a5a8e"

if __name__ == "__main__":  # Need to re-use the functions on day 14

    lst = list(range(0, 256))
    lengths = list(map(int, helper.read_day(10).strip().split(',')))
    part1 = hash_round(lst, lengths)[0]
    print("Part 1 solution:", part1[0] * part1[1])

    input_string = helper.read_day(10).strip()
    print("Part 2 solution:", knot_hash(input_string))
Exemple #11
0
import helper
import math


def calculate_fuel(mass):
    return math.floor(mass / 3) - 2


def calculate_fuel_recursive(mass):
    fuel = calculate_fuel(mass)
    if fuel > 0:
        return fuel + calculate_fuel_recursive(fuel)
    else:
        return 0


assert calculate_fuel(12) == 2
assert calculate_fuel(14) == 2
assert calculate_fuel(1969) == 654
assert calculate_fuel(100756) == 33583

input_masses = [int(mass) for mass in helper.read_day(1).splitlines()]
print("Fuel requirements (1):", sum(calculate_fuel(m) for m in input_masses))

assert calculate_fuel_recursive(14) == 2
assert calculate_fuel_recursive(1969) == 966
assert calculate_fuel_recursive(100756) == 50346

print("Fuel requirements (2)",
      sum(calculate_fuel_recursive(m) for m in input_masses))
Exemple #12
0
"""Advent of Code Day 18: Duet"""

import helper
import re
from collections import defaultdict, deque

input_data = helper.read_day(18).strip().splitlines()

# Part 1


def map_value(registers, val):
    """Maps an argument in an instruction to a numeric value.
    Letters are converted to the values in their register, while numbers are
    treated normally (as integers)."""
    return int(val) if re.match("[a-z]", val) is None else int(registers[val])


def parse_instruction(registers, instruction, args, line_num):
    """Parses a line of the instructions, excluding snd/rcv (special cases).
    Returns a line number (to deal with jumps)."""
    # First argument is a register, second is a value
    ch = args[0]
    val = map_value(registers, args[1])
    if instruction == "set":
        registers[ch] = val
    elif instruction == "add":
        registers[ch] += val
    elif instruction == "mul":
        registers[ch] *= val
    elif instruction == "mod":
Exemple #13
0
import helper
from collections import defaultdict


def process_registers(instructs):
    """Processes register instructions. Returns tuple consisting of largest
    value in a register after completion (part 1) and highest value held at
    any point in time in a register (part 2)."""
    registers = defaultdict(int)  # Default to zero
    highest = 0
    OPS = {"inc": "+=", "dec": "-="}

    for line in instructs:
        key, op, opval, *cond = line.split()
        # Build an expression like "a += 1 if b >= 2 else 0"
        # (Pass registers into local namespace for expression)
        expr = [key, OPS[op], opval] + cond + ["else 0"]
        exec(' '.join(expr), None, registers)
        # Part 2 - Query highest value
        highest = max(registers[key], highest)
    return (max(registers.values()), highest)


# Test Part 1 & 2
assert process_registers("""b inc 5 if a > 1
                            a inc 1 if b < 5
                            c dec -10 if a >= 1
                            c inc -20 if c == 10""".splitlines()) == (1, 10)

instructs = helper.read_day(8).splitlines()
print(process_registers(instructs))
Exemple #14
0
meaning distance can be represented as: max(abs(n), abs(ne), abs(n+ne))
"""


def steps_away(dirs):
    """Compute shortest number of steps away based on steps taken so far."""
    n = dirs["n"] - dirs["s"] + dirs["nw"] - dirs["se"]
    ne = dirs["ne"] - dirs["sw"] - dirs["nw"] + dirs["se"]
    return (max(abs(n), abs(ne), abs(n + ne)))


def hex_steps(path):
    """Count number of steps to return to origin given directions (part 1) 
    and furthest number of steps (part 2)."""
    furthest = 0
    dirs = {"n": 0, "nw": 0, "ne": 0, "sw": 0, "s": 0, "se": 0}
    for step in path:
        dirs[step] += 1
        if steps_away(dirs) > furthest:
            furthest = steps_away(dirs)
    return (steps_away(dirs), furthest)


# Test Part 1
assert hex_steps(["ne", "ne", "ne"])[0] == 3
assert hex_steps(["ne", "ne", "sw", "sw"])[0] == 0
assert hex_steps(["ne", "ne", "s", "s"])[0] == 2
assert hex_steps(["se", "sw", "se", "sw", "sw"])[0] == 3

data = helper.read_day(11).strip().split(',')
print(hex_steps(data))
Exemple #15
0
        if move[0] == "s":  # Spin
            spin = int(move[1:])
            progs = progs[-spin:] + progs[:-spin]
        elif move[0] == "x":  # Exchange
            a, b = map(int, move[1:].split("/"))
            progs[a], progs[b] = progs[b], progs[a]
        elif move[0] == "p":  # Partner
            a, b = move[1:].split("/")
            ia, ib = progs.index(a), progs.index(b)
            progs[ia], progs[ib] = progs[ib], progs[ia]
    return ''.join(progs)

assert dance("abcde", ["s1", "x3/4", "pe/b"]) == "baedc"

progs = "abcdefghijklmnop"
moves = helper.read_day(16).strip().split(",")
progs = dance(progs, moves)
print("Part 1:", progs)

# Part 2

# We can't brute-force a billion answers: let's try to instead find
# a recurring cycle.
# Initialize list of "solutions" with part 1 answer.
solutions = [progs]
for i in range(1,1000000000):
    progs = dance(progs, moves)
    if progs in solutions:
        solutions.append(progs)
        break
    else:
Exemple #16
0
import helper


def count_cycles(banks):
    """Returns number of cycles needed and length of cycle."""
    banks = banks.copy()
    N = len(banks)
    prev_configs = []  # Store previous cycle configurations
    count = 0

    while banks not in prev_configs:
        prev_configs.append(banks.copy())

        # Redistribute the blocks:
        # Get max value and its index (prioritizing lowest index first)
        # Note banks.index(max(banks)) works, but this needs to traverse twice
        idx, blocks = max([(i, v) for i, v in enumerate(banks)],
                          key=lambda k: (k[1], N - k[0]))
        banks[idx] = 0
        for i in range(1, blocks + 1):
            banks[(idx + i) % N] += 1
        count += 1
    return (count, count - prev_configs.index(banks))


assert count_cycles([0, 2, 7, 0]) == (5, 4)

banks_input = list(map(int, helper.read_day(6).split()))
output = count_cycles(banks_input)
print("{} cycles completed with infinite loop length of {}.".format(*output))