# -*- coding: utf-8 -*- import hashlib from advent_tools import print_answer ENCODING = 'utf-8' def hash_key_and_number(key, number): m = hashlib.md5() m.update(key.encode(ENCODING)) m.update(str(number).encode(ENCODING)) return m.hexdigest() def find_hash_seed(prefix, key): current_number = 0 while True: current_number += 1 current_hash = hash_key_and_number(puzzle_input, current_number) if current_hash.startswith(prefix): return current_number puzzle_input = input('Puzzle key: ') print_answer(1, find_hash_seed('00000', puzzle_input)) print_answer(2, find_hash_seed('000000', puzzle_input))
# -*- coding: utf-8 -*- from itertools import combinations from functools import reduce from operator import mul from advent_tools import get_input_lines, print_answer total_area, ribbon_length = (0, 0) for line in get_input_lines(): dimensions = list(map(int, line.strip().split('x'))) rectangle_sides = list(combinations(dimensions, 2)) rectangle_areas = [x * y for x, y in rectangle_sides] slack = min(rectangle_areas) total_area += sum(2 * area for area in rectangle_areas) total_area += slack perimeters = [2 * x + 2 * y for x, y in rectangle_sides] ribbon_length += min(perimeters) ribbon_length += reduce(mul, dimensions) print_answer(1, total_area) print_answer(2, ribbon_length)
# -*- coding: utf-8 -*- import re import json from advent_tools import get_input_string, print_answer NUMBERS = re.compile('-?\d+') input_string = get_input_string() print_answer(1, sum(map(int, NUMBERS.findall(input_string)))) root = json.loads(input_string) def explore(node, total): if isinstance(node, int): return total + node if isinstance(node, dict): if 'red' in node.values(): return total acum = 0 for n in node.values(): acum += explore(n, 0) return total + acum if isinstance(node, list): acum = 0 for n in node: acum += explore(n, 0)
# -*- coding: utf-8 -*- import re from advent_tools import get_input_lines, print_answer decode_pattern = re.compile(r'(\\\\)|(\\\")|(\\x[0-9a-f]{2})') encoding_subs = [ (re.compile(r'\\'), r'\\\\'), (re.compile(r'\"'), r'\\"') ] total_code_chars = 0 total_memory_size = 0 total_encoded_size = 0 for line in get_input_lines(): meaty_part = line[1:-1] mem_length = len(decode_pattern.sub('?', meaty_part)) total_code_chars += len(line) total_memory_size += mem_length encoded_line = line for pattern, sub in encoding_subs: encoded_line = pattern.sub(sub, encoded_line) encoded_line = '"{}"'.format(encoded_line) total_encoded_size += len(encoded_line) print_answer(1, total_code_chars - total_memory_size) print_answer(2, total_encoded_size - total_code_chars)
results = {} def solve(key): input_ = inputs[key] args = [] for source in input_.sources: if isinstance(source, int): args.append(source) else: if source not in results: solve(source) args.append(results[source]) if input_.operator is None: results[key] = args[0] else: results[key] = input_.operator(*args) solve('a') first_answer = c_uint16(results['a']).value print_answer(1, first_answer) inputs['b'] = Input(sources=[first_answer], operator=None) results = {} solve('a') second_answer = c_uint16(results['a']).value print_answer(2, second_answer)
# -*- coding: utf-8 -*- from advent_tools import print_answer puzzle_input = input('Puzzle input: ') def transform(line): line += '*' last_cut = 0 sequences = [] for offset, left, right in zip(range(1, len(line)), line[:-1], line[1:]): if left != right: sequences.append(line[last_cut:offset]) last_cut = offset result = '' for seq in sequences: result += str(len(seq)) result += seq[0] return result for _ in range(40): puzzle_input = transform(puzzle_input) print_answer(1, len(puzzle_input)) for _ in range(10): puzzle_input = transform(puzzle_input) print_answer(2, len(puzzle_input))
from advent_tools import get_input_string, print_answer def direction(instruction): if instruction == '(': return 1 if instruction == ')': return -1 raise ValueError('Instruction has to be either "(" or ")"') input_string = get_input_string() first_answer = input_string.count('(') - input_string.count(')') print_answer(1, first_answer) current_floor = 0 for idx, instruction in enumerate(input_string): current_floor += direction(instruction) if current_floor < 0: print_answer(2, idx + 1) break if current_floor >= 0: print('Second answer: Negative floor was never reached')
distances = dict() places = set() for line in get_input_lines(): left, _, right, _, distance = line.split() distance = int(distance) places.add(left) places.add(right) distances[frozenset((left, right))] = distance shortest_length = inf shortest_route = None biggest_length = 0 longest_route = None for route in permutations(places): route_length = 0 trips = zip(route[:-1], route[1:]) route_length = sum(distances[frozenset(t)] for t in trips) if route_length < shortest_length: shortest_length = route_length shortest_route = route if route_length > biggest_length: biggest_length = route_length longest_route = route print_answer(1, shortest_length) print_answer(2, biggest_length)
previous_pair = self.second_to_last + self.last if len(previous_pair) == 2: self.seen_pairs.add(previous_pair) self.second_to_last = self.last self.last = char def is_nice(self): return self.has_almost_contiguous_pair and self.repeats_non_overlapping_pairs def evaluate_words(evaluator, lines): nice_ones = 0 for line in lines.split("\n"): ne = evaluator() for char in line: ne.read(char) if ne.is_nice(): nice_ones += 1 return nice_ones input_string = get_input_string() print_answer(1, evaluate_words(FirstNicenessEvaluator, input_string)) print_answer(2, evaluate_words(SecondNicenessEvaluator, input_string))
previous_pair = self.second_to_last + self.last if len(previous_pair) == 2: self.seen_pairs.add(previous_pair) self.second_to_last = self.last self.last = char def is_nice(self): return (self.has_almost_contiguous_pair and self.repeats_non_overlapping_pairs) def evaluate_words(evaluator, lines): nice_ones = 0 for line in lines.split('\n'): ne = evaluator() for char in line: ne.read(char) if ne.is_nice(): nice_ones += 1 return nice_ones input_string = get_input_string() print_answer(1, evaluate_words(FirstNicenessEvaluator, input_string)) print_answer(2, evaluate_words(SecondNicenessEvaluator, input_string))
change += happiness_score[r][l] if change > biggest_change: biggest_change = change return biggest_change happiness_score = defaultdict(dict) for line in get_input_lines(): tokens = line.rstrip('.').split() left, _, effect, amount = tokens[:4] right = tokens[-1] score = int(amount) if effect == 'gain' else -int(amount) happiness_score[left][right] = score guests = list(happiness_score.keys()) print_answer(1, compute_change(guests, happiness_score)) for key in list(happiness_score.keys()): happiness_score[key]['nerdzila'] = 0 happiness_score['nerdzila'][key] = 0 guests.append('nerdzila') print_answer(2, compute_change(guests, happiness_score))
# -*- coding: utf-8 -*- from itertools import combinations from functools import reduce from operator import mul from advent_tools import get_input_lines, print_answer total_area, ribbon_length = (0, 0) for line in get_input_lines(): dimensions = list(map(int, line.strip().split("x"))) rectangle_sides = list(combinations(dimensions, 2)) rectangle_areas = [x * y for x, y in rectangle_sides] slack = min(rectangle_areas) total_area += sum(2 * area for area in rectangle_areas) total_area += slack perimeters = [2 * x + 2 * y for x, y in rectangle_sides] ribbon_length += min(perimeters) ribbon_length += reduce(mul, dimensions) print_answer(1, total_area) print_answer(2, ribbon_length)
def move(current_pos, direction): shift = shifts[direction] return (current_pos[0] + shift[0], current_pos[1] + shift[1]) instructions = get_input_string() position = (0, 0) visited = {position} for direction in instructions: position = move(position, direction) visited.add(position) print_answer(1, len(visited)) santa = (0, 0) robo_santa = (0, 0) visited = {(0, 0)} for idx, direction in enumerate(instructions): if idx % 2 == 0: santa = move(santa, direction) visited.add(santa) else: robo_santa = move(robo_santa, direction) visited.add(robo_santa) print_answer(2, len(visited))
def increment_password(string): stop_increments = False inverted_result = '' for char in string[::-1]: if stop_increments: inverted_result += char else: next_codepoint = ord(char) + 1 if next_codepoint > CODEPOINT_LIMIT: inverted_result += chr(CODEPOINT_START) else: inverted_result += chr(next_codepoint) stop_increments = True return inverted_result[::-1] password = input('Password: ') while not is_valid_password(password): password = increment_password(password) print_answer(1, password) password = increment_password(password) while not is_valid_password(password): password = increment_password(password) print_answer(2, password)
from advent_tools import print_answer puzzle_input = input('Puzzle input: ') def transform(line): line += '*' last_cut = 0 sequences = [] for offset, left, right in zip(range(1, len(line)), line[:-1], line[1:]): if left != right: sequences.append(line[last_cut:offset]) last_cut = offset result = '' for seq in sequences: result += str(len(seq)) result += seq[0] return result for _ in range(40): puzzle_input = transform(puzzle_input) print_answer(1, len(puzzle_input)) for _ in range(10): puzzle_input = transform(puzzle_input) print_answer(2, len(puzzle_input))
return range(self.x_start, self.x_end + 1) def y_range(self): return range(self.y_start, self.y_end + 1) class UpdatedInstruction(Instruction): CALLBACKS = { 'turn on': (lambda x: x + 1), 'turn off': (lambda x: 0 if x - 1 < 0 else x - 1), 'toggle': (lambda x: x + 2) } g1 = BinaryGrid(1000, 1000, 0) g2 = BinaryGrid(1000, 1000, 0) for line in get_input_lines(): print(line) first = Instruction(line) second = UpdatedInstruction(line) for x in first.x_range(): for y in second.y_range(): g1.update(x, y, first.command) g2.update(x, y, second.command) print_answer(1, sum(g1.grid)) print_answer(2, sum(g2.grid))
# -*- coding: utf-8 -*- import re from advent_tools import get_input_lines, print_answer decode_pattern = re.compile(r'(\\\\)|(\\\")|(\\x[0-9a-f]{2})') encoding_subs = [(re.compile(r'\\'), r'\\\\'), (re.compile(r'\"'), r'\\"')] total_code_chars = 0 total_memory_size = 0 total_encoded_size = 0 for line in get_input_lines(): meaty_part = line[1:-1] mem_length = len(decode_pattern.sub('?', meaty_part)) total_code_chars += len(line) total_memory_size += mem_length encoded_line = line for pattern, sub in encoding_subs: encoded_line = pattern.sub(sub, encoded_line) encoded_line = '"{}"'.format(encoded_line) total_encoded_size += len(encoded_line) print_answer(1, total_code_chars - total_memory_size) print_answer(2, total_encoded_size - total_code_chars)