From 9e9e556c734717faf092acf8ac7857c2519772f1 Mon Sep 17 00:00:00 2001 From: Oliver-Akins Date: Sun, 6 Dec 2020 20:33:17 -0700 Subject: [PATCH] Add code for 2015 advent that I did historically. --- day_1/info.md | 10 ++++++ day_1/part_1.py | 13 ++++++++ day_1/part_2.py | 23 ++++++++++++++ day_2/info.md | 3 ++ day_2/part_1.ts | 21 ++++++++++++ day_2/part_2.py | 16 ++++++++++ day_2/part_2.ts | 29 +++++++++++++++++ day_3/info.md | 5 +++ day_3/part_1.py | 37 ++++++++++++++++++++++ day_3/part_2.py | 54 +++++++++++++++++++++++++++++++ day_4/info.md | 1 + day_4/solution.py | 19 +++++++++++ day_5/info.md | 1 + day_5/part_1.py | 33 +++++++++++++++++++ day_5/part_2.py | 21 ++++++++++++ day_6/info.md | 1 + day_6/part_1.py | 56 ++++++++++++++++++++++++++++++++ day_6/part_2.py | 56 ++++++++++++++++++++++++++++++++ day_7/info.md | 1 + day_7/part_1.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++ day_8/info.md | 1 + day_8/solution.py | 25 +++++++++++++++ day_9/info.md | 6 ++++ day_9/part_1.py | 69 ++++++++++++++++++++++++++++++++++++++++ day_9/text.js | 16 ++++++++++ 25 files changed, 598 insertions(+) create mode 100644 day_1/info.md create mode 100644 day_1/part_1.py create mode 100644 day_1/part_2.py create mode 100644 day_2/info.md create mode 100644 day_2/part_1.ts create mode 100644 day_2/part_2.py create mode 100644 day_2/part_2.ts create mode 100644 day_3/info.md create mode 100644 day_3/part_1.py create mode 100644 day_3/part_2.py create mode 100644 day_4/info.md create mode 100644 day_4/solution.py create mode 100644 day_5/info.md create mode 100644 day_5/part_1.py create mode 100644 day_5/part_2.py create mode 100644 day_6/info.md create mode 100644 day_6/part_1.py create mode 100644 day_6/part_2.py create mode 100644 day_7/info.md create mode 100644 day_7/part_1.py create mode 100644 day_8/info.md create mode 100644 day_8/solution.py create mode 100644 day_9/info.md create mode 100644 day_9/part_1.py create mode 100644 day_9/text.js diff --git a/day_1/info.md b/day_1/info.md new file mode 100644 index 0000000..4f8d0bb --- /dev/null +++ b/day_1/info.md @@ -0,0 +1,10 @@ +Problem: https://adventofcode.com/2015/day/1 + + +Part 1: +Calculating the delta + + +Part 2: +Calculating the first step in the instructions to cause Santa to go into the +basement \ No newline at end of file diff --git a/day_1/part_1.py b/day_1/part_1.py new file mode 100644 index 0000000..51da3b4 --- /dev/null +++ b/day_1/part_1.py @@ -0,0 +1,13 @@ +data = input("Input Instruction set: \n") + + +# floor_delta = 0 + +# for char in data: +# if char == "(": floor_delta += 1 +# elif char == ")": floor_delta -= 1 + + +# This is equivalent to commented out code above +# DONE FOR FUN, Wouldn't use in production... +print(sum([ 1 if char == "(" else -1 for char in data])) \ No newline at end of file diff --git a/day_1/part_2.py b/day_1/part_2.py new file mode 100644 index 0000000..8da8c86 --- /dev/null +++ b/day_1/part_2.py @@ -0,0 +1,23 @@ +data = input("Input Instruction set: \n") + +floor_delta = 0 +first_negative_instruction = None + + +# Run through instruction set +for index in range(len(data)): + char = data[index] + + # Increment floor delta + if char == "(": + floor_delta += 1 + + # Decrement floor delta and track what the first index that causes us to go + # negative is. + elif char == ")": + floor_delta -= 1 + if floor_delta == -1 and not first_negative_instruction: + first_negative_instruction = index + 1 + break + +print(f"First Negative Instruction: {first_negative_instruction}") \ No newline at end of file diff --git a/day_2/info.md b/day_2/info.md new file mode 100644 index 0000000..3621ae3 --- /dev/null +++ b/day_2/info.md @@ -0,0 +1,3 @@ +https://adventofcode.com/2015/day/2 + +`2*l*w + 2*w*h + 2*h*l + min(l*w, w*h, h*l)` \ No newline at end of file diff --git a/day_2/part_1.ts b/day_2/part_1.ts new file mode 100644 index 0000000..ab69540 --- /dev/null +++ b/day_2/part_1.ts @@ -0,0 +1,21 @@ +// @ts-ignore +import { readFileSync } from "fs"; + + +let data: string = readFileSync("input", "utf-8"); + +let surface_area_sum: number = 0; + +for (var dimensions of data.split("\n")) { + let dimension_array: string[] = dimensions.split("x"); + + let l: number = parseInt(dimension_array[0]), + w: number = parseInt(dimension_array[1]), + h: number = parseInt(dimension_array[2]); + + let surface_area: number = (2*l*w + 2*l*h + 2*h*w + Math.min(l*w, l*h, h*w)); + + surface_area_sum = surface_area_sum + surface_area; +}; + +console.log(`Total Surface Area Needed Of Wrapping Paper: ${surface_area_sum}`); \ No newline at end of file diff --git a/day_2/part_2.py b/day_2/part_2.py new file mode 100644 index 0000000..0b6efd7 --- /dev/null +++ b/day_2/part_2.py @@ -0,0 +1,16 @@ +ribbon_sum = 0 + + +with open("input", "r") as data: + + + for line in data: + dimensions = line.split("x") + l, w, h = [int(x) for x in dimensions] + + min_perimeter = min(l+l+w+w, l+l+h+h, h+h+w+w) + volume = l * w * h + + ribbon_sum += min_perimeter + volume + +print(ribbon_sum) \ No newline at end of file diff --git a/day_2/part_2.ts b/day_2/part_2.ts new file mode 100644 index 0000000..5e0312c --- /dev/null +++ b/day_2/part_2.ts @@ -0,0 +1,29 @@ +// @ts-ignore +import { readFileSync } from "fs"; + + +let data: string = readFileSync("input", "utf-8"); + + +let ribbon_sum: number = 0; + +for (var line of data.split(`\n`)) { + let dimensions: string[] = line.split("x", 3); + + let l = parseInt(dimensions[0]); + let w = parseInt(dimensions[1]); + let h = parseInt(dimensions[2]); + + let min_perimeter: number = Math.min( + l+l+w+w, + l+l+h+h, + w+w+h+h + ); + + let volume: number = l * w * h; + + ribbon_sum = ribbon_sum + min_perimeter + volume; +}; + + +console.log(`Ribbon Length Needed: ${ribbon_sum}`); \ No newline at end of file diff --git a/day_3/info.md b/day_3/info.md new file mode 100644 index 0000000..d7f252f --- /dev/null +++ b/day_3/info.md @@ -0,0 +1,5 @@ +https://adventofcode.com/2015/day/3 + + +north (`^`), south (`v`), east (`>`), or west (`<`) + diff --git a/day_3/part_1.py b/day_3/part_1.py new file mode 100644 index 0000000..8a1f8c3 --- /dev/null +++ b/day_3/part_1.py @@ -0,0 +1,37 @@ +# with open("input", "r") as data: +data = input() + +unique_houses = 1 +current_coord = [0, 0] +historic_coords = [f"{current_coord[0]},{current_coord[1]}"] + + + +# Get each instruction +for direction in data: + + # Heading north + if direction == "^": current_coord[1] += 1 + + # Heading south + elif direction == "v": current_coord[1] -= 1 + + # Heading west + elif direction == "<": current_coord[0] -= 1 + + # Heading east + elif direction == ">": current_coord[0] += 1 + + # Unknown input + else: raise Exception(f"InputError: Unexpected input: {direction}") + + # Check if we've been here already + coord_string = f"{current_coord[0]},{current_coord[1]}" + if not (coord_string in historic_coords): + + # New house, keep track of it + unique_houses += 1 + historic_coords += [coord_string] + + +print(f"Total Houses With At Least One Present: {unique_houses}") \ No newline at end of file diff --git a/day_3/part_2.py b/day_3/part_2.py new file mode 100644 index 0000000..5a9c225 --- /dev/null +++ b/day_3/part_2.py @@ -0,0 +1,54 @@ +# with open("input", "r") as data: +data = input() + +unique_houses = 1 +santa_coord = [0, 0] +robo_coord = [0, 0] +historic_coords = [f"0,0"] +is_real_santa = True + + + +# Get each instruction +for direction in data: + + # Heading north + if direction == "^": + if is_real_santa: santa_coord[1] += 1 + else: robo_coord[1] += 1 + + # Heading south + elif direction == "v": + if is_real_santa: santa_coord[1] -= 1 + else: robo_coord[1] -= 1 + + # Heading west + elif direction == "<": + if is_real_santa: santa_coord[0] -= 1 + else: robo_coord[0] -= 1 + + # Heading east + elif direction == ">": + if is_real_santa: santa_coord[0] += 1 + else: robo_coord[0] += 1 + + # Unknown input + else: raise Exception(f"InputError: Unexpected input: {direction}") + + + # Get coordinate string + if is_real_santa: coord_string = f"{santa_coord[0]},{santa_coord[1]}" + else: f"{robo_coord[0]},{robo_coord[1]}" + + + # Check if we've been here already + if not (coord_string in historic_coords): + + # New house, keep track of it + unique_houses += 1 + historic_coords += [coord_string] + + is_real_santa = not is_real_santa + + +print(f"Total Houses With At Least One Present: {unique_houses}") \ No newline at end of file diff --git a/day_4/info.md b/day_4/info.md new file mode 100644 index 0000000..9c7a6d0 --- /dev/null +++ b/day_4/info.md @@ -0,0 +1 @@ +https://adventofcode.com/2015/day/4 \ No newline at end of file diff --git a/day_4/solution.py b/day_4/solution.py new file mode 100644 index 0000000..15b175a --- /dev/null +++ b/day_4/solution.py @@ -0,0 +1,19 @@ +import hashlib + +passkey = input("Input passkey here: ") + + +def find_suffix(passkey, leading_zeroes): + hexkey = "" + suffix = 0 + + while hexkey[:leading_zeroes] != "0" * leading_zeroes: + suffix += 1 + hashkey = hashlib.md5(f"{passkey}{suffix}".encode()) + hexkey = hashkey.hexdigest() + + return suffix + + +print(f"Part 1 Suffix = {find_suffix(passkey, 5)}") +print(f"Part 2 Suffix = {find_suffix(passkey, 6)}") \ No newline at end of file diff --git a/day_5/info.md b/day_5/info.md new file mode 100644 index 0000000..f61d47d --- /dev/null +++ b/day_5/info.md @@ -0,0 +1 @@ +https://adventofcode.com/2015/day/5 \ No newline at end of file diff --git a/day_5/part_1.py b/day_5/part_1.py new file mode 100644 index 0000000..4f67ecb --- /dev/null +++ b/day_5/part_1.py @@ -0,0 +1,33 @@ +import re + + +forbidden_sequences = [ "ab", "cd", "pq", "xy" ] +double_letter_pattern = r"(?P[A-Za-z])(?P=char)" + + +def has_three_vowels(string): + vowel_count = 0 + for char in string: + if char in "aeiou": + vowel_count += 1 + return vowel_count >= 3 + + +def has_double_letter(string): + return re.search(double_letter_pattern, string) != None + + +def no_forbidden_sequences(string): + for sequence in forbidden_sequences: + if sequence in string: + return False + return True + + +total_nice_lines = 0 +data = open("input", "r") +for line in data: + if has_three_vowels(line) and has_double_letter(line) and no_forbidden_sequences(line): + total_nice_lines += 1 +data.close() +print(f"Total Nice Lines: {total_nice_lines}") \ No newline at end of file diff --git a/day_5/part_2.py b/day_5/part_2.py new file mode 100644 index 0000000..c9c1a8e --- /dev/null +++ b/day_5/part_2.py @@ -0,0 +1,21 @@ +import re + +double_letter_pattern = r"(?P[A-Za-z]{2})\w*(?P=chars)" +triple_letter_pattern = r"(?P[A-Za-z])\w(?P=chars)" + + +def is_nice(string): + return ( + re.search(double_letter_pattern, string) != None + and + re.search(triple_letter_pattern, string) != None + ) + + +total_nice_lines = 0 +data = open("input", "r") +for line in data: + if is_nice(line): + total_nice_lines += 1 +data.close() +print(f"Total Nice Lines: {total_nice_lines}") \ No newline at end of file diff --git a/day_6/info.md b/day_6/info.md new file mode 100644 index 0000000..c7e669e --- /dev/null +++ b/day_6/info.md @@ -0,0 +1 @@ +https://adventofcode.com/2015/day/6 \ No newline at end of file diff --git a/day_6/part_1.py b/day_6/part_1.py new file mode 100644 index 0000000..6c1a27f --- /dev/null +++ b/day_6/part_1.py @@ -0,0 +1,56 @@ +import re + +height = 1000 +width = 1000 + +lights = [] + +for row in range(height): + lights.append([]) + for _ in range(width): + lights[row].append(False) + +pattern = r"^(?Ptoggle|turn on|turn off) (?P\d+),(?P\d+)[\sA-Za-z]+(?P\d+),(?P\d+)$" + + + +def light_range(coord1x, coord1y, coord2x, coord2y): + coord1x = int(coord1x) + coord1y = int(coord1y) + coord2x = int(coord2x) + coord2y = int(coord2y) + for row in range(coord1y, coord2y + 1): + for col in range(coord1x, coord2x + 1): + yield (row, col) + + + +data = open("input", "r") +for instruction in data: + + # Parse instruction + match = re.match(pattern, instruction) + instruction_type = match.group("type") + + coordinate_generator = light_range( + match.group("coord1x"), match.group("coord1y"), + match.group("coord2x"), match.group("coord2y") + ) + + for coord in coordinate_generator: + if instruction_type == "toggle": + lights[coord[0]][coord[1]] = not lights[coord[0]][coord[1]] + elif instruction_type == "turn on": + lights[coord[0]][coord[1]] = True + elif instruction_type == "turn off": + lights[coord[0]][coord[1]] = False + else: + raise Exception(f"Input Error: Invalid instruction: \"{instruction_type}\"") + +lights_on = 0 +for row in lights: + for light in row: + if light: + lights_on += 1 + +print(f"Total lights on: {lights_on}") \ No newline at end of file diff --git a/day_6/part_2.py b/day_6/part_2.py new file mode 100644 index 0000000..ae6e315 --- /dev/null +++ b/day_6/part_2.py @@ -0,0 +1,56 @@ +import re + +height = 1000 +width = 1000 + +lights = [] + +for row in range(height): + lights.append([]) + for _ in range(width): + lights[row].append(0) + +pattern = r"^(?Ptoggle|turn on|turn off) (?P\d+),(?P\d+)[\sA-Za-z]+(?P\d+),(?P\d+)$" + + + +def light_range(coord1x, coord1y, coord2x, coord2y): + coord1x = int(coord1x) + coord1y = int(coord1y) + coord2x = int(coord2x) + coord2y = int(coord2y) + for row in range(coord1y, coord2y + 1): + for col in range(coord1x, coord2x + 1): + yield (row, col) + + + +data = open("input", "r") +for instruction in data: + + # Parse instruction + match = re.match(pattern, instruction) + instruction_type = match.group("type") + + coordinate_generator = light_range( + match.group("coord1x"), match.group("coord1y"), + match.group("coord2x"), match.group("coord2y") + ) + + for coord in coordinate_generator: + if instruction_type == "toggle": + lights[coord[0]][coord[1]] += 2 + elif instruction_type == "turn on": + lights[coord[0]][coord[1]] += 1 + elif instruction_type == "turn off": + if lights[coord[0]][coord[1]] - 1 >= 0: + lights[coord[0]][coord[1]] -= 1 + else: + raise Exception(f"Input Error: Invalid instruction: \"{instruction_type}\"") + +brightness = 0 +for row in lights: + for light in row: + brightness += light + +print(f"Total Brightness: {brightness}") \ No newline at end of file diff --git a/day_7/info.md b/day_7/info.md new file mode 100644 index 0000000..4007c7a --- /dev/null +++ b/day_7/info.md @@ -0,0 +1 @@ +https://adventofcode.com/2015/day/7 \ No newline at end of file diff --git a/day_7/part_1.py b/day_7/part_1.py new file mode 100644 index 0000000..d5cf71c --- /dev/null +++ b/day_7/part_1.py @@ -0,0 +1,81 @@ +from random import randint + +target_key = "a" +values = {} + + +tests = [ + "123 -> x", + "456 -> y", + "x AND y -> d", + "x OR y -> e", + "x LSHIFT 2 -> f", + "y RSHIFT 2 -> g", + "NOT x -> h", + "NOT y -> i" +] + + +def get_operation(instr): + if len(instr) == 3: return "ASSIGNMENT" + elif len(instr) == 4: return "INVERT" + else: return instr[1] + + +def convert_values(op_type, instr): + + def to_int(key): + """ + Helper function to convert a single value in an instruction to an int + """ + try: + return int(key) + except ValueError: + try: + return values[key] + except KeyError: + return None + + if op_type == "INVERT": + instr[1] = to_int(instr[1]) + elif op_type == "ASSIGNMENT": + instr[0] = to_int(instr[0]) + else: + instr[0] = to_int(instr[0]) + instr[2] = to_int(instr[2]) + return instr + + +def execute_operation(op_type, instr): + target = instr[-1] + + if op_type == "ASSIGNMENT": values[target] = instr[0] + elif op_type == "INVERT": values[target] = ~instr[1] + 2**16 + elif op_type == "OR": values[target] = instr[0] | instr[2] + elif op_type == "AND": values[target] = instr[0] & instr[2] + elif op_type == "LSHIFT": values[target] = instr[0] << instr[2] + elif op_type == "RSHIFT": values[target] = instr[0] >> instr[2] + else: raise Exception(f"Input Error: Invalid Operation Type: {op_type}") + + +def run_instruction(instr): + instr = instr.split(" ") + op_type = get_operation(instr) + instr = convert_values(op_type, instr) + + # Ensure all operation parameters were found correctly + if None in instr: return False + execute_operation(op_type, instr) + return True + + +with open("input", "r") as data: + lines = data.readlines() + while "a" not in values: + + random_index = randint(0, len(lines) - 1) + success = run_instruction(lines[random_index].strip()) + if success: + del lines[random_index] + +print(f"Value of A: {values['a']}") \ No newline at end of file diff --git a/day_8/info.md b/day_8/info.md new file mode 100644 index 0000000..817dbc4 --- /dev/null +++ b/day_8/info.md @@ -0,0 +1 @@ +https://adventofcode.com/2015/day/8 \ No newline at end of file diff --git a/day_8/solution.py b/day_8/solution.py new file mode 100644 index 0000000..91a093b --- /dev/null +++ b/day_8/solution.py @@ -0,0 +1,25 @@ +import re + + +def get_code_chars(string): + return len(string) + +def get_mem_chars(string): + return len(eval(f'"{string[1:-1]}"')) + +def get_encoded_size(string): + return len(f'{re.escape(string)}') + 2 + + +with open("input", "r") as data: + encoded_code_sum = 0 + code_char_sum = 0 + mem_char_sum = 0 + for line in data: + line = line.strip() + encoded_code_sum += get_encoded_size(line) + code_char_sum += get_code_chars(line) + mem_char_sum += get_mem_chars(line) + + print(f"Part 1 Solution: {code_char_sum - mem_char_sum}") + print(f"Part 2 Solution: {encoded_code_sum - code_char_sum}") \ No newline at end of file diff --git a/day_9/info.md b/day_9/info.md new file mode 100644 index 0000000..bda57ee --- /dev/null +++ b/day_9/info.md @@ -0,0 +1,6 @@ +https://adventofcode.com/2015/day/9 + + +Part 2 Incorrect Answers: + - `361` + - `764` \ No newline at end of file diff --git a/day_9/part_1.py b/day_9/part_1.py new file mode 100644 index 0000000..28f80b3 --- /dev/null +++ b/day_9/part_1.py @@ -0,0 +1,69 @@ +def find_shortest_distance(directions, location, visited_locations = []): + min_location = ["", None] + + # Iterate through places we can travel to + for direction in directions[location]: + + if direction in visited_locations: + continue + + # find the shortest destination + if min_location[1]: + if directions[location][direction] < min_location[1]: + min_location = [ + direction, + directions[location][direction] + ] + else: + min_location = [ + direction, + directions[location][direction] + ] + return min_location + + + +def find_shortest_route(directions, start): + current_location = start + distance_travelled = 0 + visited_locations = [] + + while len(visited_locations) < len(directions): + shortest_route = find_shortest_distance(directions, current_location, visited_locations) + + if not shortest_route[1]: break + + visited_locations.append(current_location) + distance_travelled += shortest_route[1] + current_location = shortest_route[0] + return distance_travelled + + +def create_map(): + locale = {} + with open("input", "r") as file: + for line in file: + data = line.strip().split() + + # Ensure city hasn't already been assigned + if data[0] not in locale: + locale[data[0]] = {} + locale[data[0]][data[2]] = int(data[-1]) + + # Ensure city hasn't already been assigned + if data[2] not in locale: + locale[data[2]] = {} + locale[data[2]][data[0]] = int(data[-1]) + return locale + + +locations = create_map() +distances = [] + +for location in locations: + distances.append(find_shortest_route( + locations, + location + )) + +print(f"Shortest Route: {min(distances)}") \ No newline at end of file diff --git a/day_9/text.js b/day_9/text.js new file mode 100644 index 0000000..2327822 --- /dev/null +++ b/day_9/text.js @@ -0,0 +1,16 @@ +let potato = { + '.Faerun': {'Norrath': 129, 'Tristram': 58, 'AlphaCentauri': 13, 'Arbre': 24, 'Snowdin': 60, 'Tambi': 71, 'Straylight': 67}, + '.Norrath': {'Faerun': 129, 'Tristram': 142, 'AlphaCentauri': 15, 'Arbre': 135, 'Snowdin': 75, 'Tambi': 82, 'Straylight': 54}, + '.Tristram': {'Faerun': 58, 'Norrath': 142, 'AlphaCentauri': 118, 'Arbre': 122, 'Snowdin': 103, 'Tambi': 49, 'Straylight': 97}, + '.AlphaCentauri': {'Faerun': 13, 'Norrath': 15, 'Tristram': 118, 'Arbre': 116, 'Snowdin': 12, 'Tambi': 18, 'Straylight': 91}, + '.Arbre': {'Faerun': 24, 'Norrath': 135, 'Tristram': 122, 'AlphaCentauri': 116, 'Snowdin': 129, 'Tambi': 53, 'Straylight': 40}, + '.Snowdin': {'Faerun': 60, 'Norrath': 75, 'Tristram': 103, 'AlphaCentauri': 12, 'Arbre': 129, 'Tambi': 15, 'Straylight': 99}, + '.Tambi': {'Faerun': 71, 'Norrath': 82, 'Tristram': 49, 'AlphaCentauri': 18, 'Arbre': 53, 'Snowdin': 15, 'Straylight': 70}, + '.Straylight': {'Faerun': 67, 'Norrath': 54, 'Tristram': 97, 'AlphaCentauri': 91, 'Arbre': 40, 'Snowdin': 99, 'Tambi': 70}}; + +/* +Faerun (0) -> Norrath (+129) -> Tristram (+142) -> Arbre (+122) -> Snowdin (+129) -> Straylight (+99) -> AlphaCentauri (+91) -> Tambi (+15) + +AlphaCentauri (0) -> Tristram (+118) -> Norrath (+142) -> Arbre (+135) -> Snowdin (+129) -> Straylight (+99) -> Tambi (+70) -> Faerun (+71) ==== 764 + +*/ \ No newline at end of file