Last active
December 25, 2017 18:31
-
-
Save diath/9bf602b31436d9cab4f733f08eb1d3da to your computer and use it in GitHub Desktop.
Advent of Code, 2017, Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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