Lint and Refactor day 1-11
This commit is contained in:
parent
5cb2dccf62
commit
051c3f3ebd
14 changed files with 422 additions and 254 deletions
|
|
@ -1,5 +1,12 @@
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def headline(n, title):
|
||||||
|
"""Print day number and name, followed by a ruler. Used by the answer decorator"""
|
||||||
|
print(f"\n--- Day {n}: {title} ---\n")
|
||||||
|
|
||||||
|
|
||||||
year = 2019
|
year = 2019
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -19,48 +26,54 @@ if day_no and name:
|
||||||
with open("output/day_{}.py".format(padded_no), "w") as s:
|
with open("output/day_{}.py".format(padded_no), "w") as s:
|
||||||
s.write(
|
s.write(
|
||||||
f"""
|
f"""
|
||||||
from output import answer, puzzleinput
|
from output import answer # , matrix, D, DD, ADJ, ints, mhd, mdbg, vdbg
|
||||||
|
|
||||||
n = {day_no}
|
n = {day_no}
|
||||||
title = "{name}"
|
title = "{name}"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "Answer is {{}}")
|
@answer(1, "Answer is {{}}")
|
||||||
def part_1(data):
|
def part_1(outputs):
|
||||||
return data
|
return outputs[0]
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "Actually, answer is {{}}")
|
@answer(2, "Actually, answer is {{}}")
|
||||||
def part_2(data):
|
def part_2(outputs):
|
||||||
return data
|
return outputs[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# use dummy data
|
# use dummy data
|
||||||
parsed = \"\"\"
|
inp = \"\"\"
|
||||||
replace me
|
replace me
|
||||||
\"\"\".strip()
|
\"\"\".strip()
|
||||||
|
|
||||||
# uncomment to instead use stdin
|
# uncomment to instead use stdin
|
||||||
# import fileinput
|
# import sys; inp = sys.stdin.read().strip()
|
||||||
# parsed = "\\n".join(list(fileinput.input()))
|
|
||||||
|
|
||||||
# uncomment to instead use content of input/{padded_no}.txt
|
# uncomment to use AoC provided puzzle input
|
||||||
# parsed = parse_input()
|
# with open("./input/{padded_no}.txt", "r") as f:
|
||||||
|
# inp = f.read().strip()
|
||||||
|
|
||||||
part_1(parsed)
|
inp = solve(inp)
|
||||||
# part_2(parsed)
|
|
||||||
|
a = part_1(inp)
|
||||||
|
# b = part_2(inp)
|
||||||
|
|
||||||
|
# uncomment and replace 0 with actual output to refactor code
|
||||||
|
# and ensure nonbreaking changes
|
||||||
|
# assert a == 0
|
||||||
|
# assert b == 0
|
||||||
""".strip()
|
""".strip()
|
||||||
+ "\n"
|
+ "\n"
|
||||||
)
|
)
|
||||||
print(f"- creating empty input/{day_no.zfill(2)}.txt")
|
print("- making sure input dir exists")
|
||||||
with open("input/{}.txt".format(day_no.zfill(2)), "w") as i:
|
if not os.path.exists("input"):
|
||||||
i.write("")
|
os.makedirs("input")
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"""
|
f"""
|
||||||
|
|
@ -75,28 +88,34 @@ https://adventofcode.com/{year}/day/{day_no}/input
|
||||||
)
|
)
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
from output import headline
|
|
||||||
|
|
||||||
stars = 0
|
stars = 0
|
||||||
for i in [str(n).zfill(2) for n in range(1, 26)]:
|
for i in [str(n).zfill(2) for n in range(1, 26)]:
|
||||||
try:
|
if not day_no or day_no.zfill(2) == i:
|
||||||
day = __import__(
|
try:
|
||||||
"output.day_{}".format(i),
|
day = __import__(
|
||||||
globals(),
|
"output.day_{}".format(i),
|
||||||
locals(),
|
globals(),
|
||||||
["n", "title", "part_1", "part_2", "parse_input"],
|
locals(),
|
||||||
0,
|
["n", "title", "part_1", "part_2", "solve"],
|
||||||
)
|
0,
|
||||||
headline(day.n, day.title)
|
)
|
||||||
data = day.parse_input()
|
with open(f"./input/{i}.txt", "r") as f:
|
||||||
day.part_1(data, decorate=True)
|
data = f.read().strip()
|
||||||
stars += 1
|
headline(day.n, day.title)
|
||||||
day.part_2(data, decorate=True)
|
try:
|
||||||
stars += 1
|
data = day.solve(data)
|
||||||
except IOError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
except ImportError:
|
if day.part_1(data, decorate=True):
|
||||||
pass
|
stars += 1
|
||||||
print(f"\nStars: {stars}")
|
if day.part_2(data, decorate=True):
|
||||||
print("".join("*" if n <= stars else "•" for n in range(50)))
|
stars += 1
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
if not day_no:
|
||||||
|
print(f"\nStars: {stars}")
|
||||||
|
print("".join("*" if n < stars else "•" for n in range(50)))
|
||||||
print("")
|
print("")
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
import functools
|
import functools
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Directions/Adjacents for 2D matrices, in the order UP, RIGHT, DOWN, LEFT
|
||||||
|
D = [
|
||||||
|
(-1, 0),
|
||||||
|
(0, 1),
|
||||||
|
(1, 0),
|
||||||
|
(0, -1),
|
||||||
|
]
|
||||||
|
|
||||||
def puzzleinput(n, **kwargs):
|
# Directions for 2D matrices, as a dict with keys U, R, D, L
|
||||||
filename = str(n).zfill(2)
|
DD = {
|
||||||
trim_input = kwargs.get("trim_input", True)
|
"U": (-1, 0),
|
||||||
filepath = f"./input/{filename}.txt"
|
"R": (0, 1),
|
||||||
|
"D": (1, 0),
|
||||||
|
"L": (0, -1),
|
||||||
|
}
|
||||||
|
|
||||||
def decorator_pi(func):
|
# Adjacent relative positions including diagonals for 2D matrices, in the order NW, N, NE, W, E, SW, S, SE
|
||||||
@functools.wraps(func)
|
ADJ = [
|
||||||
def wrapper_pi(*args, **kwargs):
|
(-1, -1),
|
||||||
with open(filepath, "r") as f:
|
(-1, 0),
|
||||||
data = f.read()
|
(1, -1),
|
||||||
if trim_input:
|
(0, -1),
|
||||||
return func(data.strip(), *args, **kwargs)
|
(0, 1),
|
||||||
return func(data, *args, **kwargs)
|
(1, 1),
|
||||||
|
(1, 0),
|
||||||
return wrapper_pi
|
(1, -1),
|
||||||
|
]
|
||||||
return decorator_pi
|
|
||||||
|
|
||||||
|
|
||||||
def answer(part_index, fmt_string):
|
def answer(part_index, fmt_string):
|
||||||
|
"""Decorator to present a solution in a human readable format"""
|
||||||
|
|
||||||
def decorator_aoc(func):
|
def decorator_aoc(func):
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper_aoc(*args, **kwargs):
|
def wrapper_aoc(*args, **kwargs):
|
||||||
|
|
@ -32,7 +44,7 @@ def answer(part_index, fmt_string):
|
||||||
print(answer)
|
print(answer)
|
||||||
else:
|
else:
|
||||||
formatted = fmt_string.format(answer)
|
formatted = fmt_string.format(answer)
|
||||||
print(f"[part {part_index}] {formatted}")
|
print(f" {part_index}) {formatted}")
|
||||||
return answer
|
return answer
|
||||||
|
|
||||||
return wrapper_aoc
|
return wrapper_aoc
|
||||||
|
|
@ -40,6 +52,31 @@ def answer(part_index, fmt_string):
|
||||||
return decorator_aoc
|
return decorator_aoc
|
||||||
|
|
||||||
|
|
||||||
def headline(n, title):
|
def ints(s):
|
||||||
title = f"Day {n}: {title}"
|
"""Extract all integers from a string"""
|
||||||
print("\n".join(["", title, "".join("-" for _ in title), ""]))
|
return [int(n) for n in re.findall(r"\d+", s)]
|
||||||
|
|
||||||
|
|
||||||
|
def mhd(a, b):
|
||||||
|
"""Calculates the Manhattan distance between 2 positions in the format (y, x) or (x, y)"""
|
||||||
|
ar, ac = a
|
||||||
|
br, bc = b
|
||||||
|
return abs(ar - br) + abs(ac - bc)
|
||||||
|
|
||||||
|
|
||||||
|
def matrix(d):
|
||||||
|
"""Transform a string into an iterable matrix. Returns the matrix, row count and col count"""
|
||||||
|
m = [tuple(r) for r in d.split()]
|
||||||
|
return m, len(m), len(m[0])
|
||||||
|
|
||||||
|
|
||||||
|
def mdbg(m):
|
||||||
|
"""Print-debug a matrix"""
|
||||||
|
for r in m:
|
||||||
|
print("".join(r))
|
||||||
|
|
||||||
|
|
||||||
|
def vdbg(seen, h, w):
|
||||||
|
"""Print-debug visited positions of a matrix"""
|
||||||
|
for r in range(h):
|
||||||
|
print("".join(["#" if (r, c) in seen else "." for c in range(w)]))
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,40 @@
|
||||||
from output import answer, puzzleinput
|
from output import answer
|
||||||
|
|
||||||
n = 1
|
n = 1
|
||||||
title = "The Tyranny of the Rocket Equation"
|
title = "The Tyranny of the Rocket Equation"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return list(map(int, data.split()))
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "Total fuel requirements are {}")
|
@answer(1, "Total fuel requirements are {}")
|
||||||
def part_1(lines):
|
def part_1(o):
|
||||||
return sum(n // 3 - 2 for n in lines)
|
return o[0]
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "Total fuel requirements are {} including fuel costs")
|
@answer(2, "Total fuel requirements are {} including fuel costs")
|
||||||
def part_2(lines):
|
def part_2(o):
|
||||||
s = 0
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
lines = list(map(int, data.split()))
|
||||||
|
p1 = sum(n // 3 - 2 for n in lines)
|
||||||
|
p2 = 0
|
||||||
for fuel in lines:
|
for fuel in lines:
|
||||||
rem = fuel
|
rem = fuel
|
||||||
while rem > 0:
|
while rem > 0:
|
||||||
cost = rem // 3 - 2
|
cost = rem // 3 - 2
|
||||||
s += max(0, cost)
|
p2 += max(0, cost)
|
||||||
rem = max(0, cost)
|
rem = max(0, cost)
|
||||||
return s
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/01.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 3393938
|
||||||
|
assert b == 5088037
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,48 @@
|
||||||
from output import answer, puzzleinput
|
from output import answer
|
||||||
|
|
||||||
from output.intcode_computer import execute, parse
|
from output.intcode_computer import execute, parse
|
||||||
|
|
||||||
n = 2
|
n = 2
|
||||||
title = "1202 Program Alarm"
|
title = "1202 Program Alarm"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return parse(data)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "[intcode-0.1.0] Value of pos 0 is {} at halt signal")
|
@answer(1, "[intcode-0.1.0] Value of pos 0 is {} at halt signal")
|
||||||
def part_1(program):
|
def part_1(o):
|
||||||
program[1] = 12
|
return o[0]
|
||||||
program[2] = 2
|
|
||||||
_code, state, *_unused = execute(program)
|
|
||||||
return state[0]
|
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "[intcode-0.1.1] 100 * noun + verb = {} for output 19690720")
|
@answer(2, "[intcode-0.1.1] 100 * noun + verb = {} for output 19690720")
|
||||||
def part_2(program, noun=76, verb=21):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
program = parse(data)
|
||||||
|
|
||||||
|
program[1] = 12
|
||||||
|
program[2] = 2
|
||||||
|
_code, state, *_unused = execute(program)
|
||||||
|
noun = 76 # found manually by binary search
|
||||||
|
verb = 21
|
||||||
|
p1 = state[0]
|
||||||
|
|
||||||
program[1] = noun
|
program[1] = noun
|
||||||
program[2] = verb
|
program[2] = verb
|
||||||
_code, state, *_unused = execute(program)
|
_code, state, *_unused = execute(program)
|
||||||
|
p2 = state[0]
|
||||||
if state[0] == 19690720:
|
if state[0] == 19690720:
|
||||||
return 100 * noun + verb
|
p2 = 100 * noun + verb
|
||||||
return state[0]
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/02.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed, 76, 21) # found manually by binary search
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 3306701
|
||||||
|
assert b == 7621
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
from output import answer
|
||||||
|
|
||||||
n = 3
|
n = 3
|
||||||
title = "Crossed Wires"
|
title = "Crossed Wires"
|
||||||
|
|
@ -12,37 +13,24 @@ directions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return [line.split(",") for line in data.split()]
|
|
||||||
|
|
||||||
|
|
||||||
@answer(
|
@answer(
|
||||||
1, "As the crow flies, closest intersection Manhattan distance is {} units away"
|
1, "As the crow flies, closest intersection Manhattan distance is {} units away"
|
||||||
)
|
)
|
||||||
def part_1(wires):
|
def part_1(o):
|
||||||
def follow(instructions):
|
return o[0]
|
||||||
seen = []
|
|
||||||
pos = (0, 0)
|
|
||||||
for instruction in instructions:
|
|
||||||
urdl, *l = instruction
|
|
||||||
distance = int("".join(l))
|
|
||||||
for _ in range(distance):
|
|
||||||
pos = (pos[0] + directions[urdl][0], pos[1] + directions[urdl][1])
|
|
||||||
seen.append(pos)
|
|
||||||
return set(seen)
|
|
||||||
|
|
||||||
wa = follow(wires[0])
|
|
||||||
wb = follow(wires[1])
|
|
||||||
|
|
||||||
return min(sum(map(abs, i)) for i in wa & wb)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "By travel, closest intersection Manhattan distance is {} units away")
|
@answer(2, "By travel, closest intersection Manhattan distance is {} units away")
|
||||||
def part_2(wires):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(inp):
|
||||||
|
wires = [line.split(",") for line in inp.split()]
|
||||||
seen = defaultdict(dict)
|
seen = defaultdict(dict)
|
||||||
|
|
||||||
def follow(instructions, i):
|
def follow(instructions, i):
|
||||||
|
visited = []
|
||||||
steps = 0
|
steps = 0
|
||||||
pos = (0, 0)
|
pos = (0, 0)
|
||||||
for instruction in instructions:
|
for instruction in instructions:
|
||||||
|
|
@ -51,16 +39,29 @@ def part_2(wires):
|
||||||
for _ in range(distance):
|
for _ in range(distance):
|
||||||
steps += 1
|
steps += 1
|
||||||
pos = (pos[0] + directions[urdl][0], pos[1] + directions[urdl][1])
|
pos = (pos[0] + directions[urdl][0], pos[1] + directions[urdl][1])
|
||||||
|
visited.append(pos)
|
||||||
if i not in seen[pos]:
|
if i not in seen[pos]:
|
||||||
seen[pos][i] = steps
|
seen[pos][i] = steps
|
||||||
|
return set(visited)
|
||||||
|
|
||||||
|
p1w = []
|
||||||
for i, wire in enumerate(wires):
|
for i, wire in enumerate(wires):
|
||||||
follow(wire, i)
|
p1w.append(follow(wire, i))
|
||||||
|
p1 = min(sum(map(abs, i)) for i in p1w[0] & p1w[1])
|
||||||
|
|
||||||
return min(sum(v.values()) for v in seen.values() if len(v) > 1)
|
p2 = min(sum(v.values()) for v in seen.values() if len(v) > 1)
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/03.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 1337
|
||||||
|
assert b == 65356
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,44 @@
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
from output import answer
|
||||||
|
|
||||||
n = 4
|
n = 4
|
||||||
title = "Secure Container"
|
title = "Secure Container"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return data.split("-")
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "{} combinations of valid passwords")
|
@answer(1, "{} combinations of valid passwords")
|
||||||
def part_1(range_values):
|
def part_1(o):
|
||||||
a, b = range_values
|
return o[0]
|
||||||
|
|
||||||
def valid(s):
|
|
||||||
return "".join(sorted(s)) == s and any(x == y for x, y in zip(s, s[1:]))
|
|
||||||
|
|
||||||
return sum(valid(str(pw)) for pw in range(int(a), int(b) + 1))
|
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "{} combinations of valid passwords, including important detail")
|
@answer(2, "{} combinations of valid passwords, including important detail")
|
||||||
def part_2(range_values):
|
def part_2(o):
|
||||||
a, b = range_values
|
return o[1]
|
||||||
|
|
||||||
def valid(s):
|
|
||||||
|
def solve(data):
|
||||||
|
a, b = data.split("-")
|
||||||
|
|
||||||
|
def v1(s):
|
||||||
|
return "".join(sorted(s)) == s and any(x == y for x, y in zip(s, s[1:]))
|
||||||
|
|
||||||
|
def v2(s):
|
||||||
return "".join(sorted(s)) == s and 2 in Counter(s).values()
|
return "".join(sorted(s)) == s and 2 in Counter(s).values()
|
||||||
|
|
||||||
return sum(valid(str(pw)) for pw in range(int(a), int(b) + 1))
|
p1 = sum(v1(str(pw)) for pw in range(int(a), int(b) + 1))
|
||||||
|
p2 = sum(v2(str(pw)) for pw in range(int(a), int(b) + 1))
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/04.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 544
|
||||||
|
assert b == 334
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,40 @@
|
||||||
from output import answer, puzzleinput
|
from output import answer
|
||||||
|
|
||||||
from output.intcode_computer import execute, parse
|
from output.intcode_computer import execute, parse
|
||||||
|
|
||||||
n = 5
|
n = 5
|
||||||
title = "Sunny with a Chance of Asteroids"
|
title = "Sunny with a Chance of Asteroids"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return parse(data)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "[intcode-0.2.0] Program diagnostic code, ID 1: {}")
|
@answer(1, "[intcode-0.2.0] Program diagnostic code, ID 1: {}")
|
||||||
def part_1(program):
|
def part_1(o):
|
||||||
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[1])
|
return o[0]
|
||||||
return max(stdout)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "[intcode-0.2.1] Program diagnostic code, ID 5: {}")
|
@answer(2, "[intcode-0.2.1] Program diagnostic code, ID 5: {}")
|
||||||
def part_2(program):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
program = parse(data)
|
||||||
|
|
||||||
|
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[1])
|
||||||
|
p1 = max(stdout)
|
||||||
|
|
||||||
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[5])
|
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[5])
|
||||||
return stdout[0]
|
p2 = stdout[0]
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/05.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 16434972
|
||||||
|
assert b == 16694270
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,40 @@
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
from output import answer
|
||||||
|
|
||||||
n = 6
|
n = 6
|
||||||
title = "Universal Orbit Map"
|
title = "Universal Orbit Map"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
heritage = defaultdict(str)
|
|
||||||
for parent, child in [line.split(")") for line in data.split()]:
|
|
||||||
heritage[child] = parent
|
|
||||||
return heritage
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "{} direct and indirect orbits")
|
@answer(1, "{} direct and indirect orbits")
|
||||||
def part_1(heritage):
|
def part_1(o):
|
||||||
return sum(len(ancestry(heritage, v)) for v in heritage.keys())
|
return o[0]
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "Orbit transfers needed for you to share orbit with Santa: {}")
|
@answer(2, "Orbit transfers needed for you to share orbit with Santa: {}")
|
||||||
def part_2(heritage):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
heritage = defaultdict(str)
|
||||||
|
for parent, child in [line.split(")") for line in data.split()]:
|
||||||
|
heritage[child] = parent
|
||||||
|
|
||||||
|
p1 = sum(len(ancestry(heritage, v)) for v in heritage.keys())
|
||||||
|
|
||||||
a = ancestry(heritage, "YOU")
|
a = ancestry(heritage, "YOU")
|
||||||
b = ancestry(heritage, "SAN")
|
b = ancestry(heritage, "SAN")
|
||||||
shared = len(set(a) & set(b))
|
shared = len(set(a) & set(b))
|
||||||
return sum(
|
p2 = sum(
|
||||||
[
|
[
|
||||||
len(a) - shared,
|
len(a) - shared,
|
||||||
len(b) - shared,
|
len(b) - shared,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
def ancestry(parents, child):
|
def ancestry(parents, child):
|
||||||
k = child
|
k = child
|
||||||
|
|
@ -41,6 +46,13 @@ def ancestry(parents, child):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/06.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 271151
|
||||||
|
assert b == 388
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,32 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from itertools import permutations
|
from itertools import permutations
|
||||||
|
|
||||||
from output import answer, puzzleinput
|
from output import answer
|
||||||
from output.intcode_computer import execute, parse
|
from output.intcode_computer import execute, parse
|
||||||
|
|
||||||
n = 7
|
n = 7
|
||||||
title = "Amplification Circuit"
|
title = "Amplification Circuit"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return parse(data)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(
|
@answer(
|
||||||
1,
|
1,
|
||||||
"[intcode 0.3.0] The highest achievable signal to the thruster is {}",
|
"[intcode 0.3.0] The highest achievable signal to the thruster is {}",
|
||||||
)
|
)
|
||||||
def part_1(program):
|
def part_1(o):
|
||||||
|
return o[0]
|
||||||
|
|
||||||
|
|
||||||
|
@answer(
|
||||||
|
2,
|
||||||
|
"[intcode 0.3.0] By creating a feedback loop, the highest achievable signal to the thruster is {}",
|
||||||
|
)
|
||||||
|
def part_2(o):
|
||||||
|
return o[0]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
program = parse(data)
|
||||||
|
|
||||||
thruster_signals = []
|
thruster_signals = []
|
||||||
for settings in map(list, permutations(range(5))):
|
for settings in map(list, permutations(range(5))):
|
||||||
o = 0
|
o = 0
|
||||||
|
|
@ -25,14 +34,8 @@ def part_1(program):
|
||||||
_code, _state, _n, _rb, so = execute(program, stdin=[ps, o])
|
_code, _state, _n, _rb, so = execute(program, stdin=[ps, o])
|
||||||
o = so.pop(0)
|
o = so.pop(0)
|
||||||
thruster_signals.append(o)
|
thruster_signals.append(o)
|
||||||
return max(thruster_signals)
|
p1 = max(thruster_signals)
|
||||||
|
|
||||||
|
|
||||||
@answer(
|
|
||||||
2,
|
|
||||||
"[intcode 0.3.0] By creating a feedback loop, the highest achievable signal to the thruster is {}",
|
|
||||||
)
|
|
||||||
def part_2(program):
|
|
||||||
thruster_signals = []
|
thruster_signals = []
|
||||||
for settings in map(list, permutations(range(5, 10))):
|
for settings in map(list, permutations(range(5, 10))):
|
||||||
o = [0]
|
o = [0]
|
||||||
|
|
@ -56,10 +59,19 @@ def part_2(program):
|
||||||
finished.add(amp)
|
finished.add(amp)
|
||||||
o = so
|
o = so
|
||||||
thruster_signals.append(o[-1])
|
thruster_signals.append(o[-1])
|
||||||
return max(thruster_signals)
|
p2 = max(thruster_signals)
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/07.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 398674
|
||||||
|
assert b == 39431233
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,50 @@
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from textwrap import wrap
|
from textwrap import wrap
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
from output import answer
|
||||||
|
|
||||||
n = 8
|
n = 8
|
||||||
title = "Space Image Format"
|
title = "Space Image Format"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "The product of all 1s and 2s in the layer with fewest 0s is {}")
|
@answer(1, "The product of all 1s and 2s in the layer with fewest 0s is {}")
|
||||||
def part_1(data):
|
def part_1(o):
|
||||||
|
return o[0]
|
||||||
|
|
||||||
|
|
||||||
|
@answer(2, "The message is {}, the decoded image looks like above")
|
||||||
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
layers = sorted(map(Counter, wrap(data, 25 * 6)), key=lambda c: c["0"])
|
layers = sorted(map(Counter, wrap(data, 25 * 6)), key=lambda c: c["0"])
|
||||||
|
width, height = 25, 6
|
||||||
a = layers[0]["1"]
|
a = layers[0]["1"]
|
||||||
b = layers[0]["2"]
|
b = layers[0]["2"]
|
||||||
return a * b
|
p1 = a * b
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "The message is CYUAH, the decoded image looks like this:\n\n{}")
|
|
||||||
def part_2(data, width=25, height=6):
|
|
||||||
layers = wrap(data, width * height)
|
layers = wrap(data, width * height)
|
||||||
l = len(layers)
|
|
||||||
pixels = zip(*layers)
|
pixels = zip(*layers)
|
||||||
lit = map(
|
lit = map(
|
||||||
lambda s: s.replace("0", ".").replace("1", "#"),
|
lambda s: s.replace("0", ".").replace("1", "#"),
|
||||||
map(lambda p: next(filter(lambda x: x != "2", p)), pixels),
|
map(lambda p: next(filter(lambda x: x != "2", p)), pixels),
|
||||||
)
|
)
|
||||||
matrix = "\n".join(wrap("".join(lit), width))
|
matrix = "\n".join(wrap("".join(lit), width))
|
||||||
return matrix
|
print(matrix)
|
||||||
|
p2 = "CYUAH"
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/08.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 2500
|
||||||
|
assert b == "CYUAH"
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
from output import answer, puzzleinput
|
from output import answer
|
||||||
from output.intcode_computer import execute, parse
|
from output.intcode_computer import execute, parse
|
||||||
|
|
||||||
n = 9
|
n = 9
|
||||||
title = "Sensor Boost"
|
title = "Sensor Boost"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return parse(data)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "[intcode 0.3.1] BOOST keycode: {}")
|
@answer(1, "[intcode 0.3.1] BOOST keycode: {}")
|
||||||
def part_1(program):
|
def part_1(o):
|
||||||
_c, _s, _n, _rb, outputs = execute(program, stdin=[1])
|
return o[0]
|
||||||
return outputs.pop(0)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "[intcode 0.3.1] Distress signal coordinates: {}")
|
@answer(2, "[intcode 0.3.1] Distress signal coordinates: {}")
|
||||||
def part_2(program):
|
def part_2(o):
|
||||||
_c, _s, _n, _rb, outputs = execute(program, stdin=[2])
|
return o[1]
|
||||||
return outputs.pop(0)
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
program = parse(data)
|
||||||
|
p12 = []
|
||||||
|
for inp in [1, 2]:
|
||||||
|
_c, _s, _n, _rb, outputs = execute(program, stdin=[inp])
|
||||||
|
p12.append(outputs.pop(0))
|
||||||
|
return p12
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
@ -72,8 +74,13 @@ if __name__ == "__main__":
|
||||||
assert execute([109, 1, 203, 2, 204, 2, 99], stdin=[666])[4][0] == 666
|
assert execute([109, 1, 203, 2, 204, 2, 99], stdin=[666])[4][0] == 666
|
||||||
assert execute([109, 6, 21001, 9, 25, 1, 104, 0, 99, 49])[4][0] == 74
|
assert execute([109, 6, 21001, 9, 25, 1, 104, 0, 99, 49])[4][0] == 74
|
||||||
|
|
||||||
parsed = parse_input()
|
with open("./input/09.txt", "r") as f:
|
||||||
assert execute(parsed, stdin=[1])[4][0] == 2351176124
|
inp = f.read().strip()
|
||||||
|
|
||||||
part_1(parsed)
|
inp = solve(inp)
|
||||||
part_2(parsed)
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 2351176124
|
||||||
|
assert b == 73110
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,31 @@
|
||||||
from collections import OrderedDict, defaultdict, deque
|
from collections import OrderedDict, defaultdict, deque
|
||||||
from math import atan2
|
from math import atan2
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
from output import answer
|
||||||
|
|
||||||
n = 10
|
n = 10
|
||||||
title = "Monitoring Station"
|
title = "Monitoring Station"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return data.strip().split()
|
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "The monitor station will see {} asteroids at best")
|
@answer(1, "The monitor station will see {} asteroids at best")
|
||||||
def part_1(matrix):
|
def part_1(o):
|
||||||
_pos, visible = _map_visible_asteroids(matrix)
|
return o[0]
|
||||||
return len(set(dict(visible).values()))
|
|
||||||
|
|
||||||
|
|
||||||
@answer(
|
@answer(
|
||||||
2,
|
2,
|
||||||
"The asteroid at y=3 x=17 (checksum {}) will be the 200th lazer vapored asteroid, making some elf happy",
|
"The asteroid at y=3 x=17 (checksum {}) will be the 200th lazer vapored asteroid, making some elf happy",
|
||||||
)
|
)
|
||||||
def part_2(matrix):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
matrix = data.strip().split()
|
||||||
pos, visible = _map_visible_asteroids(matrix)
|
pos, visible = _map_visible_asteroids(matrix)
|
||||||
|
|
||||||
|
p1 = len(set(dict(visible).values()))
|
||||||
|
|
||||||
targets_upper = defaultdict(list)
|
targets_upper = defaultdict(list)
|
||||||
targets_lower = defaultdict(list)
|
targets_lower = defaultdict(list)
|
||||||
targets = dict()
|
targets = dict()
|
||||||
|
|
@ -58,7 +61,10 @@ def part_2(matrix):
|
||||||
break
|
break
|
||||||
if not popped:
|
if not popped:
|
||||||
break
|
break
|
||||||
return x * 100 + y
|
|
||||||
|
p2 = x * 100 + y
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
def _map_visible_asteroids(matrix):
|
def _map_visible_asteroids(matrix):
|
||||||
|
|
@ -78,6 +84,13 @@ def _map_visible_asteroids(matrix):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/10.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed)
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 292
|
||||||
|
assert b == 317
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from output import answer
|
||||||
from output.intcode_computer import execute, parse
|
from output.intcode_computer import execute, parse
|
||||||
from output import answer, puzzleinput
|
|
||||||
|
|
||||||
n = 11
|
n = 11
|
||||||
title = "Space Police"
|
title = "Space Police"
|
||||||
|
|
||||||
|
|
||||||
@puzzleinput(n)
|
|
||||||
def parse_input(data):
|
|
||||||
return parse(data)
|
|
||||||
|
|
||||||
|
|
||||||
DIRS = [
|
DIRS = [
|
||||||
(-1, 0),
|
(-1, 0),
|
||||||
(0, -1),
|
(0, -1),
|
||||||
|
|
@ -26,18 +22,28 @@ TL = ["RIGHT", "LEFT"]
|
||||||
|
|
||||||
|
|
||||||
@answer(1, "[intcode 0.3.2] Robot paints {} panes at least once")
|
@answer(1, "[intcode 0.3.2] Robot paints {} panes at least once")
|
||||||
def part_1(program):
|
def part_1(o):
|
||||||
path, pos, d = _paint(program)
|
return o[0]
|
||||||
return len(path)
|
|
||||||
|
|
||||||
|
|
||||||
@answer(
|
@answer(
|
||||||
2,
|
2,
|
||||||
'[intcode 0.3.2] The hull has registration identifier "JZPJRAGJ" freshly painted, see below: \n\n{}',
|
'[intcode 0.3.2] The hull has registration identifier "{}" freshly painted, see above',
|
||||||
)
|
)
|
||||||
def part_2(program):
|
def part_2(o):
|
||||||
|
return o[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
program = parse(data)
|
||||||
|
path, pos, d = _paint(program)
|
||||||
|
p1 = len(path)
|
||||||
|
|
||||||
path, pos, d = _paint(program, 1)
|
path, pos, d = _paint(program, 1)
|
||||||
return _inspect(path.copy(), pos, d)
|
print(_inspect(path.copy(), pos, d))
|
||||||
|
p2 = "JZPJRAGJ"
|
||||||
|
|
||||||
|
return p1, p2
|
||||||
|
|
||||||
|
|
||||||
def _paint(program, initial=0):
|
def _paint(program, initial=0):
|
||||||
|
|
@ -77,6 +83,13 @@ def _inspect(path, p, d):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parsed = parse_input()
|
with open("./input/11.txt", "r") as f:
|
||||||
part_1(parsed)
|
inp = f.read().strip()
|
||||||
part_2(parsed) # JZPJRAGJ
|
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
b = part_2(inp)
|
||||||
|
|
||||||
|
assert a == 2720
|
||||||
|
assert b == "JZPJRAGJ"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
import sys
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
sys.set_int_max_str_digits(999_999)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
intcode computer, AoC 2019
|
intcode computer, AoC 2019
|
||||||
|
|
@ -91,7 +93,7 @@ __version__ = "0.3.3"
|
||||||
|
|
||||||
|
|
||||||
def parse(data):
|
def parse(data):
|
||||||
return list(map(int, data.split(",")))
|
return [int(s) for s in data.split(",")]
|
||||||
|
|
||||||
|
|
||||||
def execute(
|
def execute(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue