def test_build_bridges(): spans = line_parser(test, parse=parse) for i, bridge in enumerate(build_bridges(spans), 1): assert 0 in bridge[0] assert i == 11
def part2(directions): position = (0, 0) heading = (0, 1) visited = set() turn = { 'R': lambda m: (-m[1], m[0]), 'L': lambda m: (m[1], -m[0]), } for t, d in directions: heading = turn[t](heading) for _ in range(d): if position in visited: break visited.add(position) position = tuple(p + h for p, h in zip(position, heading)) return sum(abs(p) for p in position) def parse(line): turn = line[0] steps = int(line[1:]) return (turn, steps) if __name__ == '__main__': directions = line_parser(get_input(day=1, year=2016), parse=parse, seperator=", ") print("Part 1: {}".format(part1(directions))) print("Part 2: {}".format(part2(directions)))
queue.append((i + 1, used + [buckets[i]])) queue.append((i + 1, used)) def test_storage_gen(): buckets = [15, 10, 5, 5, 20] assert len(list(storage_gen(buckets, 25))) == 4 def part1(buckets, volume=150): count = 0 for b in storage_gen(buckets, volume): count += 1 return count def part2(buckets, volume=150): shortest = [] for b in storage_gen(buckets, volume): if shortest == [] or len(b) < len(shortest[0]): shortest = [b] elif len(b) == len(shortest[0]): shortest.append(b) return len(shortest) if __name__ == '__main__': buckets = line_parser(get_input(day=17, year=2015)) print("Part 1: {}".format(part1(buckets))) print("Part 2: {}".format(part2(buckets)))
def test_part1(): ingredients = line_parser(test_text, parse=parse) assert 62842880 == part1(ingredients)
def make_set(table, seed): seen = set() queue = [seed] while queue: p = queue.pop() if p not in seen: seen.add(p) queue.extend(table[p]) return seen def part1(table): return len(make_set(table, 0)) def part2(table): return len(set(frozenset(make_set(table, v)) for v in table.keys())) def parse(line): ppid, pids = line.split(' <-> ') return (int(ppid), tuple(int(p) for p in pids.split(', '))) if __name__ == '__main__': table = dict(line_parser(get_input(day=12, year=2017), parse=parse)) print("Part 1: {}".format(part1(table))) print("Part 2: {}".format(part2(table)))
#!/usr/bin/env python3 from get_input import get_input, line_parser def part1(lines, update=None): i, count = 0, 0 lines = lines[:] if update is None: update = lambda x: x + 1 while 0 <= i < len(lines): jump = lines[i] lines[i] = update(lines[i]) count += 1 i += jump return count def part2(lines): return part1(lines, update=lambda x: x + 1 if x < 3 else x - 1) if __name__ == '__main__': lines = line_parser(get_input(day=5, year=2017)) print("Solution Part 1 {}".format(part1(lines))) print("Solution Part 2 {}".format(part2(lines)))
def test_part2(): reindeer = line_parser(test_text, parse=parse) assert part2(reindeer, time=1000) == 689
from get_input import get_input, line_parser def part1(addresses): lowest = 0 for start, end in sorted(addresses): if start <= lowest <= end: lowest = end + 1 return lowest def part2(addresses): allowed_addresses = 0 head = 0 for start, end in sorted(addresses): if head < start: allowed_addresses += start - head head = max(end + 1, head) return 2**32 - head + allowed_addresses def parse(line): return tuple(int(n) for n in line.split('-')) if __name__ == '__main__': addresses = line_parser(get_input(day=20, year=2016), parse=parse) print('Part 1: {}'.format(part1(addresses))) print('Part 2: {}'.format(part2(addresses)))
def part1(weights): quantum, items = None, None for group_a in split_gen(weights, 3): if items and len(group_a) > items: return quantum items = len(group_a) quantum = min(quantum or product(group_a), product(group_a)) def product(items): total = 1 for n in items: total *= n return total def part2(weights): quantum, items = None, None for group_a in split_gen(weights, 4): if items and len(group_a) > items: return quantum items = len(group_a) quantum = min(quantum or product(group_a), product(group_a)) if __name__ == '__main__': weights = line_parser(get_input(day=24, year=2015)) print("Part 1: {}".format(part1(weights))) print("Part 2: {}".format(part2(weights)))
else: continue result = Program(prog).run() if not (0 <= result.index < len(result)): return result.accumulator def parse(line): command, value = line.split(' ') return (command, int(value)) TEST_TEST_PART1 = """ nop +0 acc +1 jmp +4 acc +3 jmp -3 acc -99 acc +1 jmp -4 acc +6 """ if __name__ == "__main__": assert part1(line_parser(TEST_TEST_PART1, parse=parse)) == 5 assert part2(line_parser(TEST_TEST_PART1, parse=parse)) == 8 LINES = line_parser(get_input(day=8, year=2020), parse=parse) print(f"Part 1: {part1(LINES)}") print(f"Part 2: {part2(LINES)}")
assert a == a_gen def part1(start_a, start_b, sample=40000000): total = 0 gen_a = generator(start_a, 16807, bits=16) gen_b = generator(start_b, 48271, bits=16) for i, (a,b) in enumerate(zip(gen_a, gen_b)): if i > sample: return total if a == b: total += 1 def test_part1(): assert part1(65, 8921, sample=5) == 1 assert part1(65, 8921) == 588 def part2(start_a, start_b, sample=5000000): total = 0 gen_a = generator(start_a,16807,critera=4,bits=16) gen_b = generator(start_b,48271,critera=8,bits=16) for i, (a,b) in enumerate(zip(gen_a, gen_b)): if i > sample: return total if a == b: total += 1 if __name__ == '__main__': a, b = line_parser(get_input(day=15, year=2017), parse=lambda line:int(line.split(' ')[-1])) print("Part 1: {}".format(part1(a, b))) print("Part 2: {}".format(part2(a, b)))
return abas def test_find_aba(): assert [] == find_abas('abcde') assert ['bab'] == find_abas('aba') assert [] == find_abas('aaae') assert ['bab'] == find_abas('eabae') assert ['bab', 'aba', 'bab', 'aba'] == find_abas('ababab') def part2(lines): count = 0 for nets, hypers in lines: babs = [i for net in nets for i in find_abas(net)] for bab in babs: if any(bab in hyper for hyper in hypers): count += 1 break return count def parse(line): matches = re.findall(r'\w+', line) return ([matches[n] for n in range(0, len(matches), 2)], [matches[n] for n in range(1, len(matches), 2)]) if __name__ == '__main__': lines = line_parser(get_input(day=7, year=2016), parse=parse) print("Part 1: {}".format(part1(lines))) print("Part 2: {}".format(part2(lines)))
@command def dec(x): x.set(x.get() - 1) @command def jnz(x, y): return y.get() if x.get() != 0 else 1 def parse(line): assembunny = { re.compile(r'cpy (\S+) (\S+)'): cpy, re.compile(r'inc (\S+)'): inc, re.compile(r'dec (\S+)'): dec, re.compile(r'jnz (\S+) (\S+)'): jnz } for code, func in assembunny.items(): m = code.match(line) if m: return (line, func(*m.groups())) raise ValueError("Not a valid line {}".format(line)) if __name__ == '__main__': commands = line_parser(get_input(day=12, year=2016), parse=parse) print('Part 1: {}'.format(part1(commands))) print('Part 2: {}'.format(part2(commands)))
update(registers, oper) max_val = max(v for v in registers.values()) if biggest is None or max_val > biggest: biggest = max_val return biggest def update(env, oper): if oper.test_func(env[oper.test_reg], oper.test_val): env[oper.mod_reg] = oper.mod_func(env[oper.mod_reg], oper.mod_val) def parser(line): try: match = re.match(REGEX, line).groupdict() except AttributeError: raise ValueError("Not a match {}".format(line)) return Update(mod_reg=match['mod_reg'], mod_func=UPDATE[match['mod_func']], mod_val=int(match['mod_val']), test_reg=match['test_reg'], test_func=OPERATORS[match['test_func']], test_val=int(match['test_val']), line=line) if __name__ == '__main__': lines = line_parser(get_input(day=8, year=2017), parse=parser) print("Part 1: {}".format(part1(lines))) print("Part 2: {}".format(part2(lines)))
def test_part2(): nodes = line_parser(TEST_TEXT, parse=parse, numbered=True) assert part2(nodes, upper=25) == 7
def distribute(memory): while True: i, biggest = max(enumerate(memory), key=lambda n: (n[1], -n[0])) memory[i] = 0 for j in range(i+1, i+1+biggest): memory[j % len(memory)] += 1 yield tuple(memory) def part1(nums): sequences_seen = set() for count, sequence in enumerate(distribute(nums), 1): if sequence in sequences_seen: return count sequences_seen.add(sequence) def part2(nums): first = None sequences_seen = set() for count, sequence in enumerate(distribute(nums), 1): if sequence in sequences_seen: if first is not None: return count - first first = count sequences_seen.clear() sequences_seen.add(sequence) if __name__ == '__main__': nums = line_parser(get_input(day=6, year=2017), seperator='\t') print("Solution part 1: {}".format(part1(nums))) print("Solution part 2: {}".format(part2(nums)))
def new_add(loc_a, loc_b, limit=3): loc_c = [] for a, b in zip(loc_a, loc_b): loc_c.append(a + b) assert sum(abs(c) for c in loc_c) < limit return tuple(loc_c) def part2(instructions): grid = (("1"), ("234"), ("56789"), ("ABC"), ("D")) position = (-2, 0) moves = {"U": (-1, 0), "D": (1, 0), "L": (0, -1), "R": (0, 1)} code = "" for instruction in instructions: for move in instruction: try: position = new_add(moves[move], position) except AssertionError: continue code += grid[2 + position[0]][2 - abs(position[0]) + position[1]] return code if __name__ == '__main__': instructions = line_parser(get_input(day=2, year=2016), parse=tuple) print("Part 1: {}".format(part1(instructions))) print("Part 2: {}".format(part2(instructions)))
# No general purpose algo for figuring this one out reg = {v: 0 if v != 'a' else 1 for v in "abcdefgh"} state = ProgRunner(program, reg=reg) for s in state: if s.i == 10: if s.reg['b'] % s.reg['d'] == 0: s.i = 25 # print("{:4} % {:4} == 0, {} skip to {}".format( # s.reg['b'], s.reg['d'], s.reg['h'], s)) else: s.i = 20 return s.reg['h'] def is_prime(n): if n % 2 == 0: return False for m in range(3, int((n + 1)**0.5), 2): if n % m == 0: return False return True if __name__ == '__main__': lines = line_parser(get_input(day=23, year=2017), parse=lambda line: line.split(' ')) # Part 1: 3025 # Part 2: 915 print("Part 1: {}".format(part1(lines))) print("Part 2: {}".format(part2(lines)))
class Reindeer(object): def __init__(self, name, speed, time, rest): self.name = name self.speed = int(speed) self.time = int(time) self.rest = int(rest) def distance(self, time): location = 0 while True: if time <= self.time: return location + time * self.speed location += self.speed * self.time time -= self.time if time <= self.rest: return location time -= self.rest def parse(line): form = re.compile(r'(?P<name>\w+) can fly (?P<speed>\d+) km/s for ' + \ '(?P<time>\d+) seconds, but then must rest for (?P<rest>\d+) seconds.') m = form.match(line) return Reindeer(**m.groupdict()) if __name__ == "__main__": reindeer = line_parser(get_input(day=14, year=2015), parse=parse) print("Part 1: {}".format(part1(reindeer))) print("Part 2: {}".format(part2(reindeer)))
def dense_hash(values, block_size=16): hash_str = '' for block_start in range(0, len(values), block_size): h = 0 for char in values[block_start:block_start+block_size]: h ^= char hash_str += format(h, '02x') return hash_str def part1(lengths, n_items=256): chars = ''.join( chr(l) for l in lengths ) items = knot_hash(chars, hash_size=n_items, iterations=1) return items[0] * items[1] def test_part1(): test_input = [227,169,3,166,246,201,0,47,1,255,2,254,96,3,97,144] assert part1(test_input) == 13760 def part2(chars, hash_size=256, iterations=64, block_size=16): hash_vals = knot_hash(chars) return dense_hash(hash_vals) def test_part2(): assert 'a2582a3a0e66e6e86e3812dcb672a272' == part2('') assert '33efeb34ea91902bb2f59c9920caa6cd' == part2('AoC 2017') if __name__ == '__main__': line = get_input(day=10, year=2017).strip() print("Part 1: {}".format(part1(line_parser(line, seperator=',')))) print("Part 2: {}".format(part2(line)))
dist = [0] * buckets dist[0] = volume while True: yield dist dist[0] -= 1 dist[1] += 1 if dist[0] < 0: i = 1 while dist[0] < 0: if i + 1 >= len(dist): raise StopIteration dist[i + 1] += 1 dist[0] += dist[i] - 1 dist[i] = 0 i += 1 def parse(line): ingredient = re.compile( r'(?P<name>\w+): capacity (?P<capacity>-?\d+), ' + 'durability (?P<durability>-?\d+), flavor (?P<flavor>-?\d+), ' + 'texture (?P<texture>-?\d+), calories (?P<calories>-?\d+)') m = ingredient.match(line) return {k: int(v) if k != 'name' else v for k, v in m.groupdict().items()} if __name__ == '__main__': ingredients = line_parser(get_input(day=15, year=2015), parse=parse) print("Part 1: {}".format(part1(ingredients))) print("Part 2: {}".format(part2(ingredients)))
counts = Counter(c for c in name if c != '-') key = sorted(counts.items(), key=lambda v: (-v[1], v[0])) check = ''.join(k[0] for k in key[:5]) if check == checksum: total += id_num return total def part2(sectors): for name, shift, _ in sectors: word = '' for c in name: if c == '-': word += ' ' else: word += chr(((ord(c) - 97 + shift) % 26) + 97) if 'northpole' in word: return shift def parse(line): m = re.match(r'([a-z-]+)-(\d+)\[([a-z]{5})\]$', line) name, id_num, checksum = m.groups() return (name, int(id_num), checksum) if __name__ == '__main__': sectors = line_parser(get_input(day=4, year=2016), parse=parse) print("Part 1: {}".format(part1(sectors))) print("Part 2: {}".format(part2(sectors)))
'samoyeds': lambda v: v == 2, 'pomeranians': lambda v: v < 3, 'akitas': lambda v: v == 0, 'vizslas': lambda v: v == 0, 'goldfish': lambda v: v < 5, 'trees': lambda v: v > 3, 'cars': lambda v: v == 2, 'perfumes': lambda v: v == 1, } aunts = filter_aunts(aunts, props) assert len(aunts) == 1 return list(aunts.keys())[0] def parse(line): aunt_n = line.index(':') aunt = int(line[4:aunt_n]) props = {} for prop in line[aunt_n + 2:].split(', '): k, v = prop.split(': ') props[k] = int(v) return (aunt, props) if __name__ == '__main__': aunts = dict(line_parser(get_input(day=16, year=2015), parse=parse)) # Part 1: 103 # Part 2: 405 print("Part 1: {}".format(part1(aunts))) print("Part 2: {}".format(part2(aunts)))
new[key] = value.difference(set(mapping.values())) if new == allergens: raise NotImplementedError() allergens = new return mapping def part1(lines): mapping = set(get_mapping(lines).values()) return sum(1 for (ingred, _) in lines for i in ingred if i not in mapping) def part2(lines): mapping = get_mapping(lines) return ','.join(kv[1] for kv in sorted(mapping.items(), key=lambda kv: kv[0])) def parse(line): m = re.match(r"([^()]+)(?: \(contains (.+)\))", line) ingredients = tuple(m.group(1).strip().split(' ')) contains = tuple(m.group(2).split(', ')) return (ingredients, contains) if __name__ == "__main__": LINES = line_parser(get_input(day=21, year=2020), parse=parse) print(f"Part 1: {part1(LINES)}") print(f"Part 2: {part2(LINES)}")
return start def part1(boardingpasses): max_id = 0 for boardingpass in boardingpasses: row = binary_search([char == "F" for char in boardingpass[:7]], 0, 127) col = binary_search([char == "L" for char in boardingpass[7:]], 0, 7) max_id = max(row * 8 + col, max_id) return max_id def part2(boardingpasses): seats = {(row, col) for row in range(128) for col in range(8)} for boardingpass in boardingpasses: row = binary_search([char == "F" for char in boardingpass[:7]], 0, 127) col = binary_search([char == "L" for char in boardingpass[7:]], 0, 7) seats.remove((row, col)) seat = [s for s in seats if 10 < s[0] and s[0] < 100] assert len(seat) == 1 seat = seat.pop() return seat[0] * 8 + seat[1] if __name__ == "__main__": LINES = line_parser(get_input(day=5, year=2020), parse=list) assert binary_search([c == "F" for c in "FBFBBFF"], 0, 127) == 44 assert binary_search([c == 'L' for c in "RLR"], 0, 7) == 5 print(f"Part 1: {part1(LINES)}") print(f"Part 2: {part2(LINES)}")
import re def part1(disks): for time in count(0): for disk, holes, start in disks: if (time + disk + start) % holes != 0: break else: return time def test_part1(): disks = ((1, 5, 4), (2, 2, 1)) assert 5 == part1(disks) def part2(disks): return part1(disks + [(len(disks) + 1, 11, 0)]) def parse(line): frmt = r'Disc #(\d+) has (\d+) positions; at time=0, it is at position (\d+).' return tuple(int(g) for g in re.match(frmt, line).groups()) if __name__ == '__main__': disks = line_parser(get_input(day=15, year=2016), parse=parse) print("Part 1: {}".format(part1(disks))) print("Part 2: {}".format(part2(disks)))
#!/usr/bin/env python3 from get_input import get_input, line_parser from collections import Counter def part1(lines): phrase_counter = [Counter() for _ in range(len(lines[0]))] for line in lines: for i, c in enumerate(line): phrase_counter[i][c] += 1 return ''.join(max(p.items(), key=lambda q: q[1])[0] for p in phrase_counter) def part2(lines): phrase_counter = [Counter() for _ in range(len(lines[0]))] for line in lines: for i, c in enumerate(line): phrase_counter[i][c] += 1 return ''.join(min(p.items(), key=lambda q: q[1])[0] for p in phrase_counter) if __name__ == '__main__': lines = line_parser(get_input(day=6, year=2016), parse=lambda l: tuple(l), seperator='\n') print("Part 1: {}".format(part1(lines))) print("Part 2: {}".format(part2(lines)))
/dev/grid/node-x2-y1 9T 8T 1T 88% /dev/grid/node-x2-y2 9T 6T 3T 66%""" def test_part2(): nodes = line_parser(TEST_TEXT, parse=parse, numbered=True) assert part2(nodes, upper=25) == 7 def build(nodes, full_limit): max_x, max_y = 0, 0 full_nodes = set() for n in nodes: max_x, max_y = max(max_x, n.x), max(max_y, n.y) if n.used == 0: zero = Point(n.x, n.y) elif n.used > full_limit: full_nodes.add(Point(n.x, n.y)) return (max_x, max_y), zero, full_nodes def parse(line, i): if i < 2: return regex = r'/dev/grid/node-x(\d+)-y(\d+)\s+(\d+)T\s+(\d+)T\s+(\d+)T\s+(\d+)%' args = (int(g) for g in re.match(regex, line).groups()) return Node(*args) if __name__ == '__main__': nodes = line_parser(get_input(day=22, year=2016), parse=parse, numbered=True) print("Part 1: {}".format(part1(nodes))) print("Part 2: {}".format(part2(nodes)))
def part1(lines): door_public, card_public = lines door_loop = None card_loop = None loop_number = 1 public = 7 while door_loop is None or card_loop is None: print(f"{loop_number}: {public}") loop_number += 1 public = (7 * public) % 20201227 if card_loop is None and public == card_public: card_loop = loop_number if door_loop is None and public == door_public: door_loop = loop_number private = transform(door_public, card_loop) assert private == transform(card_public, door_loop) return private def part2(lines): return "Merry Christmas!" if __name__ == "__main__": assert part1([17807724, 5764801]) == 14897079 LINES = line_parser(get_input(day=25, year=2020)) print(f"Part 1: {part1(LINES)}") print(f"Part 2: {part2(LINES)}")
from get_input import get_input, line_parser def paper(l, w, h): sides = (l * w, w * h, h * l) return 2 * sum(sides) + min(sides) def part1(lines): return sum(paper(*line) for line in lines) def ribbon(l, w, h): s, m, l = sorted((l, w, h)) return 2 * (s + m) + s * m * l def part2(lines): return sum(ribbon(*line) for line in lines) def parse(line): return tuple(int(n) for n in line.split('x')) if __name__ == '__main__': lines = line_parser(get_input(day=2, year=2015), parse=parse) print("Part 1: {}".format(part1(lines))) print("Part 2: {}".format(part2(lines)))