Added days 2-11
parent
8e83278b02
commit
71fa1a9cd3
|
@ -0,0 +1,47 @@
|
||||||
|
from lib import format_main
|
||||||
|
from itertools import product
|
||||||
|
from operator import mul, add
|
||||||
|
|
||||||
|
def primitive(operator):
|
||||||
|
def opcode(program, i):
|
||||||
|
val = lambda x: program[program[x]]
|
||||||
|
program[program[i+3]] = operator(val(i+1), val(i+2))
|
||||||
|
return i+4
|
||||||
|
return opcode
|
||||||
|
|
||||||
|
opcodes = {1 : primitive(add),
|
||||||
|
2 : primitive(mul),
|
||||||
|
99 : lambda p, i: len(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
def interpret(program):
|
||||||
|
i = 0
|
||||||
|
while i < len(program):
|
||||||
|
op = program[i]
|
||||||
|
i = opcodes[op](program, i)
|
||||||
|
return program
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
program = list(map(int, puzzle_input.split(',')))
|
||||||
|
init_prog = lambda a,b: program[:1] + [a, b] + program[3:]
|
||||||
|
return init_prog
|
||||||
|
|
||||||
|
|
||||||
|
def partI(init_prog):
|
||||||
|
end_state = interpret(init_prog(12, 2))
|
||||||
|
return end_state[0]
|
||||||
|
|
||||||
|
def partII(init_prog):
|
||||||
|
target = 19690720
|
||||||
|
space = 2 * list(range(100))
|
||||||
|
for noun, verb in product(space, space):
|
||||||
|
memory = init_prog(noun, verb)
|
||||||
|
end_state = interpret(memory)
|
||||||
|
if end_state[0] == target:
|
||||||
|
break
|
||||||
|
|
||||||
|
return 100*noun + verb
|
||||||
|
|
||||||
|
import solver
|
|
@ -0,0 +1,80 @@
|
||||||
|
up = lambda v: (v[0], v[1] + 1)
|
||||||
|
down = lambda v: (v[0], v[1] - 1)
|
||||||
|
left = lambda v: (v[0] - 1, v[1])
|
||||||
|
right = lambda v: (v[0] + 1, v[1])
|
||||||
|
|
||||||
|
moves = {'U' : up,
|
||||||
|
'D' : down,
|
||||||
|
'L' : left,
|
||||||
|
'R' : right
|
||||||
|
}
|
||||||
|
|
||||||
|
def memoize(f):
|
||||||
|
cache = dict()
|
||||||
|
def memf(path):
|
||||||
|
if path not in cache:
|
||||||
|
cache[path] = f(path)
|
||||||
|
return cache[path]
|
||||||
|
return memf
|
||||||
|
|
||||||
|
def iterate(f, x, N):
|
||||||
|
for i in range(N):
|
||||||
|
yield x
|
||||||
|
x = f(x)
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def lines(path):
|
||||||
|
pos = (0, 0)
|
||||||
|
r = []
|
||||||
|
for move in path.split(','):
|
||||||
|
dir, steps = move[0], int(move[1:])
|
||||||
|
line = list(iterate(moves[dir], pos, steps+1))
|
||||||
|
r.append(line)
|
||||||
|
pos = line[-1]
|
||||||
|
return r
|
||||||
|
|
||||||
|
def coordinates(path, corners=True):
|
||||||
|
return sum((line[1:len(line) - 1 + corners]
|
||||||
|
for line in lines(path)), [])
|
||||||
|
|
||||||
|
def crossings(*paths):
|
||||||
|
return set.intersection(*(set(coordinates(path, corners=False))
|
||||||
|
for path in paths))
|
||||||
|
|
||||||
|
def min_crossing(path1, path2, f):
|
||||||
|
return min(f(v) for v in crossings(path1, path2))
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return puzzle_input.split()
|
||||||
|
|
||||||
|
def partI(paths):
|
||||||
|
key = lambda v: abs(v[0]) + abs(v[1])
|
||||||
|
|
||||||
|
path1, path2 = paths
|
||||||
|
return min_crossing(path1, path2, key)
|
||||||
|
|
||||||
|
def partII(paths):
|
||||||
|
path1, path2 = paths
|
||||||
|
def key(c1, c2):
|
||||||
|
r = lambda v: c1.index(v) + c2.index(v) + 2
|
||||||
|
return r
|
||||||
|
|
||||||
|
def min_steps(p1, p2):
|
||||||
|
c1, c2 = coordinates(p1), coordinates(p2)
|
||||||
|
return min_crossing(p1, p2, key(c1, c2))
|
||||||
|
|
||||||
|
return min_steps(path1, path2)
|
||||||
|
|
||||||
|
import solver
|
||||||
|
|
||||||
|
tests = solver.Tests()
|
||||||
|
tests.add("R75,D30,R83,U83,L12,D49,R71,U7,L72\n" +
|
||||||
|
"U62,R66,U55,R34,D71,R55,D58,R83",
|
||||||
|
partI=159,
|
||||||
|
partII=610)
|
||||||
|
|
||||||
|
tests.add("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\n" +
|
||||||
|
"U98,R91,D20,R16,D67,R40,U7,R15,U6,R7",
|
||||||
|
partI=135,
|
||||||
|
partII=410)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
space = tuple(map(int, puzzle_input.split('-')))
|
||||||
|
cands = []
|
||||||
|
for i in range(*space):
|
||||||
|
digs = str(i)
|
||||||
|
|
||||||
|
if sorted(digs) != list(digs):
|
||||||
|
continue
|
||||||
|
if max(digs.count(d) for d in set(digs)) < 2:
|
||||||
|
continue
|
||||||
|
cands.append(i)
|
||||||
|
return cands
|
||||||
|
|
||||||
|
def partI(cands):
|
||||||
|
return len(cands)
|
||||||
|
|
||||||
|
def partII(cands):
|
||||||
|
c = 0
|
||||||
|
for i in cands:
|
||||||
|
digs = str(i)
|
||||||
|
if 2 in [digs.count(d) for d in set(digs)]:
|
||||||
|
c += 1
|
||||||
|
return c
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from intcode import Interpreter, SingletonIO
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return list(map(int, puzzle_input.split(',')))
|
||||||
|
|
||||||
|
def partI(program):
|
||||||
|
return Interpreter(program, SingletonIO).run(1)
|
||||||
|
|
||||||
|
def partII(program):
|
||||||
|
return Interpreter(program, SingletonIO).run(5)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
from lib import Graph
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
graph = Graph()
|
||||||
|
for line in puzzle_input.split('\n'):
|
||||||
|
sun, planet = line.split(')')
|
||||||
|
graph.add_edge(sun, planet)
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def partI(graph):
|
||||||
|
return sum(w for node, w in graph.min_paths("COM").items())
|
||||||
|
|
||||||
|
def partII(graph):
|
||||||
|
return graph.min_path("SAN", "YOU") - 2
|
||||||
|
|
||||||
|
import solver
|
||||||
|
|
||||||
|
tests = solver.Tests()
|
||||||
|
tests.add("""COM)B
|
||||||
|
B)C
|
||||||
|
C)D
|
||||||
|
D)E
|
||||||
|
E)F
|
||||||
|
B)G
|
||||||
|
G)H
|
||||||
|
D)I
|
||||||
|
E)J
|
||||||
|
J)K
|
||||||
|
K)L""", partI=42)
|
||||||
|
|
||||||
|
tests.add("""COM)B
|
||||||
|
B)C
|
||||||
|
C)D
|
||||||
|
D)E
|
||||||
|
E)F
|
||||||
|
B)G
|
||||||
|
G)H
|
||||||
|
D)I
|
||||||
|
E)J
|
||||||
|
J)K
|
||||||
|
K)L
|
||||||
|
K)YOU
|
||||||
|
I)SAN""", partII=4)
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
from lib import format_main
|
||||||
|
from intcode import Interpreter, makeIO, Singleton
|
||||||
|
from itertools import permutations
|
||||||
|
|
||||||
|
stack_size = 5
|
||||||
|
fst_amp_input = 0
|
||||||
|
|
||||||
|
IO = makeIO(list, Singleton)
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
program = list(map(int, puzzle_input.split(',')))
|
||||||
|
amp = lambda : Interpreter(program, IO)
|
||||||
|
return amp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def partI(amp):
|
||||||
|
phase_range = range(stack_size)
|
||||||
|
best = 0
|
||||||
|
|
||||||
|
for perm in permutations(phase_range):
|
||||||
|
amp_in = fst_amp_input
|
||||||
|
for phase in perm:
|
||||||
|
amp_in = amp().run([phase, amp_in])
|
||||||
|
best = max(amp_in, best)
|
||||||
|
return best
|
||||||
|
|
||||||
|
def partII(amp):
|
||||||
|
phase_range = range(5, 10)
|
||||||
|
best = 0
|
||||||
|
|
||||||
|
for perm in permutations(phase_range):
|
||||||
|
amps = [amp() for _ in range(stack_size)]
|
||||||
|
for p, a in zip(perm, amps):
|
||||||
|
a.write([p])
|
||||||
|
next(a)
|
||||||
|
|
||||||
|
amp_in = fst_amp_input
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
for a in amps:
|
||||||
|
a.write([amp_in])
|
||||||
|
amp_in = next(a)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
best = max(amp_in, best)
|
||||||
|
|
||||||
|
return best
|
||||||
|
|
||||||
|
import solver
|
||||||
|
|
||||||
|
tests = solver.Tests()
|
||||||
|
|
||||||
|
tests.add(
|
||||||
|
"3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0", partI=43210)
|
||||||
|
|
||||||
|
tests.add(
|
||||||
|
"3,23,3,24,1002,24,10,24,1002,23,-1,23," +
|
||||||
|
"101,5,23,23,1,24,23,23,4,23,99,0,0", partI=54321)
|
||||||
|
|
||||||
|
tests.add(
|
||||||
|
"3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33," +
|
||||||
|
"1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0", partI=65210)
|
||||||
|
|
||||||
|
tests.add(
|
||||||
|
"3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26," +
|
||||||
|
"27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5", partII=139629729)
|
||||||
|
|
||||||
|
tests.add(
|
||||||
|
"3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54," +
|
||||||
|
"-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4," +
|
||||||
|
"53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10", partII=18216)
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
ZERO, ONE, TWO = "012"
|
||||||
|
|
||||||
|
BLACK = 0
|
||||||
|
WHITE = 1
|
||||||
|
|
||||||
|
color = {WHITE : u"\u2B1C",
|
||||||
|
BLACK : u"\u2B1B"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Image:
|
||||||
|
def __init__(self, data, w, h):
|
||||||
|
self.data = data
|
||||||
|
self.w = w
|
||||||
|
self.h = h
|
||||||
|
|
||||||
|
def layers(self):
|
||||||
|
w, h = self.w, self.h
|
||||||
|
return (self.data[i:i+w*h] for i in range(0, len(self.data), w*h))
|
||||||
|
|
||||||
|
def image(self):
|
||||||
|
final = str()
|
||||||
|
for stack in zip(*self.layers()):
|
||||||
|
final += (''.join(stack).replace(TWO, "") + TWO)[0]
|
||||||
|
return final
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
w, image = self.w, self.image()
|
||||||
|
return '\n'.join(image[i:i+w] for i in range(0, len(image), w))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self).replace(ZERO, color[BLACK]).replace(ONE, color[WHITE])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
w, h = 25, 6
|
||||||
|
data = puzzle_input.replace('\n', '')
|
||||||
|
return Image(data, w, h)
|
||||||
|
|
||||||
|
def partI(image):
|
||||||
|
layer = min(image.layers(), key=lambda ly: ly.count(ZERO))
|
||||||
|
return layer.count(ONE) * layer.count(TWO)
|
||||||
|
|
||||||
|
def partII(image):
|
||||||
|
return '\n' + str(image)
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
from intcode import Interpreter, SingletonIO
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return list(map(int, puzzle_input.split(',')))
|
||||||
|
|
||||||
|
def partI(program):
|
||||||
|
return Interpreter(program, SingletonIO).run(1)
|
||||||
|
|
||||||
|
def partII(program):
|
||||||
|
return Interpreter(program, SingletonIO).run(2)
|
||||||
|
|
||||||
|
import solver
|
||||||
|
|
||||||
|
tests = solver.Tests()
|
||||||
|
tests.add("104,1125899906842624,99", partI=1125899906842624)
|
|
@ -0,0 +1,146 @@
|
||||||
|
from fractions import gcd, Fraction
|
||||||
|
from itertools import product
|
||||||
|
from functools import total_ordering
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
ASTEROID = '#'
|
||||||
|
|
||||||
|
def zrange(x, y, step):
|
||||||
|
if x == y == step == 0:
|
||||||
|
def yzero():
|
||||||
|
while True:
|
||||||
|
yield 0
|
||||||
|
return yzero()
|
||||||
|
return range(x, y, step)
|
||||||
|
|
||||||
|
def angle(v):
|
||||||
|
if v.x == 0:
|
||||||
|
return (2 * int(v.y > 0), 0)
|
||||||
|
halve = 1 if v.x > 0 else 3
|
||||||
|
return (halve, Fraction(v.y, v.x))
|
||||||
|
|
||||||
|
def rebase(base, vectors):
|
||||||
|
return (v - base for v in vectors if v != base)
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class Vector:
|
||||||
|
def __init__(self, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
def __add__(self, other):
|
||||||
|
return Vector(self.x + other.x, self.y + other.y)
|
||||||
|
def __sub__(self, other):
|
||||||
|
return self + Vector(-other.x, -other.y)
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.x == other.x and self.y == other.y
|
||||||
|
def __lt__(self, other):
|
||||||
|
return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
|
||||||
|
def __str__(self):
|
||||||
|
return str((self.x, self.y))
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
class Map:
|
||||||
|
def __init__(self, map):
|
||||||
|
self.map = map
|
||||||
|
|
||||||
|
def __getitem__(self, v):
|
||||||
|
return self.map[v.y][v.x]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '\n'.join(self.map)
|
||||||
|
|
||||||
|
def is_asteroid(self, v):
|
||||||
|
return self[v] == ASTEROID
|
||||||
|
|
||||||
|
def vectors(self):
|
||||||
|
X, Y = len(self.map[0]), len(self.map)
|
||||||
|
return (Vector(x, y) for x, y in product(range(X), range(Y)))
|
||||||
|
|
||||||
|
def asteroid_vectors(self):
|
||||||
|
return filter(lambda v: self.is_asteroid(v), self.vectors())
|
||||||
|
|
||||||
|
def num_in_sight(self, v):
|
||||||
|
vs = rebase(v, self.asteroid_vectors())
|
||||||
|
return len(set(map(angle, vs)))
|
||||||
|
|
||||||
|
def best(self):
|
||||||
|
return max((self.num_in_sight(v), v) for v in self.asteroid_vectors())
|
||||||
|
|
||||||
|
def vaporize_seq(self, base):
|
||||||
|
vs = rebase(base, self.asteroid_vectors())
|
||||||
|
angles = defaultdict(list)
|
||||||
|
for v in vs:
|
||||||
|
angles[angle(v)].append(v)
|
||||||
|
for ang in angles.keys():
|
||||||
|
angles[ang].sort()
|
||||||
|
r = []
|
||||||
|
for i in range(max(map(len, angles.values()))):
|
||||||
|
r += [angles[ang][i] + base
|
||||||
|
for ang in sorted(angles.keys()) if i < len(angles[ang])]
|
||||||
|
return r
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
asteroid_map = Map(puzzle_input.split())
|
||||||
|
score, asteroid = asteroid_map.best()
|
||||||
|
return asteroid_map, asteroid, score
|
||||||
|
|
||||||
|
def partI(packed):
|
||||||
|
_, _, score = packed
|
||||||
|
return score
|
||||||
|
|
||||||
|
def partII(packed):
|
||||||
|
asteroid_map, asteroid, _ = packed
|
||||||
|
v = asteroid_map.vaporize_seq(asteroid)[199]
|
||||||
|
return 100*v.x + v.y
|
||||||
|
|
||||||
|
import solver
|
||||||
|
|
||||||
|
tests = solver.Tests()
|
||||||
|
|
||||||
|
map1 = \
|
||||||
|
""".#..#
|
||||||
|
.....
|
||||||
|
#####
|
||||||
|
....#
|
||||||
|
...##"""
|
||||||
|
|
||||||
|
map2 = \
|
||||||
|
"""#.#...#.#.
|
||||||
|
.###....#.
|
||||||
|
.#....#...
|
||||||
|
##.#.#.#.#
|
||||||
|
....#.#.#.
|
||||||
|
.##..###.#
|
||||||
|
..#...##..
|
||||||
|
..##....##
|
||||||
|
......#...
|
||||||
|
.####.###.
|
||||||
|
"""
|
||||||
|
|
||||||
|
map3 = \
|
||||||
|
""".#..##.###...#######
|
||||||
|
##.############..##.
|
||||||
|
.#.######.########.#
|
||||||
|
.###.#######.####.#.
|
||||||
|
#####.##.#.##.###.##
|
||||||
|
..#####..#.#########
|
||||||
|
####################
|
||||||
|
#.####....###.#.#.##
|
||||||
|
##.#################
|
||||||
|
#####.##.###..####..
|
||||||
|
..######..##.#######
|
||||||
|
####.##.####...##..#
|
||||||
|
.#####..#.######.###
|
||||||
|
##...#.##########...
|
||||||
|
#.##########.#######
|
||||||
|
.####.#.###.###.#.##
|
||||||
|
....##.##.###..#####
|
||||||
|
.#.#.###########.###
|
||||||
|
#.#.#.#####.####.###
|
||||||
|
###.##.####.##.#..##
|
||||||
|
"""
|
||||||
|
|
||||||
|
tests.add(map1, partI=8)
|
||||||
|
tests.add(map2, partI=35)
|
||||||
|
tests.add(map3, partI=210, partII=802)
|
|
@ -0,0 +1,85 @@
|
||||||
|
from advent import read_input
|
||||||
|
from intcode import Interpreter
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
BLACK = 0
|
||||||
|
WHITE = 1
|
||||||
|
|
||||||
|
color = {WHITE : u"\u2B1C",
|
||||||
|
BLACK : u"\u2B1B"
|
||||||
|
}
|
||||||
|
|
||||||
|
UP = (0, 1)
|
||||||
|
LEFT = 0
|
||||||
|
RIGHT = 1
|
||||||
|
|
||||||
|
def rotate(v, dir):
|
||||||
|
return (-dir) * v[1], dir * v[0]
|
||||||
|
|
||||||
|
def left(v):
|
||||||
|
return rotate(v, 1)
|
||||||
|
|
||||||
|
def right(v):
|
||||||
|
return rotate(v, -1)
|
||||||
|
|
||||||
|
def add(v1, v2):
|
||||||
|
return v1[0] + v2[0], v1[1] + v2[1]
|
||||||
|
|
||||||
|
class Canvas(defaultdict):
|
||||||
|
def __init__(self, color):
|
||||||
|
self.color = color
|
||||||
|
super(Canvas, self).__init__(int)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
xs, ys = zip(*self.keys())
|
||||||
|
return '\n'.join(''.join(self.color[self[(x, y)]]
|
||||||
|
for x in range(min(xs), max(xs)+1))
|
||||||
|
for y in range(max(ys), min(ys)-1, -1))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return unicode(self).encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
class robotIO:
|
||||||
|
def __init__(self, canvas=Canvas(color)):
|
||||||
|
self.canvas = canvas
|
||||||
|
self.dir = UP
|
||||||
|
self.pos = 0, 0
|
||||||
|
self.paint = True
|
||||||
|
|
||||||
|
def pop_input(self):
|
||||||
|
return self.canvas[self.pos]
|
||||||
|
|
||||||
|
def append_output(self, x):
|
||||||
|
if self.paint:
|
||||||
|
self.canvas[self.pos] = x
|
||||||
|
else:
|
||||||
|
self.dir = left(self.dir) if x == LEFT else right(self.dir)
|
||||||
|
self.pos = add(self.pos, self.dir)
|
||||||
|
self.paint = not self.paint
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
return self.canvas
|
||||||
|
|
||||||
|
class Robot:
|
||||||
|
def __init__(self, program, canvas=Canvas(color)):
|
||||||
|
self.canvas = canvas
|
||||||
|
self.program = program
|
||||||
|
|
||||||
|
def paint(self):
|
||||||
|
comp = Interpreter(self.program, robotIO)
|
||||||
|
comp.IO.canvas = self.canvas
|
||||||
|
return comp.run()
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return list(map(int, puzzle_input.split(',')))
|
||||||
|
|
||||||
|
def partI(program):
|
||||||
|
canvas = Robot(program).paint()
|
||||||
|
return len(canvas)
|
||||||
|
|
||||||
|
def partII(program):
|
||||||
|
canvas = Canvas(color)
|
||||||
|
canvas[(0, 0)] = WHITE
|
||||||
|
canvas = Robot(program, canvas).paint()
|
||||||
|
return '\n' + str(canvas)
|
Loading…
Reference in New Issue