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