Skip to content

Instantly share code, notes, and snippets.

@diath
Last active December 25, 2017 18:31
Show Gist options
  • Save diath/9bf602b31436d9cab4f733f08eb1d3da to your computer and use it in GitHub Desktop.
Save diath/9bf602b31436d9cab4f733f08eb1d3da to your computer and use it in GitHub Desktop.
Advent of Code, 2017, Python
from util import get_input, test, run
def main():
input = get_input(1)
def peek_next(s, pos):
if pos == len(s) - 1:
return s[0]
return s[pos + 1]
def peek_next_halfway(s, pos):
size = len(s)
step = size // 2
return s[(pos + step) % size]
def solve(input, fun):
return sum([
int(letter) if fun(input, index) == letter else 0
for (index, letter, ) in enumerate(input)
])
test((solve, peek_next, ), [
('1122', 3, ),
('1111', 4, ),
('1234', 0, ),
('91212129', 9, ),
])
test((solve, peek_next_halfway, ), [
('1212', 6, ),
('1221', 0, ),
('123425', 4, ),
('123123', 12, ),
('12131415', 4, ),
])
run([
(solve, input, peek_next, ),
(solve, input, peek_next_halfway, ),
])
if __name__ == '__main__':
main()
from util import to_number_list, get_input, test, run
from functools import reduce
def main():
input = get_input(10)
def to_ascii(input):
return list(map(ord, input))
def multiply(state):
return state[0] * state[1]
def xor_hex_chunks(state):
return ''.join(['{:02x}'.format(hex) for hex in [
reduce(lambda x, y: x ^ y, state[n:n + 16]) for n in range(0, len(state), 16)
]])
def hash(state, input, size, position, skip):
for n in input:
chunk = [state[(position + x) % size] for x in range(n)]
for x in range(n):
state[(position + x) % size] = chunk[n - x - 1]
position = (position + n + skip) % size
skip += 1
return (position, skip, )
def solve(input, fun, size, rounds):
state = [n for n in range(size)]
position = 0
skip = 0
for _ in range(rounds):
(position, skip, ) = hash(state, input, size, position, skip)
return fun(state)
run([
(lambda input, fun: solve(input, fun, 256, 1), to_number_list(input, ','), multiply, ),
(lambda input, fun: solve(input, fun, 256, 64), to_ascii(input) + [17, 31, 73, 47, 23], xor_hex_chunks, ),
])
if __name__ == '__main__':
main()
from util import get_input_string_list, test, run
def main():
input = get_input_string_list(11, ',')
DIRECTIONS = {
'ne': ( 1, 0, -1),
'n': ( 0, 1, -1),
'nw': (-1, 1, 0),
'sw': (-1, 0, 1),
's': ( 0, -1, 1),
'se': ( 1, -1, 0),
}
def move(position, direction):
return tuple(sum(x) for x in zip(position, DIRECTIONS.get(direction, (0, 0, 0, ))))
def get_distance(position):
return sum(map(abs, position)) // 2
def get_last_dist(distances):
return distances[-1]
def get_max_dist(distances):
return max(distances)
def solve(input, fun):
position = (0, 0, 0, )
distances = []
for direction in input:
position = move(position, direction)
distances.append(get_distance(position))
return fun(distances)
run([
(solve, input, get_last_dist, ),
(solve, input, get_max_dist, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from collections import defaultdict
def main():
input = get_input_string_rows(12)
def get_programs(prog_from, routes):
queue = [prog_from]
visited = set()
while queue:
prog_from = queue.pop()
for prog_to in routes.get(prog_from, set()):
if prog_to not in visited:
visited.add(prog_to)
queue.append(prog_to)
return visited
def get_groups(routes):
groups = 0
visited = set()
for prog_from in routes.keys():
if prog_from not in visited:
visited |= get_programs(prog_from, routes)
groups += 1
return groups
def solve(input, fun):
routes = defaultdict(set)
for row in input:
(prog_from, progs_to, ) = row.split(' <-> ')
for dst in progs_to.split(', '):
routes[prog_from].add(dst)
routes[dst].add(prog_from)
return fun(routes)
test((solve, lambda routes: len(get_programs('0', routes)), ), [
(to_string_rows("""0 <-> 2
1 <-> 1
2 <-> 0, 3, 4
3 <-> 2, 4
4 <-> 2, 3, 6
5 <-> 6
6 <-> 4, 5"""), 6, ),
])
test((solve, get_groups, ), [
(to_string_rows("""0 <-> 2
1 <-> 1
2 <-> 0, 3, 4
3 <-> 2, 4
4 <-> 2, 3, 6
5 <-> 6
6 <-> 4, 5"""), 2, ),
])
run([
(solve, input, lambda routes: len(get_programs('0', routes)), ),
(solve, input, get_groups, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from itertools import count
def main():
input = get_input_string_rows(13)
def is_safe(depth, range_, delay=0):
return (depth + delay) % (2 * range_ - 2) != 0
def get_severity(depth, range_):
return depth * range_ if not is_safe(depth, range_) else 0
def get_total_severity(layers):
return sum(get_severity(depth, range_) for (depth, range_, ) in layers.items())
def get_safe_delay(layers):
for delay in count():
if all(is_safe(depth, range_, delay) for (depth, range_, ) in layers.items()):
return delay
def solve(input, fun):
layers = {int(depth): int(range_) for (depth, range_, ) in [row.split(': ') for row in input]}
return fun(layers)
test((solve, get_total_severity, ), [
(to_string_rows("""0: 3
1: 2
4: 4
6: 4"""), 24, ),
])
test((solve, get_safe_delay, ), [
(to_string_rows("""0: 3
1: 2
4: 4
6: 4"""), 10, ),
])
run([
(solve, input, get_total_severity, ),
(solve, input, get_safe_delay, ),
])
if __name__ == '__main__':
main()
from util import test, run
def main():
gen_a_start = 289
gen_b_start = 629
factor_a = 16807
factor_b = 48271
remainder = 2147483647
def advance(gen, factor):
return (gen * factor) % remainder
def advance_both(gen_a, gen_b):
return (advance(gen_a, factor_a, ), advance(gen_b, factor_b, ))
def advance_muls(gen_a, gen_b):
(gen_a, gen_b, ) = advance_both(gen_a, gen_b)
while gen_a % 4 != 0:
gen_a = advance(gen_a, factor_a)
while gen_b % 8 != 0:
gen_b = advance(gen_b, factor_b)
return (gen_a, gen_b, )
def solve(input, fun):
count = 0
(gen_a, gen_b, iterations, ) = input
for _ in range(iterations):
(gen_a, gen_b, ) = fun(gen_a, gen_b, )
if (gen_a & 0xFFFF) ^ (gen_b & 0xFFFF) == 0:
count += 1
return count
test((solve, advance_both, ), [
((65, 8921, 5, ), 1, ),
((65, 8921, 40000000, ), 588, ),
])
test((solve, advance_muls, ), [
((65, 8921, 5, ), 0, ),
((65, 8921, 1056, ), 1, ),
((65, 8921, 5000000, ), 309, ),
])
run([
(solve, (gen_a_start, gen_b_start, 40000000, ), advance_both, ),
(solve, (gen_a_start, gen_b_start, 5000000, ), advance_muls, ),
])
if __name__ == '__main__':
main()
from util import to_string_list, get_input_string_list, test, run
from re import compile
def main():
input = get_input_string_list(16, ',')
RE_SPIN = compile(r's(\d+)')
RE_EXCHANGE = compile(r'x(\d+)/(\d+)')
RE_PARTNER = compile(r'p([a-z])/([a-z])')
def spin(programs, match):
n = int(match.group(1))
return programs[-n:] + programs[:-n]
def exchange(programs, match):
a = int(match.group(1))
b = int(match.group(2))
programs[a], programs[b] = programs[b], programs[a]
return programs
def partner(programs, match):
a = programs.index(match.group(1))
b = programs.index(match.group(2))
programs[a], programs[b] = programs[b], programs[a]
return programs
MOVES = [
(RE_SPIN, spin, ),
(RE_EXCHANGE, exchange, ),
(RE_PARTNER, partner, ),
]
def make_test_programs():
return [chr(n) for n in range(97, 102)]
def make_programs():
return [chr(n) for n in range(97, 113)]
def dance(input, programs):
for move in input:
for (expr, fun, ) in MOVES:
match = expr.match(move)
if match:
programs = fun(programs, match)
break
return programs
def solve(input, fun):
(input, iters, ) = input
programs = fun()
seen = []
for n in range(iters):
joined = ''.join(programs)
if joined not in seen:
seen.append(joined)
else:
return seen[iters % n]
programs = dance(input, programs)
return ''.join(programs)
test((solve, make_test_programs, ), [
((to_string_list('s1,x3/4,pe/b', ','), 1, ), 'baedc', ),
])
run([
(solve, (input, 1, ), make_programs, ),
(solve, (input, 1000000000, ), make_programs, ),
])
if __name__ == '__main__':
main()
from util import get_input_number, test, run
def main():
input = get_input_number(17)
def solve(input, p2):
(step, iters, value, ) = input
position = 0
if not p2:
spinlock = [0]
for n in range(1, iters + 1):
position = (position + step + 1) % (n + 1)
spinlock.insert(position, n + 1)
return spinlock[spinlock.index(value) + 1]
else:
result = 0
for n in range(1, iters + 1):
position = ((position + step) % n) + 1
if position == 1:
result = n
return result
test((solve, False, ), [
((3, 2017, 2017, ), 638, ),
])
run([
(solve, (input, 2017, 2017, ), False, ),
(solve, (input, 50000000, 0, ), True, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from collections import defaultdict
def main():
input = get_input_string_rows(18)
class Program(object):
def __init__(self, input, id, q1, q2):
self.id = id
self.input = [line.split(' ') for line in input]
self.size = len(self.input)
self.sent = 0
self.position = 0
self.regs = defaultdict(int)
self.regs['p'] = id
self.queue_in = q1
self.queue_out = q2
self.oob = False
def get_value(self, value):
try:
return int(value)
except (ValueError, ):
return self.regs.get(value, 0)
def terminated(self):
(ins, *_, ) = self.input[self.position]
return self.oob or (ins == 'rcv' and not self.queue_in)
def step(self):
if self.terminated():
return
(ins, *info, ) = self.input[self.position]
if ins == 'set':
self.regs[info[0]] = self.get_value(info[1])
self.position += 1
elif ins == 'add':
self.regs[info[0]] += self.get_value(info[1])
self.position += 1
elif ins == 'mul':
self.regs[info[0]] *= self.get_value(info[1])
self.position += 1
elif ins == 'mod':
self.regs[info[0]] %= self.get_value(info[1])
self.position += 1
elif ins == 'rcv':
self.regs[info[0]] = self.queue_in.pop(0)
self.position += 1
elif ins == 'snd':
self.queue_out.append(self.get_value(info[0]))
self.sent += 1
self.position += 1
elif ins == 'jgz':
if self.get_value(info[0]) > 0:
self.position += self.get_value(info[1])
else:
self.position += 1
if self.position < 0 or self.position >= self.size:
self.oob = True
def part1(input, fun):
prog = Program(input, 0, [], [])
while not prog.terminated():
prog.step()
return prog.queue_out.pop()
def part2(input, fun):
q1 = []
q2 = []
prog_a = Program(input, 0, q1, q2)
prog_b = Program(input, 1, q2, q1)
while not prog_a.terminated() or not prog_b.terminated():
prog_a.step()
prog_b.step()
return prog_b.sent
test((part1, lambda: None, ), [
(to_string_rows('''set a 1
add a 2
mul a a
mod a 5
snd a
set a 0
rcv a
jgz a -1
set a 1
jgz a -2'''), 4, )
])
run([
(part1, input, lambda: None, ),
(part2, input, lambda: None, ),
])
if __name__ == '__main__':
main()
from util import get_input, test, run
def main():
input = [list(row) for row in get_input(19, False).split('\n')]
def solve(input, fun):
position = (input[0].index('|'), 0, )
dir = (0, 1, )
result = ''
steps = 0
def move(position, dir):
return tuple(sum(x) for x in zip(position, dir))
def get_ch_at(position):
(x, y, ) = position
try:
return input[y][x]
except (IndexError, ):
return ' '
while True:
(x, y, ) = position
ch = get_ch_at(position)
if ch == ' ':
break
if ch == '+':
(dx, dy, ) = dir
if dx == 0:
dx = 1 if get_ch_at((x - 1, y, )) == ' ' else -1
dy = 0
else:
dx = 0
dy = 1 if get_ch_at((x, y - 1, )) == ' ' else -1
dir = (dx, dy, )
elif ch.isalpha():
result += ch
position = move(position, dir)
steps += 1
return fun(result, steps)
run([
(solve, input, lambda x, _: x, ),
(solve, input, lambda _, x: x, ),
])
if __name__ == '__main__':
main()
from util import to_number_matrix, get_input_number_matrix, test, run
from itertools import combinations
def main():
input = get_input_number_matrix(2)
def sum_min_max(row):
return max(row) - min(row)
def sum_divisible(row):
for (x, y, ) in combinations(row, 2):
if x % y == 0:
return x // y
if y % x == 0:
return y // x
return 0
def solve(input, fun):
return sum([fun(row) for row in input])
test((solve, sum_min_max, ), [
(to_number_matrix('5 1 9 5\n7 5 3\n2 4 6 8'), 18, ),
])
test((solve, sum_divisible, ), [
(to_number_matrix('5 9 2 8\n9 4 7 3\n3 8 6 5'), 9, ),
])
run([
(solve, input, sum_min_max, ),
(solve, input, sum_divisible, ),
])
if __name__ == '__main__':
main()
from util import get_input_string_rows, test, run
from re import compile
from itertools import combinations
def main():
input = get_input_string_rows(20)
RE_VEC3 = compile(r'<([ -]?\d+),([ -]?\d+),([ -]?\d+)>')
class Vec3(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return 'Vec3({}, {}, {})'.format(self.x, self.y, self.z)
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.z == other.z
def to_list(self):
return [self.x, self.y, self.z]
class Particle(object):
def __init__(self, id, pos, vel, acc):
self.id = id
self.pos = pos
self.vel = vel
self.acc = acc
self.removed = False
def __repr__(self):
return 'Particle({}, {}, {})'.format(self.pos, self.vel, self.acc)
def move(self):
if self.removed:
return
self.vel = Vec3(*[sum(x) for x in zip(self.vel.to_list(), self.acc.to_list())])
self.pos = Vec3(*[sum(x) for x in zip(self.pos.to_list(), self.vel.to_list())])
def dist(self):
return sum(map(abs, self.pos.to_list()))
def part1(input):
input = [Particle(index, *[Vec3(*map(int, v3)) for v3 in RE_VEC3.findall(row)]) for (index, row, ) in enumerate(input)]
for _ in range(500):
for particle in input:
particle.move()
return sorted(input, key=lambda p: p.dist())[0].id
def part2(input):
input = [Particle(index, *[Vec3(*map(int, v3)) for v3 in RE_VEC3.findall(row)]) for (index, row, ) in enumerate(input)]
for _ in range(500):
for particle in input:
particle.move()
for (a, b, ) in combinations([particle for particle in input if not particle.removed], 2):
if a.pos == b.pos:
a.removed = True
b.removed = True
return len([particle for particle in input if not particle.removed])
run([
(lambda input, fun: part1(input), input, lambda: None, ),
(lambda input, fun: part2(input), input, lambda: None, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from collections import defaultdict
def main():
input = get_input_string_rows(22)
CH_CLEAN = '.'
CH_INFCT = '#'
CH_WEKND = 'W'
CH_FLGGD = 'F'
DIR_UP = ( 0, -1, )
DIR_DN = ( 0, 1, )
DIR_LT = (-1, 0, )
DIR_RT = ( 1, 0, )
LEFT = {
DIR_UP: DIR_LT,
DIR_LT: DIR_DN,
DIR_DN: DIR_RT,
DIR_RT: DIR_UP,
}
RIGHT = {
DIR_UP: DIR_RT,
DIR_RT: DIR_DN,
DIR_DN: DIR_LT,
DIR_LT: DIR_UP,
}
REVERSE = {
DIR_UP: DIR_DN,
DIR_DN: DIR_UP,
DIR_LT: DIR_RT,
DIR_RT: DIR_LT,
}
def solve(input, part2):
(rows, iters, ) = input
matrix = defaultdict(lambda: CH_CLEAN)
matrix_index = lambda x, y: '{}_{}'.format(x, y)
matrix_value = lambda x, y: matrix[matrix_index(x, y)]
turn = lambda lut, d: lut.get(d)
for (y, row, ) in enumerate(rows):
for (x, cell, ) in enumerate(row):
matrix[matrix_index(x, y)] = cell
size = len(rows)
position = (size // 2, size // 2, )
direction = (0, -1, )
stats = defaultdict(int)
for _ in range(iters):
(x, y, ) = position
ch = matrix_value(x, y)
stats[ch] += 1
if part2 is False:
if ch == CH_INFCT:
direction = turn(RIGHT, direction)
matrix[matrix_index(x, y)] = CH_CLEAN
elif ch == CH_CLEAN:
direction = turn(LEFT, direction)
matrix[matrix_index(x, y)] = CH_INFCT
else:
if ch == CH_INFCT:
direction = turn(RIGHT, direction)
matrix[matrix_index(x, y)] = CH_FLGGD
elif ch == CH_CLEAN:
direction = turn(LEFT, direction)
matrix[matrix_index(x, y)] = CH_WEKND
elif ch == CH_WEKND:
matrix[matrix_index(x, y)] = CH_INFCT
elif ch == CH_FLGGD:
direction = turn(REVERSE, direction)
matrix[matrix_index(x, y)] = CH_CLEAN
(dx, dy, ) = direction
position = (x + dx, y + dy, )
if part2 is False:
return stats.get(CH_CLEAN)
return stats.get(CH_WEKND)
test_grid = to_string_rows('''..#
#..
...''')
test((solve, False, ), [
((test_grid, 7, ), 5, ),
((test_grid, 70, ), 41, ),
((test_grid, 10000, ), 5587, ),
])
test((solve, True, ), [
((test_grid, 100, ), 26, ),
((test_grid, 10000000, ), 2511944, ),
])
run([
(solve, (input, 10000, ), False, ),
(solve, (input, 10000000, ), True, ),
])
if __name__ == '__main__':
main()
from util import get_input_number, test, run
from math import ceil
def main():
input = get_input_number(3)
def get_spiral_moves(input):
if input <= 1:
return 0
rings = ceil(input ** 0.5)
if rings % 2 == 0:
rings += 1
offset = (rings ** 2) - input
steps = offset % (rings - 1)
return rings // 2 + abs(rings // 2 - steps)
def get_first_largest(input):
position = (0, 0, )
direction = (1, 0, )
matrix = {}
index = 0
stride = 0
matrix_index = lambda x, y: '{}_{}'.format(x, y)
matrix_value = lambda x, y: matrix.get(matrix_index(x, y), 0)
matrix[matrix_index(0, 0)] = 1
while True:
if index % 2 == 0:
stride += 1
for n in range(stride):
(x, y, ) = position = (position[0] + direction[0], position[1] + direction[1], )
value = sum([
matrix_value(x - 1, y + 1),
matrix_value(x + 0, y + 1),
matrix_value(x + 1, y + 1),
matrix_value(x - 1, y + 0),
matrix_value(x + 1, y + 0),
matrix_value(x - 1, y - 1),
matrix_value(x + 0, y - 1),
matrix_value(x + 1, y - 1),
])
if value >= input:
return value
matrix[matrix_index(x, y)] = value
index += 1
direction = (-direction[1], direction[0], )
return 0
def solve(input, fun):
return fun(input)
test((solve, get_spiral_moves, ), [
(1, 0, ),
(12, 3, ),
(23, 2, ),
(1024, 31, ),
])
run([
(solve, input, get_spiral_moves, ),
(solve, input, get_first_largest, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from itertools import combinations
def main():
input = get_input_string_rows(4)
def is_valid(row):
elems = row.split()
return len(elems) == len(set(elems))
def is_valid_no_anagram(row):
for (a, b, ) in combinations(row.split(), 2):
if sorted(a) == sorted(b):
return False
return True
def solve(input, fun):
return sum([int(fun(row)) for row in input])
test((solve, is_valid, ), [
(to_string_rows('aa bb cc dd ee'), 1, ),
(to_string_rows('aa bb cc dd aa'), 0, ),
(to_string_rows('aa bb cc dd aaa'), 1, ),
])
test((solve, is_valid_no_anagram, ), [
(to_string_rows('abcde fghij'), 1, ),
(to_string_rows('abcde xyz ecdab'), 0, ),
(to_string_rows('a ab abc abd abf abj'), 1, ),
(to_string_rows('iiii oiii ooii oooi oooo'), 1, ),
(to_string_rows('oiii ioii iioi iiio'), 0, ),
])
run([
(solve, input, is_valid, ),
(solve, input, is_valid_no_anagram, ),
])
if __name__ == '__main__':
main()
from util import to_number_rows, get_input_number_rows, test, run
def main():
input = get_input_number_rows(5)
def jump(input):
return 1
def jump_strange(n):
return -1 if n >= 3 else 1
def solve(input, fun):
steps = 0
position = 0
size = len(input)
try:
while True:
n = input[position]
input[position] += fun(n)
position += n
steps += 1
except (IndexError, ):
pass
return steps
test((solve, jump, ), [
(to_number_rows('0\n3\n0\n1\n-3'), 5, )
])
test((solve, jump_strange, ), [
(to_number_rows('0\n3\n0\n1\n-3'), 10, )
])
run([
(solve, input[:], jump, ),
(solve, input[:], jump_strange, ),
])
if __name__ == '__main__':
main()
from util import to_number_list, get_input_number_list, test, run
from collections import OrderedDict
def main():
input = get_input_number_list(6)
def get_steps(input, seen):
return len(seen)
def get_steps_between(input, seen):
return len(seen) - list(seen.keys()).index(tuple(input))
def solve(input, fun):
seen = OrderedDict()
while seen.get(tuple(input), None) is None:
seen[tuple(input[:])] = True
value = max(input)
index = input.index(value)
size = len(input)
input[index] = 0
for n in range(value):
input[(index + n + 1) % size] += 1
return fun(input, seen)
test((solve, get_steps, ), [
(to_number_list('0 2 7 0'), 5, )
])
test((solve, get_steps_between, ), [
(to_number_list('0 2 7 0'), 4, )
])
run([
(solve, input[:], get_steps, ),
(solve, input[:], get_steps_between, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from re import compile
def main():
input = get_input_string_rows(7)
RE_DISC = compile(r'(\S+) \((\d+)\)( -> ([\S ]+))?')
def get_children(discs, disc):
return [discs.get(child) for child in disc.get('children')]
def get_weight(discs, disc):
return disc.get('weight') + sum([get_weight(discs, child) for child in get_children(discs, disc)])
def get_root_name(discs, root):
return root.get('name')
def get_corrected_weight(discs, root):
prev = dict()
while True:
weights = {child.get('name'): get_weight(discs, child) for child in get_children(discs, root)}
values = list(weights.values())
if max(values) - min(values) == 0:
return root.get('weight') - (max(prev.values()) - min(prev.values()))
prev = weights
root = discs.get(list(weights.keys())[values.index(max(values))])
return 0
def solve(input, fun):
discs = dict({
m.group(1): {'name': m.group(1), 'weight': int(m.group(2)), 'children': [] if m.group(4) is None else m.group(4).strip().split(', ')}
for m in [RE_DISC.match(row) for row in input]
})
for disc in discs.values():
for child in get_children(discs, disc):
child['parent'] = disc
root = next(filter(lambda disc: disc.get('parent') is None, discs.values()))
return fun(discs, root)
test((solve, get_root_name, ), [
(to_string_rows('''pbga (66)
xhth (57)
ebii (61)
havc (66)
ktlj (57)
fwft (72) -> ktlj, cntj, xhth
qoyq (66)
padx (45) -> pbga, havc, qoyq
tknk (41) -> ugml, padx, fwft
jptl (61)
ugml (68) -> gyxo, ebii, jptl
gyxo (61)
cntj (57)'''), 'tknk', )
])
test((solve, get_corrected_weight, ), [
(to_string_rows('''pbga (66)
xhth (57)
ebii (61)
havc (66)
ktlj (57)
fwft (72) -> ktlj, cntj, xhth
qoyq (66)
padx (45) -> pbga, havc, qoyq
tknk (41) -> ugml, padx, fwft
jptl (61)
ugml (68) -> gyxo, ebii, jptl
gyxo (61)
cntj (57)'''), 60, )
])
run([
(solve, input[:], get_root_name, ),
(solve, input[:], get_corrected_weight, ),
])
if __name__ == '__main__':
main()
from util import to_string_rows, get_input_string_rows, test, run
from collections import defaultdict
import operator
def main():
input = get_input_string_rows(8)
OPERATOR_LUT = dict({
'>': operator.gt,
'<': operator.lt,
'>=': operator.ge,
'<=': operator.le,
'==': operator.eq,
'!=': operator.ne,
})
INSTRUCTION_LUT = dict({
'inc': operator.add,
'dec': operator.sub,
})
def check_operator(op, src_val, cmp):
check_op = OPERATOR_LUT.get(op, None)
if check_op is None:
return False
return check_op(src_val, cmp)
def get_largest_register(regs):
return max(list(regs.values()))
def solve(input, fun):
regs = defaultdict(int)
largest_ever = 0
for row in input:
(dst, ins, val, _, src, op, cmp, ) = tuple(row.split())
dst_val = regs.get(dst, 0)
src_val = regs.get(src, 0)
val = int(val)
cmp = int(cmp)
if check_operator(op, src_val, cmp):
regs[dst] = INSTRUCTION_LUT.get(ins, lambda x, y: 0)(regs[dst], val)
if fun is None and regs:
largest_ever = max(get_largest_register(regs), largest_ever)
if fun is None:
return largest_ever
return fun(regs)
test((solve, get_largest_register, ), [
(to_string_rows('''b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10'''), 1, )
])
test((solve, None, ), [
(to_string_rows('''b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10'''), 10, )
])
run([
(solve, input, get_largest_register, ),
(solve, input, None, ),
])
if __name__ == '__main__':
main()
from util import get_input, test, run
from collections import defaultdict
import operator
def main():
input = get_input(9)
CH_ESCAPE = '!'
CH_GARBAGE_BEG = '<'
CH_GARBAGE_END = '>'
CH_GROUP_BEG = '{'
CH_GROUP_END = '}'
def solve(input, fun):
score = 0
garbage = 0
level = 0
in_garbage = False
size = len(input)
pos = 0
while pos < size:
ch = input[pos]
if ch == CH_ESCAPE:
pos += 1
elif in_garbage and ch != CH_GARBAGE_END:
garbage += 1
elif ch == CH_GROUP_BEG:
level += 1
elif ch == CH_GROUP_END:
score += level
level -= 1
elif ch == CH_GARBAGE_BEG:
in_garbage= True
elif ch == CH_GARBAGE_END:
in_garbage = False
pos += 1
return fun(score, garbage)
test((solve, lambda x, _: x), [
('{}', 1, ),
('{{{}}}', 6, ),
('{{},{}}', 5, ),
('{{{},{},{{}}}}', 16, ),
('{<a>,<a>,<a>,<a>}', 1, ),
('{{<ab>},{<ab>},{<ab>},{<ab>}}', 9, ),
('{{<!!>},{<!!>},{<!!>},{<!!>}}', 9, ),
('{{<a!>},{<a!>},{<a!>},{<ab>}}', 3, ),
])
run([
(solve, input, lambda x, _: x, ),
(solve, input, lambda _, x: x, ),
])
if __name__ == '__main__':
main()
from time import time
def to_number(input):
try:
return int(input)
except (ValueError, ):
print('Failed to convert input to a number.')
return 0
def to_number_list(input, ch=' '):
try:
return list(map(int, input.split(ch)))
except (ValueError, ):
print('Failed to convert input to a list of numbers.')
return []
def to_number_rows(input):
return to_number_list(input.replace('\n', ' '))
def to_string_list(input, ch=' '):
return input.split(ch)
def to_string_rows(input):
return input.split('\n')
def to_number_matrix(input):
try:
return [list(map(int, row.split())) for row in input.split('\n')]
except (ValueError, ):
print('Failed to convert input to a matrix of numbers.')
return [[]]
def get_input(day, strip=True):
res = None
with open(('D{}.txt'.format(day))) as handle:
res = handle.read()
if strip:
res = res.strip()
return res
def get_input_number(day):
return to_number(get_input(day))
def get_input_number_list(day, ch=' '):
return to_number_list(get_input(day), ch)
def get_input_number_rows(day):
return to_number_rows(get_input(day))
def get_input_string_list(day, ch=' '):
return to_string_list(get_input(day), ch)
def get_input_string_rows(day):
return to_string_rows(get_input(day))
def get_input_number_matrix(day):
return to_number_matrix(get_input(day))
def time_ms():
return int(round(time() * 1000))
def test(funs, xs):
solve, callback = funs
for (input, value, ) in xs:
ret = solve(input, callback)
assert ret == value, 'Test failed for input {} - Expected {} - Got {}'.format(input, value, ret)
def run(info):
start = time_ms()
timings = []
for index, (solve, input, fn, ) in enumerate(info):
solution_start = time_ms()
print('P{} result: {}'.format(index + 1, solve(input, fn)))
timings.append(time_ms() - solution_start)
print('Time: {} | Total: {}ms'.format(
', '.join(['{}ms (P{})'.format(time, index + 1) for (index, time, ) in enumerate(timings)]),
time_ms() - start
))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment