Added days 2-11

master
Tibor Bizjak 2023-03-13 21:25:55 +01:00
parent 8e83278b02
commit 71fa1a9cd3
10 changed files with 574 additions and 0 deletions

47
day02.py 100644
View File

@ -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

80
day03.py 100644
View File

@ -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)

26
day04.py 100644
View File

@ -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

11
day05.py 100644
View File

@ -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)

44
day06.py 100644
View File

@ -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)

72
day07.py 100644
View File

@ -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)

48
day08.py 100644
View File

@ -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)

15
day09.py 100644
View File

@ -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)

146
day10.py 100644
View File

@ -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)

85
day11.py 100644
View File

@ -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)