#############################
# --- Day 12: Rain Risk --- #
#############################

import AOCUtils

moves = {"E": (1, 0),
         "N": (0, 1),
         "W": (-1, 0),
         "S": (0, -1)}

#############################

navigation = AOCUtils.loadInput(12)

pos = (0, 0)
facing = 0

for inst in navigation:
    action, n = inst[0], int(inst[1:])
   
    if action in moves:
        delta = moves[action]
        pos = (pos[0] + (delta[0] * n), pos[1] + (delta[1] * n))
    elif action == "L":
        facing = (facing + (n // 90)) % 4
    elif action == "R":
        facing = (facing - (n // 90)) % 4
    elif action == "F":
        delta = list(moves.values())[facing]
        pos = (pos[0] + (delta[0] * n), pos[1] + (delta[1] * n))
####################################################
# --- Day 2: I Was Told There Would Be No Math --- #
####################################################

import AOCUtils

####################################################

presents = AOCUtils.loadInput(2)

presents = [tuple(map(int, present.split("x"))) for present in presents]

totalPaper = 0
for present in presents:
    l, w, h = present

    paper = 2 * l * w + 2 * w * h + 2 * h * l + min(l * w, w * h, h * l)
    totalPaper += paper

print("Part 1: {}".format(totalPaper))

totalRibbon = 0
for present in presents:
    l, w, h = present

    ribbon = 2 * min(l + w, w + h, h + l) + l * w * h
    totalRibbon += ribbon

print("Part 2: {}".format(totalRibbon))

AOCUtils.printTimeTaken()
# --- Day 10: Balance Bots --- #
################################

import AOCUtils


class Bot:
    def __init__(self):
        self.chips = []
        self.lowType, self.lowID = None, None
        self.highType, self.highID = None, None


################################

instructions = AOCUtils.loadInput(10)

bots = dict()
for inst in instructions:
    inst = inst.split()

    if inst[0] == "bot":
        botID = int(inst[1])
        if botID not in bots:
            bots[botID] = Bot()

        bots[botID].lowType = inst[5]
        bots[botID].lowID = int(inst[6])
        bots[botID].highType = inst[10]
        bots[botID].highID = int(inst[11])
    elif inst[0] == "value":
Beispiel #4
0
    vm = VM(memory)
    vm.run()
    print("".join([chr(c) for c in vm.output]))
    while not vm.halted:
        vm.output = []
        vm.run(input() + "\n")
        print("".join([chr(c) for c in vm.output]))
    exit()


def oppositeDoor(direction):
    opp = {"north": "south", "south": "north", "east": "west", "west": "east"}
    return opp[direction]


rawProgram = AOCUtils.loadInput(25)
memory = [int(i) for i in rawProgram.split(",")]

blacklist = set([
    "infinite loop", "molten lava", "giant electromagnet", "photons",
    "escape pod"
])

vm = VM(memory)
vm.run()

finalState = None
maxItemsFound = 0

# BFS through all rooms, storing (room, inventory) visited states
visited = set()
########################################
# --- Day 1: No Time for a Taxicab --- #
########################################

import AOCUtils

########################################

steps = AOCUtils.loadInput(1)
steps = [s.strip() for s in steps.split(",")]

directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]  # NESW, clockwise

pos = (0, 0)
facing = 0
visited = set()
hq = None
for step in steps:
    d, n = step[0], int(step[1:])

    facing += 1 if d == "R" else -1
    direction = directions[facing % 4]

    for _ in range(n):
        pos = (pos[0] + direction[0], pos[1] + direction[1])
        if not hq:
            if pos not in visited:
                visited.add(pos)
            else:
                hq = pos
Beispiel #6
0
            # print(" | ".join(k+": "+"{:<7}".format(str(v)) for k, v in self.registers.items()))

            self.pc += 1


def isPrime(n):
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True


#############################################

code = AOCUtils.loadInput(23)

program = Program(code)
program.run()
print("Part 1: {}".format(program.mulCount))

# program = Program(code, 1)
# program.run()
# print("Part 2: {}".format(program.registers["h"]))

b0 = int(code[0].split()[-1]) * 100 + 100000

nonPrimesAmt = 0
for b in range(b0, b0 + 17000 + 1, 17):
    if not isPrime(b):
        nonPrimesAmt += 1
                neighbors += int(grid[i + 1][j - 1] == "#")
            if i + 1 < sizeX:
                neighbors += int(grid[i + 1][j] == "#")
            if i + 1 < sizeX and j + 1 < sizeY:
                neighbors += int(grid[i + 1][j + 1] == "#")

            if grid[i][j] == "#":
                newGrid[i][j] = "#" if neighbors in [2, 3] else "."
            elif grid[i][j] == ".":
                newGrid[i][j] = "#" if neighbors == 3 else "."

    return newGrid


############################################

startGrid = [list(s) for s in AOCUtils.loadInput(18)]

grid = [row[:] for row in startGrid]
for _ in range(100):
    grid = step(grid, part=1)

print("Part 1: {}".format(sum(row.count("#") for row in grid)))

grid = [row[:] for row in startGrid]
for _ in range(100):
    grid = step(grid, part=2)

print("Part 2: {}".format(sum(row.count("#") for row in grid)))

AOCUtils.printTimeTaken()
Beispiel #8
0
        queue = deque([(self.start, 0, 0)])
        visited = set()
        while queue:
            cur, level, dist = queue.popleft()

            if (cur, level) in visited: continue
            visited.add((cur, level))
            if level == 0 and cur == self.end: break


            if level > 0 and cur in self.outerPortals:
                queue.append((self.outerPortals[cur], level-1, dist+1))
            elif cur in self.innerPortals:
                queue.append((self.innerPortals[cur], level+1, dist+1))

            for m in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
                step = (cur[0]+m[0], cur[1]+m[1])
                if self.__isWalkable(step):
                    queue.append((step, level, dist+1))

        return dist

rawMaze = [list(s) for s in AOCUtils.loadInput(20)]
maze = Maze(rawMaze)

print("Part 1: {}".format(maze.getMinDistance()))

print("Part 2: {}".format(maze.getMinDistanceLayers()))

AOCUtils.printTimeTaken()
import AOCUtils


def replaceNth(s, old, new, n):
    find = s.find(old)
    for _ in range(n - 1):
        find = s.find(old, find + 1)
        if find == -1: return s

    return s[:find] + new + s[find + len(old):]


########################################

rawInput = AOCUtils.loadInput(19)

replacements = [r.split(" => ") for r in rawInput[:-2]]
molecule = rawInput[-1]

newMolecules = set()
for old, new in replacements:
    for i in range(molecule.count(old)):
        newMolecule = replaceNth(molecule, old, new, i + 1)
        newMolecules.add(newMolecule)

print("Part 1: {}".format(len(newMolecules)))
'''
X != Rn, Ar, Y

e => XX
#####################################
# --- Day 19: A Series of Tubes --- #
#####################################

import AOCUtils

#####################################

diagram = AOCUtils.loadInput(19)

h, w = len(diagram), len(diagram[0])

cx, cy = None, None
for y in range(w):
    if diagram[0][y] != " ":
        cx, cy = 0, y
        break

seenLetters = []
steps = 0

px, py = -1, cy
nx, ny = 1, cy
while diagram[cx][cy] != " ":
    if diagram[cx][cy].isalpha():
        seenLetters.append(diagram[cx][cy])

    if diagram[cx][cy] != "+":
        nx, ny = cx+cx-px, cy+cy-py
    else:
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
Beispiel #11
0
##########################

import AOCUtils


def distToOrigin(p):
    x, y = p
    if (x >= 0) == (y >= 0):
        return abs(x + y)
    else:
        return max(abs(x), abs(y))


##########################

path = AOCUtils.loadInput(11).split(",")

# X axis rotated 30 deg (L/R is SW/NE)
directions = {
    "nw": (-1, 1),
    "n": (0, 1),
    "ne": (1, 0),
    "sw": (-1, 0),
    "s": (0, -1),
    "se": (1, -1)
}

steps = [(0, 0)]
for p in path:
    x, y = steps[-1]
    dx, dy = directions[p]
Beispiel #12
0
##################################
# --- Day 22: Grid Computing --- #
##################################

import AOCUtils
from collections import deque

##################################

rawNodes = AOCUtils.loadInput(22)[2:]

nodes = dict()
for rawNode in rawNodes:
    rawNode = rawNode.split()

    name, size, used, avail, pct = rawNode
    x, y = name.split("-")[1:]

    x, y = int(x[1:]), int(y[1:])
    size, used = int(size[:-1]), int(used[:-1])
    avail, pct = int(avail[:-1]), int(pct[:-1])

    nodes[(x, y)] = {"size": size, "used": used, "avail": avail, "pct": pct}

viableCount = 0
for a in nodes:
    for b in nodes:
        if a == b: continue

        if nodes[a]["used"] != 0 and nodes[a]["used"] < nodes[b]["avail"]:
            viableCount += 1
# of linear congruences (assumes all elements in mods are coprime)
def chineseRemainderTheorem(mods, remainders):
    # Given linear congruences x%3 = 2, x%5 = 3, x%7 = 2,
    # x = chineseRemainderTheorem([3, 5, 7], [2, 3, 2])

    N = 1
    for m in mods:
        N *= m

    x = sum(r * N // m * modinv(N // m, m) for m, r in zip(mods, remainders))
    return x % N


##################################

notes = AOCUtils.loadInput(13)

arrivedAtBusStop = int(notes[0])
schedule = notes[1].split(",")

nextArrivals = []
for i, busID in enumerate(schedule):
    if busID == "x": continue
    busInterval = int(busID)

    sinceLastArrival = arrivedAtBusStop % busInterval
    untilNextArrival = busInterval - sinceLastArrival

    nextArrivals.append((untilNextArrival, busInterval))

nextArrivals.sort()
        self.removed = False

        p, v, a = rawParticle.split(", ")
        self.p = [int(i) for i in p[3:-1].split(",")]
        self.v = [int(i) for i in v[3:-1].split(",")]
        self.a = [int(i) for i in a[3:-1].split(",")]

    def update(self):
        if not self.removed:
            self.v = tuple(v + a for v, a in zip(self.v, self.a))
            self.p = tuple(p + v for p, v in zip(self.p, self.v))


##################################

rawParticles = AOCUtils.loadInput(20)

particles = [Particle(i, p) for i, p in enumerate(rawParticles)]

for _ in range(1000):
    for p in particles:
        p.update()

m = min(particles, key=lambda p: sum(map(abs, p.p)))
print("Part 1: {}".format(m.pid))

particles = [Particle(i, p) for i, p in enumerate(rawParticles)]

for _ in range(1000):
    for p in particles:
        p.update()
Beispiel #15
0
        if part == 2:
            for _ in range(2016):
                s = hashlib.md5(s.encode()).hexdigest()

        for c in range(len(s) - 3 - 1):
            if len(set(s[c:c + 3])) == 1:
                possibleKeys[s[c]].append(i)
                break

        for c in range(len(s) - 5 - 1):
            if len(set(s[c:c + 5])) == 1:
                for keyi in possibleKeys[s[c]]:
                    if keyi + 1 <= i <= keyi + 1000:
                        otpKeys.add(keyi)
                break

        i += 1

    return sorted(otpKeys)[63]


################################

salt = AOCUtils.loadInput(14)

print("Part 1: {}".format(getOTP(salt, part=1)))

print("Part 2: {}".format(getOTP(salt, part=2)))

AOCUtils.printTimeTaken()
Beispiel #16
0
                if xVal != 0:
                    self.pc += yVal - 1
            elif inst == "tgl":
                n = self.pc + xVal
                if 0 <= n < len(self.program):
                    if n in self.toggled:
                        self.toggled.remove(n)
                    else:
                        self.toggled.add(n)

            self.pc += 1


#################################

program = AOCUtils.loadInput(23)

# vm = VM(program)
# vm.registers["a"] = 7
# vm.run()
# print("Part 1: {}".format(vm.registers["a"]))

# vm = VM(program)
# vm.registers["a"] = 12
# vm.run()
# print("Part 2: {}".format(vm.registers["a"]))

X = int(program[19].split()[1])
Y = int(program[20].split()[1])

a = factorial(7) + X * Y
Beispiel #17
0
def countTrees(forest, deltaW, deltaH):
    h, w = len(forest), len(forest[0])

    trees = 0

    curH, curW = 0, 0
    for curH in range(0, h, deltaH):
        trees += int(forest[curH][curW] == "#")

        curW = (curW + deltaW) % w

    return trees


######################################

forest = AOCUtils.loadInput(3)

p1 = countTrees(forest, 3, 1)

print("Part 1: {}".format(p1))

p2 = countTrees(forest, 1, 1)
p2 *= countTrees(forest, 3, 1)
p2 *= countTrees(forest, 5, 1)
p2 *= countTrees(forest, 7, 1)
p2 *= countTrees(forest, 1, 2)

print("Part 2: {}".format(p2))

AOCUtils.printTimeTaken()
##################################
# --- Day 1: Inverse Captcha --- #
##################################

import AOCUtils

##################################

digits = str(AOCUtils.loadInput(1))

totalSum = sum(
    int(digits[i]) for i in range(len(digits)) if digits[i] == digits[i - 1])
print("Part 1: {}".format(totalSum))

skip = len(digits) // 2

totalSum = sum(
    int(digits[i]) for i in range(len(digits))
    if digits[i] == digits[(i + skip) % len(digits)])
print("Part 2: {}".format(totalSum))

AOCUtils.printTimeTaken()
import AOCUtils


def allTuplesWithSum(n, total):
    if n == 1:
        yield (total, )
        return

    for i in range(total + 1):
        for t in allTuplesWithSum(n - 1, total - i):
            yield (i, ) + t


#############################################

rawIngredients = AOCUtils.loadInput(15)

ingredients = []
for rawIngredient in rawIngredients:
    rawIngredient = rawIngredient.split()

    ingredient = {
        "capacity": int(rawIngredient[2][:-1]),
        "durability": int(rawIngredient[4][:-1]),
        "flavor": int(rawIngredient[6][:-1]),
        "texture": int(rawIngredient[8][:-1]),
        "calories": int(rawIngredient[10])
    }

    ingredients.append(ingredient)
Beispiel #20
0
##################################
# --- Day 6: Binary Boarding --- #
##################################

import AOCUtils

##################################

rawAnswers = AOCUtils.loadInput(6)

for i in range(len(rawAnswers)):
    if rawAnswers[i] == "": rawAnswers[i] = "\n"

rawGroups = " ".join(rawAnswers).split("\n")

groups = [[set(answer) for answer in rawGroup.split()]
          for rawGroup in rawGroups]

p1 = sum(len(set.union(*group)) for group in groups)
print("Part 1: {}".format(p1))

p2 = sum(len(set.intersection(*group)) for group in groups)
print("Part 2: {}".format(p2))

AOCUtils.printTimeTaken()
####################################
# --- Day 6: Signals and Noise --- #
####################################

import AOCUtils

####################################

messages = AOCUtils.loadInput(6)
n = len(messages[0])

counts = [dict() for _ in range(n)]
for message in messages:
    for i, c in enumerate(message):
        if c not in counts[i]:
            counts[i][c] = 0
        counts[i][c] += 1

corrected = "".join([max((ct, c) for c, ct in count.items())[1] for count in counts])
print("Part 1: {}".format(corrected))

corrected = "".join([max((-ct, c) for c, ct in count.items())[1] for count in counts])
print("Part 2: {}".format(corrected))

AOCUtils.printTimeTaken()
#######################################
# --- Day 24: Air Duct Spelunking --- #
#######################################

import AOCUtils
from collections import deque
from itertools import permutations

#######################################

ducts = AOCUtils.loadInput(24)

points = dict()
for x in range(len(ducts)):
    for y in range(len(ducts[0])):
        if ducts[x][y] in "0123456789":
            points[ducts[x][y]] = (x, y)

# Get minimum distance from all points to all points
allDistances = dict()
for a, start in points.items():
    for b, dest in points.items():
        if (b, a) in allDistances:
            allDistances[(a, b)] = allDistances[(b, a)]
            continue
        if a == b:
            allDistances[(a, b)] = 0
            continue

        queue = deque([(start, 0)])
        visited = set()
Beispiel #23
0
                if holdingWeights.count(w) == 1:  # Unique weight
                    originalWeight = w
                    originalName = name
                else:  # Other weights
                    goalWeight = w

            # Final answer, escalate to parent calls
            deltaWeight = goalWeight - originalWeight
            newWeight = programs[originalName].w + deltaWeight
            return (newWeight, None)

        # Memoize result and return
        totalWeight[p] = programs[p].w + sum(holdingWeights)
        return (None, totalWeight[p])

    return getWeights(root)[0]


###################################

programs = {}
for p in AOCUtils.loadInput(7):
    p = p.split()
    programs[p[0]] = Program(p)

root = topoSort(programs)[0]
print("Part 1: {}".format(root))

print("Part 2: {}".format(fixBalance(programs, root)))

AOCUtils.printTimeTaken()
Beispiel #24
0
#############################################
# --- Day 17: No Such Thing as Too Much --- #
#############################################

import AOCUtils
from itertools import combinations

#############################################

containers = AOCUtils.loadInput(17)
eggnog = 150

containerAmounts = []
for i in range(len(containers)+1):
    for combination in combinations(containers, i):
        if sum(combination) == eggnog:
            containerAmounts.append(i)

p1 = len(containerAmounts)
print("Part 1: {}".format(p1))

p2 = containerAmounts.count(min(containerAmounts))
print("Part 2: {}".format(p2))

AOCUtils.printTimeTaken()
Beispiel #25
0
############################
# --- Day 16: Aunt Sue --- #
############################

import AOCUtils

############################

rawAunts = AOCUtils.loadInput(16)

aunts = dict()
for rawAunt in rawAunts:
    rawAunt = rawAunt.split()

    auntID = int(rawAunt[1][:-1])
    aunt = dict()
    for i in range(2, len(rawAunt), 2):
        thing = rawAunt[i].rstrip(":")
        amount = int(rawAunt[i + 1].rstrip(","))
        aunt[thing] = amount

    aunts[auntID] = aunt

tape = {
    "children": 3,
    "cats": 7,
    "samoyeds": 2,
    "pomeranians": 3,
    "akitas": 0,
    "vizslas": 0,
    "goldfish": 5,
#################################
# --- Day 1: Not Quite Lisp --- #
#################################

import AOCUtils

#################################

directions = AOCUtils.loadInput(1)

directions = [1 if c == "(" else -1 for c in directions]

print("Part 1: {}".format(sum(directions)))

cur = 0
for i, c in enumerate(directions):
    cur += c
    if cur == -1:
        print("Part 2: {}".format(i+1))
        break

AOCUtils.printTimeTaken()
                recursiveCopy2 = list(player2)[:top2]

                score1, score2 = playGame2(recursiveCopy1, recursiveCopy2)

                p1Wins = (score1 > score2)
            else:
                p1Wins = (top1 > top2)

        if p1Wins:
            player1.append(top1)
            player1.append(top2)
        else:
            player2.append(top2)
            player2.append(top1)

    return getScore(player1), getScore(player2)


###############################

rawDecks = AOCUtils.loadInput(22)

rawPlayer1, rawPlayer2 = "\n".join(rawDecks).split("\n\n")
rawPlayer1 = [int(i) for i in rawPlayer1.split("\n")[1:]]
rawPlayer2 = [int(i) for i in rawPlayer2.split("\n")[1:]]

print("Part 1: {}".format(max(playGame1(rawPlayer1, rawPlayer2))))

print("Part 2: {}".format(max(playGame2(rawPlayer1, rawPlayer2))))

AOCUtils.printTimeTaken()
Beispiel #28
0
        for pos in active:
            for delta in moves:
                neighbor = tuple(k + d for k, d in zip(pos, delta))
                toBeUpdated.add(neighbor)

        newActive = set(active)
        for pos in toBeUpdated:
            neighbors = 0
            for delta in moves:
                neighbor = tuple(k + d for k, d in zip(pos, delta))
                neighbors += int(neighbor in active)

            if pos in active and neighbors not in [2, 3]:
                newActive.remove(pos)
            elif pos not in active and neighbors == 3:
                newActive.add(pos)

        active = newActive

    return len(active)


################################

rawGrid = AOCUtils.loadInput(17)

print("Part 1: {}".format(conwayCubes(rawGrid, 3)))

print("Part 2: {}".format(conwayCubes(rawGrid, 4)))

AOCUtils.printTimeTaken()
Beispiel #29
0
                out = ~get(cmd[1]) & 0xFFFF
            elif op == "LSHIFT":
                out = get(cmd[0]) << get(cmd[2])
            elif op == "RSHIFT":
                out = get(cmd[0]) >> get(cmd[2])
        else:
            out = get(cmd[0])

        wires[wire] = out
        return wires[wire]

    return get(wire)

#########################################

rawCommands = AOCUtils.loadInput(7)

commands = dict()
for cmd in rawCommands:
    op, out = cmd.split(" -> ")
    commands[out] = op

wires = dict()
p1 = getWire(commands, wires, "a")

print("Part 1: {}".format(p1))

wires = {"b": p1}
p2 = getWire(commands, wires, "a")

print("Part 1: {}".format(p2))
Beispiel #30
0
    def getState(self, c):
        return str([moon.getState(c) for moon in self.moons])


def lcm2(x, y):
    return abs(x * y) // gcd(x, y)


def lcmN(a):
    l = lcm2(a[0], a[1])
    for i in a[2:]:
        l = lcm2(l, i)
    return l


rawMoons = AOCUtils.loadInput(12)
moons = [Moon(rawMoon) for rawMoon in rawMoons]

system = MoonSystem(moons)
for step in range(1000):
    system.step()

print("Part 1: {}".format(system.getTotalEnergy()))
periods = [0 for _ in range(3)]
seen = [set() for _ in range(3)]

system = MoonSystem(moons)
step = 0
while not all(periods):
    for c in range(3):
        if not periods[c]: