├── 2018 ├── dec-01 │ ├── script-pt-2.py │ └── script.py ├── dec-02 │ ├── script-pt-2.py │ └── script.py ├── dec-03 │ └── script.py ├── dec-04 │ ├── script-pt-2.py │ └── script.py ├── dec-05 │ └── script.py ├── dec-06 │ ├── script-pt2.py │ └── script.py ├── dec-07 │ ├── script-pt2.py │ └── script.py ├── dec-08 │ └── script.py ├── dec-09 │ └── script.py ├── dec-10 │ └── script.py ├── dec-11 │ └── script.py ├── dec-12 │ └── script.py ├── dec-13 │ └── script.py └── dec-14 │ └── script.py ├── 2019 ├── dec-01 │ └── script.py ├── dec-02 │ └── script.py ├── dec-03 │ └── script.py ├── dec-04 │ └── script.py ├── dec-05 │ └── script.py ├── dec-06 │ └── script.py ├── dec-07 │ └── script.py ├── dec-08 │ └── script.py ├── dec-09 │ └── script.py ├── dec-10 │ └── script.py ├── dec-11 │ └── script.py ├── dec-12 │ └── script.py ├── dec-13 │ └── script.py └── dec-14 │ └── script.py ├── 2020 ├── dec-01 │ └── script.py ├── dec-02 │ └── script.py ├── dec-03 │ └── script.py ├── dec-04 │ └── script.py ├── dec-05 │ └── script.py ├── dec-06 │ └── script.py ├── dec-07 │ └── script.py ├── dec-08 │ └── script.py ├── dec-09 │ └── script.py ├── dec-10 │ └── script.py ├── dec-11 │ ├── script-p2.py │ └── script.py ├── dec-12 │ ├── script-2.py │ └── script.py ├── dec-13 │ └── script.py ├── dec-14 │ ├── script.py │ └── script2.py ├── dec-15 │ └── script.py └── dec-16 │ ├── script-2.py │ └── script.py ├── 2021 ├── 01 │ └── script.py ├── 02 │ └── script.py ├── 03 │ ├── 1.py │ └── 2.py ├── 04 │ ├── 1.py │ └── 2.py └── 06 │ └── 1.py ├── 2022 ├── 01 │ └── script.py ├── 02 │ └── script.py ├── 03 │ └── script.py ├── 04 │ └── script.py ├── 05 │ └── script.py ├── 06 │ └── script.py ├── 07 │ └── script.py └── 08 │ ├── script.py │ └── script2.py └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | input.txt 3 | sample-input.txt 4 | .DS_Store -------------------------------------------------------------------------------- /2018/dec-01/script-pt-2.py: -------------------------------------------------------------------------------- 1 | with open('./input.txt', 'r') as f: 2 | data = [int(i) for i in f] 3 | 4 | def get_first_duplicate_total(data): 5 | total = 0 6 | prev_totals = set([0]) 7 | while True: 8 | for i in data: 9 | total += i 10 | if total in prev_totals: 11 | return total 12 | prev_totals.add(total) 13 | return total 14 | 15 | print(get_first_duplicate_total(data)) -------------------------------------------------------------------------------- /2018/dec-01/script.py: -------------------------------------------------------------------------------- 1 | with open('input.txt', 'r') as data: 2 | total = 0 3 | for line in data: 4 | total += int(line) 5 | print(total) 6 | 7 | # Could also do print(sum(int(i) for i in open('input.txt', 'r'))) -------------------------------------------------------------------------------- /2018/dec-02/script-pt-2.py: -------------------------------------------------------------------------------- 1 | with open('input.txt', 'r') as f: 2 | boxes = [box.strip() for box in f] 3 | 4 | def check_differences(box1, box2): 5 | difference_idx = -1 6 | for idx, letter in enumerate(box1): 7 | if letter != box2[idx]: 8 | if difference_idx < 0: 9 | difference_idx = idx 10 | else: 11 | return False 12 | return box1[0:difference_idx] + box1[difference_idx+1:] 13 | 14 | 15 | def find_one_difference(boxes): 16 | for idx, box in enumerate(boxes): 17 | for box2 in boxes[idx+1:]: 18 | diff = check_differences(box, box2) 19 | if diff: 20 | return diff 21 | 22 | print(find_one_difference(boxes)) -------------------------------------------------------------------------------- /2018/dec-02/script.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | with open('input.txt', 'r') as f: 4 | twice = 0 5 | thrice = 0 6 | for line in f: 7 | counts = Counter(line).values() 8 | if 2 in counts: 9 | twice += 1 10 | if 3 in counts: 11 | thrice += 1 12 | print(twice * thrice) 13 | -------------------------------------------------------------------------------- /2018/dec-03/script.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open('input.txt', 'r') as f: 4 | data = [] 5 | for line in f: 6 | nums = [int(n) for n in re.findall(r'\d+', line)] 7 | data.append({'id': nums[0], 'coordinates': [nums[1], nums[2]], 'dimensions': [nums[3], nums[4]]}) 8 | 9 | 10 | def get_coordinates(coordinates, dimensions): 11 | for x in range(dimensions[0]): 12 | for y in range(dimensions[1]): 13 | yield str(x + coordinates[0]) + "," + str(y + coordinates[1]) 14 | 15 | 16 | def get_overlaps(data): 17 | overlaps = set() 18 | filled = set() 19 | for line in data: 20 | for coord in get_coordinates(line['coordinates'], line['dimensions']): 21 | if coord in filled: 22 | overlaps.add(coord) 23 | else: 24 | filled.add(coord) 25 | return overlaps 26 | 27 | 28 | def no_overlaps(coordinates, dimensions, overlaps): 29 | for coord in get_coordinates(coordinates, dimensions): 30 | if coord in overlaps: 31 | return False 32 | return True 33 | 34 | 35 | def find_no_overlaps(data, overlaps): 36 | for line in data: 37 | if no_overlaps(line['coordinates'], line['dimensions'], overlaps): 38 | return line['id'] 39 | 40 | 41 | overlaps = get_overlaps(data) 42 | # Q1 43 | print(len(overlaps)) 44 | 45 | # Q2 46 | print(find_no_overlaps(data, overlaps)) -------------------------------------------------------------------------------- /2018/dec-04/script-pt-2.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import Counter 3 | 4 | with open('input.txt', 'r') as f: 5 | data = [] 6 | for line in f: 7 | date = line[line.find("[")+1:line.find("]")] 8 | action = line.split("] ")[1].strip() 9 | data.append((date, action,)) 10 | data = sorted(data, key=lambda i: i[0]) 11 | 12 | guards = {} 13 | for time, action in data: 14 | time = int(time[-2:]) 15 | if "Guard" in action: 16 | _id = re.findall(r'\d+', action)[0] 17 | if not _id in guards: 18 | guards[_id] = [] 19 | elif action == "falls asleep": 20 | start = time 21 | else: 22 | guards[_id] += list(range(start, time)) 23 | 24 | max_count = 0 25 | solution = 0 26 | for guard, minutes in guards.items(): 27 | if minutes: 28 | most_frequent = Counter(minutes).most_common(1)[0] 29 | if most_frequent[1] > max_count: 30 | max_count = most_frequent[1] 31 | solution = int(guard) * most_frequent[0] 32 | print(solution) 33 | -------------------------------------------------------------------------------- /2018/dec-04/script.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import Counter 3 | 4 | with open('input.txt', 'r') as f: 5 | data = [] 6 | for line in f: 7 | date = line[line.find("[")+1:line.find("]")] 8 | action = line.split("] ")[1].strip() 9 | data.append((date, action,)) 10 | data = sorted(data, key=lambda i: i[0]) 11 | 12 | guards = {} 13 | for time, action in data: 14 | time = int(time[-2:]) 15 | if "Guard" in action: 16 | _id = re.findall(r'\d+', action)[0] 17 | if not _id in guards: 18 | guards[_id] = {'length': 0, 'minutes': []} 19 | elif action == "falls asleep": 20 | start = time 21 | else: 22 | guards[_id]['length'] += time - start 23 | guards[_id]['minutes'] += list(range(start, time)) 24 | 25 | sleep_longest = max(guards.items(),key=lambda guard: guard[1]['length']) 26 | minutes = sleep_longest[1]['minutes'] 27 | print(Counter(minutes).most_common(1)[0][0] * int(sleep_longest[0])) -------------------------------------------------------------------------------- /2018/dec-05/script.py: -------------------------------------------------------------------------------- 1 | with open('input.txt', 'r') as f: 2 | text = '' 3 | for line in f: 4 | text += line.strip() 5 | 6 | def react(text): 7 | stack = [] 8 | for letter in text: 9 | last = stack[-1] if stack else None 10 | if letter != last and (last == letter.upper() or last == letter.lower()): 11 | stack.pop() 12 | else: 13 | stack.append(letter) 14 | return len(stack) 15 | 16 | # A1 17 | print(react(text)) 18 | 19 | # A2 20 | possibilities = set(text.lower()) 21 | print(min(react(text.replace(p, '').replace(p.upper(), '')) for p in possibilities)) 22 | -------------------------------------------------------------------------------- /2018/dec-06/script-pt2.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | with open('input.txt', 'r') as f: 4 | coords = [] 5 | max_x = 0 6 | max_y = 0 7 | for line in f: 8 | line = [int(i) for i in line.strip().split(', ')] 9 | if line[0] > max_x: max_x = line[0] 10 | if line[1] > max_y: max_y = line[1] 11 | coords.append((line[1], line[0],)) 12 | 13 | n_regions = 0 14 | matrix = [[(0, 0) for i in range(max_x + 2)] for n in range(max_y + 2)] 15 | for r_idx, row in enumerate(matrix): 16 | for c_idx, col in enumerate(row): 17 | total_dist = 0 18 | for idx, (x, y) in enumerate(coords): 19 | dist = abs(x - r_idx) + abs(y - c_idx) 20 | total_dist += dist 21 | if total_dist < 10000: 22 | n_regions += 1 23 | 24 | print(n_regions) -------------------------------------------------------------------------------- /2018/dec-06/script.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def file_cleanup(f): 4 | coords = [] 5 | max_x = 0 6 | max_y = 0 7 | for line in f: 8 | line = [int(i) for i in line.strip().split(', ')] 9 | max_x, max_y = max(max_x, line[0]), max(max_y, line[1]) 10 | coords.append((line[1], line[0],)) 11 | return max_x, max_y, coords 12 | 13 | 14 | def empty_matrix(max_x, max_y): 15 | return [[(0, 0) for i in range(max_x + 2)] for n in range(max_y + 2)] 16 | 17 | 18 | def find_closest(coords, max_x, max_y): 19 | matrix = empty_matrix(max_x, max_y) 20 | for idx, (x, y) in enumerate(coords): 21 | matrix[x][y] = (idx+1, 0,) 22 | for r_idx, row in enumerate(matrix): 23 | for c_idx, col in enumerate(row): 24 | dist = abs(x - r_idx) + abs(y - c_idx) 25 | if col[0] == 0 or dist < col[1]: 26 | matrix[r_idx][c_idx] = (idx+1, dist,) 27 | elif dist == col[1] and col[0] != idx+1: 28 | matrix[r_idx][c_idx] = (None, dist,) 29 | return matrix 30 | 31 | 32 | with open('input.txt', 'r') as f: 33 | max_x, max_y, coords = file_cleanup(f) 34 | 35 | matrix = find_closest(coords, max_x, max_y) 36 | 37 | matrix = [[i[0] for i in sublist] for sublist in matrix] 38 | flipped_matrix = matrix[::-1] 39 | to_filter = set(matrix[0] + matrix[-1] + flipped_matrix[0] + flipped_matrix[-1]) 40 | list_matrix = [] 41 | 42 | for row in matrix: 43 | for col in row: 44 | if col not in to_filter: 45 | list_matrix.append(col) 46 | 47 | 48 | print(Counter(list_matrix).most_common(1)[0][1]) 49 | -------------------------------------------------------------------------------- /2018/dec-07/script-pt2.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from string import ascii_uppercase 3 | import re 4 | 5 | def clean_input(data): 6 | relationships = defaultdict(set) 7 | for line in data: 8 | _, parent, child = re.findall(r'[A-Z]', line) 9 | relationships[child].add(parent) 10 | if parent not in relationships: 11 | relationships[parent] = set() 12 | return relationships 13 | 14 | 15 | def letter_to_number(letter): 16 | return ascii_uppercase.index(letter) + 61 17 | 18 | 19 | def find_time(relationships): 20 | total = 0 21 | done = [] 22 | N_WORKERS = 5 23 | enqueued = [None] * N_WORKERS 24 | 25 | while len(done) < len(relationships): 26 | print(enqueued) 27 | for i, value in enumerate(enqueued): 28 | if value: 29 | letter, time = value 30 | if time == 1: 31 | done.append(letter) 32 | enqueued[i] = None 33 | else: 34 | enqueued[i][1] -= 1 35 | for node in relationships: 36 | letters_enqueued = [i[0] for i in enqueued if i] 37 | if node not in done and node not in letters_enqueued and relationships[node].issubset(done) and None in enqueued: 38 | enqueued[enqueued.index(None)] = [node, letter_to_number(node)] 39 | total += 1 40 | return total - 1 41 | 42 | 43 | with open ('input.txt', 'r') as f: 44 | relationships = clean_input(f) 45 | 46 | print(find_time(relationships)) 47 | -------------------------------------------------------------------------------- /2018/dec-07/script.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | import re 3 | 4 | def clean_input(data): 5 | relationships = defaultdict(set) 6 | for line in data: 7 | _, parent, child = re.findall(r'[A-Z]', line) 8 | relationships[child].add(parent) 9 | if parent not in relationships: 10 | relationships[parent] = set() 11 | return relationships 12 | 13 | 14 | def find_order(relationships): 15 | done = [] 16 | while len(done) < len(relationships): 17 | ready = [] 18 | for node in relationships: 19 | if node not in done and relationships[node].issubset(done): 20 | ready.append(node) 21 | done.append(sorted(ready)[0]) 22 | return done 23 | 24 | 25 | with open ('input.txt', 'r') as f: 26 | relationships = clean_input(f) 27 | 28 | print(''.join(find_order(relationships))) 29 | -------------------------------------------------------------------------------- /2018/dec-08/script.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | with open('input.txt', 'r') as f: 4 | data = deque() 5 | for line in f: 6 | for val in line.split(' '): 7 | data.append(int(val)) 8 | 9 | 10 | class Tree: 11 | def __init__(self, data): 12 | self.n_children = data.popleft() 13 | self.n_metadata = data.popleft() 14 | self.children = [Tree(data) for _ in range(self.n_children)] 15 | self.metadata = [data.popleft() for _ in range(self.n_metadata)] 16 | 17 | def get_total(self): 18 | return sum(self.metadata) + sum(child.get_total() for child in self.children) 19 | 20 | def get_child_value(self, child): 21 | if child < len(self.children): 22 | return self.children[child].get_root_value() 23 | return 0 24 | 25 | def get_root_value(self): 26 | if not self.children: return sum(self.metadata) 27 | total = 0 28 | for idx in self.metadata: 29 | total += self.get_child_value(idx - 1) # Index starts at 1 not 0 :( 30 | return total 31 | 32 | 33 | tree = Tree(data) 34 | print(tree.get_total()) 35 | print(tree.get_root_value()) -------------------------------------------------------------------------------- /2018/dec-09/script.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import deque 3 | 4 | def get_sequence(max, players): 5 | sequence = deque() 6 | scores = [0] * players 7 | for marble in range(0, max + 1): 8 | if marble % 23 == 0 and marble > 0: 9 | current_player = marble % players 10 | sequence.rotate(-7) 11 | scores[current_player] += marble + sequence.pop() 12 | else: 13 | sequence.rotate(2) 14 | sequence.append(marble) 15 | return scores 16 | 17 | 18 | with open('input.txt', 'r') as f: 19 | for line in f: 20 | players, last_marble = [int(n) for n in re.findall(r'\d+', line)] 21 | scores = get_sequence(last_marble, players) 22 | print(max(scores)) 23 | large_scores = get_sequence(last_marble * 100, players) 24 | print(max(large_scores)) 25 | -------------------------------------------------------------------------------- /2018/dec-10/script.py: -------------------------------------------------------------------------------- 1 | import re 2 | import math 3 | import time 4 | 5 | class CoordinatePlane: 6 | def __init__(self, values): 7 | self.values = [Point(*value) for value in values] 8 | 9 | def x_vals(self): 10 | vals = [val.x for val in self.values] 11 | return min(vals), max(vals) 12 | 13 | def y_vals(self): 14 | vals = [val.y for val in self.values] 15 | return min(vals), max(vals) 16 | 17 | def draw(self): 18 | min_x, max_x = self.x_vals() 19 | min_y, max_y = self.y_vals() 20 | if max_x - min_x > 100 or max_y - min_y > 100: return 21 | grid = [['.' for _ in range(min_x, max_x+1)] for _ in range(min_y, max_y+1)] 22 | for value in self.values: 23 | grid[value.y - min_y][value.x - min_x] = 'X' 24 | for row in grid: 25 | print(''.join(row)) 26 | time.sleep(2) 27 | print('\n\n\n') 28 | 29 | def increment(self): 30 | for value in self.values: 31 | value.move() 32 | 33 | 34 | class Point: 35 | def __init__(self, x, y, x_speed, y_speed): 36 | self.x = x 37 | self.y = y 38 | self.x_speed = x_speed 39 | self.y_speed = y_speed 40 | 41 | def move(self): 42 | self.x += self.x_speed 43 | self.y += self.y_speed 44 | 45 | 46 | with open('sample-input.txt', 'r') as f: 47 | values = [] 48 | for line in f: 49 | x, y, x_speed, y_speed = [int(n) for n in re.findall(r'[+-]?\d+', line)] 50 | values.append((x, y, x_speed, y_speed,)) 51 | plane = CoordinatePlane(values) 52 | speed = 0 53 | while True: 54 | print(speed) 55 | plane.draw() 56 | plane.increment() 57 | speed += 1 -------------------------------------------------------------------------------- /2018/dec-11/script.py: -------------------------------------------------------------------------------- 1 | SERIAL_NUMBER = 1308 2 | 3 | def get_power_level(x, y): 4 | rack_id = x + 10 5 | power_level = rack_id * y 6 | power_level += SERIAL_NUMBER 7 | power_level *= rack_id 8 | hundreds_digit = int(str(power_level)[-3]) if power_level > 100 else 0 9 | return hundreds_digit - 5 10 | 11 | 12 | def gen_grid(): 13 | grid = [] 14 | for x in range(300): 15 | row = [] 16 | for y in range(300): 17 | row.append(get_power_level(x+1, y+1)) 18 | grid.append(row) 19 | return grid 20 | 21 | 22 | def get_box(grid, row, col, size): 23 | _sum = 0 24 | for x in range(0, size): 25 | for y in range(0, size): 26 | _sum += grid[row + x][col + y] 27 | return _sum 28 | 29 | 30 | def find_max_subgrid(grid): 31 | max_sum = 0 32 | coordinates = [0, 0] 33 | for size in range(3, 300): 34 | for i in range(300 - size): 35 | for j in range(300 - size): 36 | box_sum = get_box(grid, i, j, size) 37 | if box_sum > max_sum: 38 | max_sum = box_sum 39 | coordinates = [i + 1, j + 1, size] 40 | print(coordinates, size, max_sum) 41 | return coordinates, max_sum 42 | 43 | 44 | print(find_max_subgrid(gen_grid())) -------------------------------------------------------------------------------- /2018/dec-12/script.py: -------------------------------------------------------------------------------- 1 | with open('sample-input.txt', 'r') as f: 2 | rules = {} 3 | for idx, line in enumerate(f): 4 | if idx == 0: 5 | state = line.strip() 6 | elif idx > 1: 7 | rule = line.strip().split(" => ") 8 | rules[rule[0]] = rule[1] 9 | 10 | 11 | def get_score(state, n_change): 12 | n_change *= -1 13 | score = 0 14 | for l in state: 15 | if l == "#": 16 | score += n_change 17 | n_change += 1 18 | return score 19 | 20 | 21 | n_change = 0 22 | for _ in range(20): #1000 for large input 23 | n_change += 4 24 | state = "...." + state + "...." 25 | new_state = "" 26 | for idx, val in enumerate(state): 27 | left_chunk = state[idx-2:idx] 28 | right_chunk = state[idx+1:idx+3] 29 | chunk = left_chunk + val + right_chunk 30 | if chunk in rules: 31 | new_state += rules[chunk] 32 | else: 33 | new_state += "." 34 | start = 0 35 | while new_state[start] == ".": 36 | start += 1 37 | n_change -= start 38 | end = len(new_state) - 1 39 | while new_state[end] == ".": 40 | end -= 1 41 | state = new_state[start:end+1] 42 | 43 | # uncomment for pt2 44 | # score = get_score(state, n_change) 45 | # print(((50_000_000_000 - 1000) * 42) + score) 46 | 47 | print(get_score(state, n_change)) -------------------------------------------------------------------------------- /2018/dec-13/script.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | 3 | with open('input.txt', 'r') as f: 4 | grid = [] 5 | for line in f: 6 | grid.append(list(line.replace('\n', ''))) 7 | 8 | 9 | increments = { 10 | '<': [-1, 0], 11 | '>': [1, 0], 12 | 'v': [0, 1], 13 | '^': [0, -1] 14 | } 15 | 16 | intersections = { 17 | "left": { 18 | "v": ">", 19 | "^": "<", 20 | ">": "^", 21 | "<": "v" 22 | }, 23 | "right": { 24 | "v": "<", 25 | "^": ">", 26 | ">": "v", 27 | "<": "^" 28 | } 29 | } 30 | 31 | curves = { 32 | "/": { 33 | "v": "<", 34 | "^": ">", 35 | ">": "^", 36 | "<": "v" 37 | }, 38 | "\\": { 39 | "v": ">", 40 | "^": "<", 41 | ">": "v", 42 | "<": "^" 43 | } 44 | } 45 | 46 | directions = ["left", "straight", "right", "straight"] 47 | 48 | def change_directions(direction): 49 | if direction == "left": 50 | return "straight" 51 | if direction == "right": 52 | return "left" 53 | if direction == "straight": 54 | return "right" 55 | 56 | class Cart: 57 | def __init__(self, x, y, direction): 58 | self.x = x 59 | self.y = y 60 | self.direction = direction 61 | self.turn = "left" 62 | 63 | def __repr__(self): 64 | return f'x={self.x} y={self.y} direction={self.direction} turn={self.turn}' 65 | 66 | def move_straight(self): 67 | x_move, y_move = increments[self.direction] 68 | self.x += x_move 69 | self.y += y_move 70 | 71 | def intersection(self): 72 | if self.turn != "straight": 73 | self.direction = intersections[self.turn][self.direction] 74 | self.move_straight() 75 | self.turn = change_directions(self.turn) 76 | 77 | def curve(self, curve): 78 | self.direction = curves[curve][self.direction] 79 | self.move_straight() 80 | 81 | def coordinates(self): 82 | return f'{self.x},{self.y}' 83 | 84 | def move(self): 85 | move = grid[self.y][self.x] 86 | if move == "|" or move == "-": 87 | self.move_straight() 88 | elif move == "+": 89 | self.intersection() 90 | elif move == "/" or move == "\\": 91 | self.curve(move) 92 | else: 93 | print("whatthefuck") 94 | 95 | 96 | carts = [] 97 | for y, row in enumerate(grid): 98 | for x, col in enumerate(row): 99 | if col in "<>v^": 100 | carts.append(Cart(x, y, col)) 101 | 102 | 103 | def clean_original(grid): 104 | for x, row in enumerate(grid): 105 | for y, col in enumerate(row): 106 | if col == ">" or col == "<": 107 | grid[x][y] = "-" 108 | elif col == "^" or col == "v": 109 | grid[x][y] = "|" 110 | return grid 111 | 112 | 113 | def format_grid(grid): 114 | for cart in carts: 115 | grid[cart.y][cart.x] = cart.direction 116 | for row in grid: 117 | print(''.join(row)) 118 | 119 | 120 | def last_survivor(carts): 121 | while len(carts) > 1: 122 | seen = set(cart.coordinates() for cart in carts) 123 | for cart in carts: 124 | if cart.coordinates() in seen: 125 | seen.remove(cart.coordinates()) 126 | cart.move() 127 | if cart.coordinates() in seen: 128 | seen.remove(cart.coordinates()) 129 | else: 130 | seen.add(cart.coordinates()) 131 | carts = [cart for cart in carts if cart.coordinates() in seen] 132 | return carts[0] 133 | 134 | 135 | def get_collision(carts): 136 | seen = set() 137 | for cart in carts: 138 | cart.move() 139 | if (cart.x, cart.y,) in seen: 140 | return cart 141 | seen.add((cart.x, cart.y,)) 142 | return get_collision(carts) 143 | 144 | grid = clean_original(grid) 145 | print(get_collision(deepcopy(carts))) 146 | print(last_survivor(carts)) 147 | -------------------------------------------------------------------------------- /2018/dec-14/script.py: -------------------------------------------------------------------------------- 1 | vals = [3, 7] 2 | a_idx, b_idx = 0, 1 3 | 4 | INPUT_SCORE = 894501 5 | 6 | def get_new_score(a, b): 7 | return [int(i) for i in str(a + b)] 8 | 9 | def increase_idx(idx): 10 | return (idx + int(vals[idx]) + 1) % len(vals) 11 | 12 | # Part 1 13 | for _ in range(10 + INPUT_SCORE): 14 | vals += get_new_score(vals[a_idx], vals[b_idx]) 15 | a_idx, b_idx = increase_idx(a_idx), increase_idx(b_idx) 16 | 17 | print(''.join(str(val) for val in vals)[INPUT_SCORE:INPUT_SCORE+10]) 18 | 19 | 20 | INPUT_SCORE = str(INPUT_SCORE) 21 | 22 | # Part 2 23 | while True: 24 | vals += get_new_score(vals[a_idx], vals[b_idx]) 25 | p1, p2 = ''.join(str(i) for i in vals[-len(INPUT_SCORE):]), ''.join(str(i) for i in vals[-len(INPUT_SCORE) - 1: -1]) 26 | if INPUT_SCORE == p1 or INPUT_SCORE == p2: 27 | to_s = ''.join(str(i) for i in vals) 28 | print(to_s.find(INPUT_SCORE)) 29 | break 30 | a_idx, b_idx = increase_idx(a_idx), increase_idx(b_idx) 31 | -------------------------------------------------------------------------------- /2019/dec-01/script.py: -------------------------------------------------------------------------------- 1 | from math import floor 2 | 3 | # Part 1 4 | def get_fuel(mass): 5 | return floor(mass / 3) - 2 6 | 7 | # Part 2 8 | def get_fuel_recursive(mass, running_sum=0): 9 | if mass <= 0: return running_sum 10 | new_fuel = get_fuel(mass) 11 | return get_fuel_recursive(new_fuel, running_sum + max(0, new_fuel)) 12 | 13 | 14 | recursive_sum = 0 15 | non_recursive_sum = 0 16 | with open("input.txt") as _file: 17 | for line in _file: 18 | mass = int(line) 19 | recursive_sum += get_fuel_recursive(mass) 20 | non_recursive_sum += get_fuel(mass) 21 | 22 | print(f"Part 1: {non_recursive_sum}") 23 | print(f"Part 2: {recursive_sum}") 24 | -------------------------------------------------------------------------------- /2019/dec-02/script.py: -------------------------------------------------------------------------------- 1 | def calculate(num1, num2, nums): 2 | nums[1] = num1 3 | nums[2] = num2 4 | idx = 0 5 | while nums[idx] != 99: 6 | num = nums[idx] 7 | val1 = nums[nums[idx + 1]] 8 | val2 = nums[nums[idx + 2]] 9 | idx3 = nums[idx + 3] 10 | if num == 1: 11 | nums[idx3] = val1 + val2 12 | elif num == 2: 13 | nums[idx3] = val1 * val2 14 | idx += 4 15 | return nums[0] 16 | 17 | 18 | with open("input.txt") as _file: 19 | for line in _file: 20 | input_values = [int(num) for num in line.split(",")] 21 | # part 1 22 | print(f"Part 1: {calculate(12, 2, input_values[:])}") 23 | 24 | # part 2 25 | GOAL = 19690720 26 | for i in range(100): 27 | for j in range(100): 28 | if calculate(i, j, input_values[:]) == GOAL: 29 | print(f"Part 2: {100 * i + j}") 30 | break 31 | -------------------------------------------------------------------------------- /2019/dec-03/script.py: -------------------------------------------------------------------------------- 1 | def format_coords(coords): 2 | return [(val[0], int(val[1:])) for val in coords.split(",")] 3 | 4 | DIRECTIONS = {"R": (1, 0), "L": (-1, 0), "U": (0, 1), "D": (0, -1)} 5 | 6 | def find_points(paths): 7 | points = {} 8 | 9 | x = 0 10 | y = 0 11 | steps = 0 12 | 13 | for direction, distance in paths: 14 | for point in range(distance): 15 | x_change, y_change = DIRECTIONS[direction] 16 | x += x_change 17 | y += y_change 18 | steps += 1 19 | points[(x, y)] = steps 20 | 21 | return points 22 | 23 | 24 | def intersections(points1, points2): 25 | return set(points1.keys()).intersection(set(points2.keys())) 26 | 27 | 28 | def manhattan_distances(points): 29 | return [abs(x) + abs(y) for x, y in points] 30 | 31 | 32 | def least_steps(intersections, points1, points2): 33 | return [points1[point] + points2[point] for point in intersections] 34 | 35 | 36 | with open("input.txt") as _file: 37 | paths1 = format_coords(_file.readline()) 38 | points1 = find_points(paths1) 39 | 40 | paths2 = format_coords(_file.readline()) 41 | points2 = find_points(paths2) 42 | 43 | intersections = intersections(points1, points2) 44 | 45 | print(f"Part 1: {min(manhattan_distances(intersections))}") 46 | 47 | print(f"Part 1: {min(least_steps(intersections, points1, points2))}") -------------------------------------------------------------------------------- /2019/dec-04/script.py: -------------------------------------------------------------------------------- 1 | def check_ascending(n): 2 | return "".join(sorted(n)) == n 3 | 4 | 5 | def check_repeat(n): 6 | for digit1, digit2 in zip(n, n[1:]): 7 | if digit1 == digit2: 8 | return True 9 | 10 | 11 | def check_two_consecutive_digits(n): 12 | repeat_count = 0 13 | for n1, n2 in zip(n, n[1:]): 14 | if n1 == n2: 15 | repeat_count += 1 16 | else: 17 | if repeat_count == 1: 18 | return True 19 | repeat_count = 0 20 | return repeat_count == 1 21 | 22 | 23 | p1_count = 0 24 | p2_count = 0 25 | 26 | for n in range(134792, 675811): 27 | n = str(n) 28 | if check_ascending(n): 29 | if check_repeat(n): 30 | p1_count += 1 31 | if check_two_consecutive_digits(n): 32 | p2_count += 1 33 | 34 | print(f"Part 1: {p1_count}") 35 | print(f"Part 2: {p2_count}") 36 | -------------------------------------------------------------------------------- /2019/dec-05/script.py: -------------------------------------------------------------------------------- 1 | def get_modes(modes): 2 | return [int(mode) for mode in [modes[2], modes[1], modes[0], modes[3:]]] 3 | 4 | 5 | def get_param(mode, increment, idx, data): 6 | if mode == 0: 7 | return data[data[idx + increment]] 8 | return data[idx + increment] 9 | 10 | def get_params(mode1, mode2, idx, data): 11 | return get_param(mode1, 1, idx, data), get_param(mode2, 2, idx, data) 12 | 13 | 14 | def call_operation(mode1, mode2, idx, data, operation): 15 | param1, param2 = get_params(mode1, mode2, idx, data) 16 | return operation(param1, param2), idx + 4 17 | 18 | def add(param1, param2): 19 | return param1 + param2 20 | 21 | def multiply(param1, param2): 22 | return param1 * param2 23 | 24 | def less_than(param1, param2): 25 | return 1 if param1 < param2 else 0 26 | 27 | def equals(param1, param2): 28 | return 1 if param1 == param2 else 0 29 | 30 | def jump_if_true(mode1, mode2, idx, data): 31 | param1, param2 = get_params(mode1, mode2, idx, data) 32 | return param2 if param1 != 0 else idx + 3 33 | 34 | def jump_if_false(mode1, mode2, idx, data): 35 | param1, param2 = get_params(mode1, mode2, idx, data) 36 | return param2 if param1 == 0 else idx + 3 37 | 38 | 39 | def calculate(data, input_val): 40 | idx = 0 41 | diagnostic_code = None 42 | while data[idx] != 99: 43 | mode1, mode2, mode3, opcode = get_modes(f"{data[idx]:05}") 44 | OPERATIONS = {1: add, 2: multiply, 7: less_than, 8: equals} 45 | if opcode in OPERATIONS: 46 | data[data[idx + 3]], idx = call_operation( 47 | mode1, mode2, idx, data, OPERATIONS[opcode] 48 | ) 49 | elif opcode == 3: 50 | data[data[idx + 1]] = input_val 51 | idx += 2 52 | elif opcode == 4: 53 | diagnostic_code = data[data[idx + 1]] 54 | idx += 2 55 | elif opcode == 5: 56 | idx = jump_if_true(mode1, mode2, idx, data) 57 | elif opcode == 6: 58 | idx = jump_if_false(mode1, mode2, idx, data) 59 | return diagnostic_code 60 | 61 | 62 | with open("input.txt") as _file: 63 | for line in _file: 64 | input_vals = [int(num) for num in line.split(",")] 65 | print(f"Part 1: {calculate(input_vals[:], 1)}") 66 | print(f"Part 2: {calculate(input_vals[:], 5)}") 67 | 68 | -------------------------------------------------------------------------------- /2019/dec-06/script.py: -------------------------------------------------------------------------------- 1 | def get_data(_file): 2 | orbits = {} 3 | objects = set() 4 | 5 | for line in _file: 6 | to_orbit, orbiter = line.rstrip().split(")") 7 | orbits[orbiter] = to_orbit 8 | objects.add(to_orbit) 9 | objects.add(orbiter) 10 | 11 | return orbits, objects 12 | 13 | 14 | def get_orbit(current_obj, orbits): 15 | if current_obj not in orbits: return [] 16 | return [orbits[current_obj]] + get_orbit(orbits[current_obj], orbits) 17 | 18 | 19 | def get_total_orbits(orbits, objects): 20 | return sum(len(get_orbit(obj, orbits)) for obj in objects) 21 | 22 | 23 | def get_path_between(start, end, orbits): 24 | start_path, end_path = get_orbit(start, orbits), get_orbit(end, orbits) 25 | # Get the first point that is in both paths 26 | overlapping_point = [i for i in start_path if i in end_path][0] 27 | return start_path.index(overlapping_point) + end_path.index(overlapping_point) 28 | 29 | 30 | with open("input.txt") as _file: 31 | orbits, objects = get_data(_file) 32 | 33 | print(f"Part 1: {get_total_orbits(orbits, objects)}") 34 | print(f'Part 2: {get_path_between("YOU", "SAN", orbits)}') 35 | -------------------------------------------------------------------------------- /2019/dec-07/script.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | 3 | def get_permutations(li): 4 | for permutation in permutations(li): 5 | yield permutation 6 | 7 | def get_modes(modes): 8 | return [int(mode) for mode in [modes[2], modes[1], modes[0], modes[3:]]] 9 | 10 | 11 | class Computer: 12 | def __init__(self, data): 13 | self.idx = 0 14 | self.data = data[:] 15 | self.done = False 16 | self.output = None 17 | self.inputs = [] 18 | 19 | def get_params(self, mode1, mode2): 20 | return self.get_param(mode1, 1), self.get_param(mode2, 2) 21 | 22 | def get_param(self, mode, increment): 23 | if mode == 0: 24 | return self.data[self.data[self.idx + increment]] 25 | return self.data[self.idx + increment] 26 | 27 | def add(self, mode1, mode2): 28 | param1, param2 = self.get_params(mode1, mode2) 29 | self.data[self.data[self.idx + 3]] = param1 + param2 30 | self.idx += 4 31 | 32 | def multiply(self, mode1, mode2): 33 | param1, param2 = self.get_params(mode1, mode2) 34 | self.data[self.data[self.idx + 3]] = param1 * param2 35 | self.idx += 4 36 | 37 | def take_input(self): 38 | self.data[self.data[self.idx + 1]] = self.inputs.pop(0) 39 | self.idx += 2 40 | 41 | def create_output(self): 42 | self.output = self.data[self.data[self.idx + 1]] 43 | self.idx += 2 44 | return self.output 45 | 46 | def less_than(self, mode1, mode2): 47 | param1, param2 = self.get_params(mode1, mode2) 48 | self.data[self.data[self.idx + 3]] = 1 if param1 < param2 else 0 49 | self.idx += 4 50 | 51 | def equals(self, mode1, mode2): 52 | param1, param2 = self.get_params(mode1, mode2) 53 | self.data[self.data[self.idx + 3]] = 1 if param1 == param2 else 0 54 | self.idx += 4 55 | 56 | def jump_if_true(self, mode1, mode2): 57 | param1, param2 = self.get_params(mode1, mode2) 58 | self.idx = param2 if param1 != 0 else self.idx + 3 59 | 60 | def jump_if_false(self, mode1, mode2): 61 | param1, param2 = self.get_params(mode1, mode2) 62 | self.idx = param2 if param1 == 0 else self.idx + 3 63 | 64 | def calculate(self, input_val): 65 | self.inputs.append(input_val) 66 | modes = { 67 | 1: lambda: self.add(mode1, mode2), 68 | 2: lambda: self.multiply(mode1, mode2), 69 | 3: lambda: self.take_input(), 70 | 5: lambda: self.jump_if_true(mode1, mode2), 71 | 6: lambda: self.jump_if_false(mode1, mode2), 72 | 7: lambda: self.less_than(mode1, mode2), 73 | 8: lambda: self.equals(mode1, mode2) 74 | } 75 | while True: 76 | mode1, mode2, mode3, opcode = get_modes(f"{self.data[self.idx]:05}") 77 | if opcode in modes: 78 | modes[opcode]() 79 | elif opcode == 4: 80 | return self.create_output() 81 | elif opcode == 99: 82 | self.done = True 83 | return self.output 84 | 85 | 86 | def max_output_signal(input_vals): 87 | max_output_signal = 0 88 | for permutation in get_permutations([0, 1, 2, 3, 4]): 89 | output_signal = 0 90 | for input_signal in permutation: 91 | computer = Computer(input_vals) 92 | computer.inputs.append(input_signal) 93 | output_signal = computer.calculate(output_signal) 94 | max_output_signal = max(max_output_signal, output_signal) 95 | return max_output_signal 96 | 97 | 98 | def max_output_signal_feedback_loop(input_vals): 99 | max_output_signal = 0 100 | for permutation in get_permutations([5, 6, 7, 8, 9]): 101 | computers = [Computer(input_vals) for _ in range(5)] 102 | output_signal = 0 103 | for computer, phase_setting in zip(computers, permutation): 104 | computer.inputs.append(phase_setting) 105 | while computers[-1].done == False: 106 | for computer in computers: 107 | output_signal = computer.calculate(output_signal) 108 | max_output_signal = max(output_signal, max_output_signal) 109 | return max_output_signal 110 | 111 | 112 | 113 | with open("input.txt") as _file: 114 | for line in _file: 115 | input_vals = [int(num) for num in line.split(",")] 116 | print(f"Part 1: {max_output_signal(input_vals)}") 117 | print(f"Part 2: {max_output_signal_feedback_loop(input_vals)}") -------------------------------------------------------------------------------- /2019/dec-08/script.py: -------------------------------------------------------------------------------- 1 | def get_layer(data, y=1, x=1): 2 | start = 0 3 | while start < len(data): 4 | yield data[start:start + (x * y)] 5 | start += x * y 6 | 7 | def get_pixel(layers, idx): 8 | for layer in layers: 9 | if layer[idx] == "1": 10 | return "1" 11 | elif layer[idx] == "0": 12 | return " " 13 | 14 | 15 | LAYER_HEIGHT = 6 16 | LAYER_WIDTH = 25 17 | 18 | with open('input.txt') as _file: 19 | data = _file.read() 20 | layers = [layer for layer in get_layer(data, LAYER_HEIGHT, LAYER_WIDTH)] 21 | least_zeroes = sorted(layers, key=lambda x: x.count("0"))[0] 22 | print(f'Part 1: {least_zeroes.count("1") * least_zeroes.count("2")}') 23 | 24 | stacked_pixels = "" 25 | for coordinate in range(LAYER_HEIGHT * LAYER_WIDTH): 26 | stacked_pixels += get_pixel(layers, coordinate) 27 | 28 | start = 0 29 | print("Part 2: ") 30 | for layer in get_layer(stacked_pixels, LAYER_WIDTH): 31 | print(''.join(layer)) 32 | 33 | 34 | -------------------------------------------------------------------------------- /2019/dec-09/script.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | 3 | def get_permutations(li): 4 | for permutation in permutations(li): 5 | yield permutation 6 | 7 | def get_modes(modes): 8 | return [int(mode) for mode in [modes[2], modes[1], modes[0], modes[3:]]] 9 | 10 | 11 | class Computer: 12 | def __init__(self, data): 13 | self.idx = 0 14 | self.data = data[:] + [0] * 3000 15 | self.done = False 16 | self.output = None 17 | self.inputs = [] 18 | self.relative_base = 0 19 | 20 | def get_params(self, mode1, mode2, mode3): 21 | return self.get_param(mode1, 1), self.get_param(mode2, 2), self.get_param(mode3, 3) 22 | 23 | def get_param(self, mode, increment): 24 | if mode == 0: 25 | return self.data[self.idx + increment] 26 | elif mode == 1: 27 | return self.idx + increment 28 | else: 29 | return self.relative_base + self.data[self.idx + increment] 30 | 31 | def add(self, mode1, mode2, mode3): 32 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 33 | self.data[param3] = self.data[param1] + self.data[param2] 34 | self.idx += 4 35 | 36 | def multiply(self, mode1, mode2, mode3): 37 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 38 | self.data[param3] = self.data[param1] * self.data[param2] 39 | self.idx += 4 40 | 41 | def take_input(self, mode1): 42 | param1 = self.get_param(mode1, 1) 43 | self.data[param1] = self.inputs.pop(0) 44 | self.idx += 2 45 | 46 | def create_output(self, mode1): 47 | param1 = self.get_param(mode1, 1) 48 | self.output = self.data[param1] 49 | self.idx += 2 50 | return self.output 51 | 52 | def less_than(self, mode1, mode2, mode3): 53 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 54 | self.data[param3] = 1 if self.data[param1] < self.data[param2] else 0 55 | self.idx += 4 56 | 57 | def equals(self, mode1, mode2, mode3): 58 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 59 | self.data[param3] = 1 if self.data[param1] == self.data[param2] else 0 60 | self.idx += 4 61 | 62 | def jump_if_true(self, mode1, mode2, mode3): 63 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 64 | self.idx = self.data[param2] if self.data[param1] != 0 else self.idx + 3 65 | 66 | def jump_if_false(self, mode1, mode2, mode3): 67 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 68 | self.idx = self.data[param2] if self.data[param1] == 0 else self.idx + 3 69 | 70 | def relative_offset(self, mode1): 71 | param1 = self.get_param(mode1, 1) 72 | self.relative_base += self.data[param1] 73 | self.idx += 2 74 | 75 | def calculate(self, input_val): 76 | self.inputs.append(input_val) 77 | modes = { 78 | 1: lambda: self.add(mode1, mode2, mode3), 79 | 2: lambda: self.multiply(mode1, mode2, mode3), 80 | 3: lambda: self.take_input(mode1), 81 | 5: lambda: self.jump_if_true(mode1, mode2, mode3), 82 | 6: lambda: self.jump_if_false(mode1, mode2, mode3), 83 | 7: lambda: self.less_than(mode1, mode2, mode3), 84 | 8: lambda: self.equals(mode1, mode2, mode3), 85 | 9: lambda: self.relative_offset(mode1) 86 | } 87 | while True: 88 | mode1, mode2, mode3, opcode = get_modes(f"{self.data[self.idx]:05}") 89 | if opcode in modes: 90 | modes[opcode]() 91 | elif opcode == 4: 92 | return self.create_output(mode1) 93 | elif opcode == 99: 94 | self.done = True 95 | return self.output 96 | 97 | 98 | with open("input.txt") as _file: 99 | for line in _file: 100 | input_vals = [int(num) for num in line.split(",")] 101 | computer = Computer(input_vals) 102 | print(f"Part 1: {computer.calculate(1)}") 103 | 104 | computer = Computer(input_vals) 105 | print(f"Part 2: {computer.calculate(2)}") 106 | -------------------------------------------------------------------------------- /2019/dec-10/script.py: -------------------------------------------------------------------------------- 1 | from math import atan2, sqrt, degrees, pi 2 | from collections import defaultdict 3 | 4 | def angle(point1, point2): 5 | x1, y1 = point1 6 | x2, y2 = point2 7 | # atan2 will give us different degrees for different 8 | # distances: https://gamedev.stackexchange.com/questions/14602/what-are-atan-and-atan2-used-for-in-games 9 | return atan2(y2 - y1, x2 - x1) 10 | 11 | 12 | def distance(point1, point2): 13 | x1, y1 = point1 14 | x2, y2 = point2 15 | 16 | return sqrt((x2 - x1)**2 + (y2 - y1)**2) 17 | 18 | 19 | def get_points(_file): 20 | points = [] 21 | for y, line in enumerate(_file): 22 | for x, char in enumerate(line): 23 | if char == "#": 24 | points.append((x, y)) 25 | return points 26 | 27 | 28 | def get_best_location(points): 29 | visibilities = [(p1, len(set(angle(p1, p2) for p2 in points))) for p1 in points] 30 | return max(visibilities, key=lambda point: point[1]) 31 | 32 | 33 | def get_visibilities(best_point, points): 34 | visibilities = defaultdict(list) 35 | points.remove(best_point) 36 | for point in points: 37 | line = degrees(angle(point, best_point)) 38 | visibilities[line].append((point, distance(point, best_point))) 39 | return visibilities 40 | 41 | 42 | def sort_by_distance(degrees): 43 | for degree in degrees.keys(): 44 | degrees[degree].sort(key=lambda point: point[1], reverse=True) 45 | 46 | 47 | def get_quadrants(angles): 48 | quadrant1 = sorted([angle for angle in angles.keys() if angle >= 90]) 49 | quadrant2 = sorted([angle for angle in angles.keys() if angle <= -90]) 50 | quadrant3 = sorted([angle for angle in angles.keys() if angle < 0 and angle >= -90]) 51 | quadrant4 = sorted([angle for angle in angles.keys() if angle >= 0 and angle < 90]) 52 | return quadrant1 + quadrant2 + quadrant3 + quadrant4 53 | 54 | 55 | def order_quadrants(angles, quadrants): 56 | ordered_visibilities = {} 57 | 58 | for angle in quadrants: 59 | ordered_visibilities[angle] = visibilities[angle] 60 | 61 | return ordered_visibilities 62 | 63 | 64 | def vaporize(visibilities, stop_idx): 65 | pops = 1 66 | while True: 67 | for point in ordered_visibilities.keys(): 68 | if ordered_visibilities[point]: 69 | item = ordered_visibilities[point].pop() 70 | if pops == stop_idx: 71 | return item[0] 72 | pops += 1 73 | 74 | 75 | with open("input.txt") as _file: 76 | points = get_points(_file) 77 | 78 | 79 | best_point, max_visible = get_best_location(points) 80 | print(f"Part 1: {max_visible}") 81 | 82 | visibilities = get_visibilities(best_point, points) 83 | sort_by_distance(visibilities) 84 | 85 | quadrants = get_quadrants(visibilities) 86 | ordered_visibilities = order_quadrants(visibilities, quadrants) 87 | 88 | x, y = vaporize(ordered_visibilities, 200) 89 | print(f"Part 2: {x * 100 + y}") 90 | -------------------------------------------------------------------------------- /2019/dec-11/script.py: -------------------------------------------------------------------------------- 1 | def get_modes(modes): 2 | return [int(mode) for mode in [modes[2], modes[1], modes[0], modes[3:]]] 3 | 4 | 5 | class Computer: 6 | def __init__(self, data): 7 | self.idx = 0 8 | self.data = data[:] + [0] * 3000 9 | self.done = False 10 | self.output = None 11 | self.inputs = [] 12 | self.relative_base = 0 13 | 14 | def get_params(self, mode1, mode2, mode3): 15 | return self.get_param(mode1, 1), self.get_param(mode2, 2), self.get_param(mode3, 3) 16 | 17 | def get_param(self, mode, increment): 18 | if mode == 0: 19 | return self.data[self.idx + increment] 20 | elif mode == 1: 21 | return self.idx + increment 22 | else: 23 | return self.relative_base + self.data[self.idx + increment] 24 | 25 | def add(self, mode1, mode2, mode3): 26 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 27 | self.data[param3] = self.data[param1] + self.data[param2] 28 | self.idx += 4 29 | 30 | def multiply(self, mode1, mode2, mode3): 31 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 32 | self.data[param3] = self.data[param1] * self.data[param2] 33 | self.idx += 4 34 | 35 | def take_input(self, mode1): 36 | param1 = self.get_param(mode1, 1) 37 | self.data[param1] = self.inputs.pop(0) 38 | self.idx += 2 39 | 40 | def create_output(self, mode1): 41 | param1 = self.get_param(mode1, 1) 42 | self.output = self.data[param1] 43 | self.idx += 2 44 | return self.output 45 | 46 | def less_than(self, mode1, mode2, mode3): 47 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 48 | self.data[param3] = 1 if self.data[param1] < self.data[param2] else 0 49 | self.idx += 4 50 | 51 | def equals(self, mode1, mode2, mode3): 52 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 53 | self.data[param3] = 1 if self.data[param1] == self.data[param2] else 0 54 | self.idx += 4 55 | 56 | def jump_if_true(self, mode1, mode2, mode3): 57 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 58 | self.idx = self.data[param2] if self.data[param1] != 0 else self.idx + 3 59 | 60 | def jump_if_false(self, mode1, mode2, mode3): 61 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 62 | self.idx = self.data[param2] if self.data[param1] == 0 else self.idx + 3 63 | 64 | def relative_offset(self, mode1): 65 | param1 = self.get_param(mode1, 1) 66 | self.relative_base += self.data[param1] 67 | self.idx += 2 68 | 69 | def calculate(self, input_val=None): 70 | if input_val is not None: self.inputs.append(input_val) 71 | modes = { 72 | 1: lambda: self.add(mode1, mode2, mode3), 73 | 2: lambda: self.multiply(mode1, mode2, mode3), 74 | 3: lambda: self.take_input(mode1), 75 | 5: lambda: self.jump_if_true(mode1, mode2, mode3), 76 | 6: lambda: self.jump_if_false(mode1, mode2, mode3), 77 | 7: lambda: self.less_than(mode1, mode2, mode3), 78 | 8: lambda: self.equals(mode1, mode2, mode3), 79 | 9: lambda: self.relative_offset(mode1) 80 | } 81 | while True: 82 | mode1, mode2, mode3, opcode = get_modes(f"{self.data[self.idx]:05}") 83 | if opcode in modes: 84 | modes[opcode]() 85 | elif opcode == 4: 86 | return self.create_output(mode1) 87 | elif opcode == 99: 88 | self.done = True 89 | return self.output 90 | 91 | 92 | class Painting: 93 | def __init__(self, input_vals, initial_color=0): 94 | self.computer = Computer(input_vals) 95 | self.direction = 0 96 | self.x, self.y = 0, 0 97 | self.painted = {(self.x, self.y): initial_color} 98 | 99 | def paint(self): 100 | while not self.computer.done: 101 | starting_color = self.painted[(self.x, self.y)] if (self.x, self.y) in self.painted else 0 102 | self.painted[(self.x, self.y)] = self.computer.calculate(starting_color) 103 | self.change_direction(self.computer.calculate()) 104 | self.rotate() 105 | 106 | def change_direction(self, rotate_direction): 107 | if rotate_direction == 0: 108 | self.direction = (self.direction - 1) % 4 109 | else: 110 | self.direction = (self.direction + 1) % 4 111 | 112 | def rotate(self): 113 | if self.direction == 0: 114 | self.y += 1 115 | elif self.direction == 1: 116 | self.x += 1 117 | elif self.direction == 2: 118 | self.y -= 1 119 | elif self.direction == 3: 120 | self.x -= 1 121 | 122 | def show_painting(self): 123 | data = [[" " for _ in range(50)] for _ in range(6)] 124 | for x, y in self.painted.keys(): 125 | color = self.painted[(x, y)] 126 | data[abs(y)][x] = " " if color == 0 else "|" 127 | for row in data: 128 | print(''.join(row)) 129 | 130 | 131 | with open("input.txt") as _file: 132 | for line in _file: 133 | input_vals = [int(num) for num in line.split(",")] 134 | painting = Painting(input_vals) 135 | painting.paint() 136 | print(f"Part 1: {len(painting.painted.keys())}") 137 | 138 | letter_painting = Painting(input_vals, 1) 139 | letter_painting.paint() 140 | print(f"Part 2: ") 141 | letter_painting.show_painting() 142 | -------------------------------------------------------------------------------- /2019/dec-12/script.py: -------------------------------------------------------------------------------- 1 | import re 2 | from itertools import combinations 3 | 4 | 5 | def greatest_common_denominator(a, b): 6 | while b: 7 | a, b = b, a % b 8 | return a 9 | 10 | 11 | def least_common_multiple(a, b): 12 | return (a * b) / greatest_common_denominator(a, b) 13 | 14 | 15 | def create_data(): 16 | points = [] 17 | with open("input.txt") as _file: 18 | for line in _file: 19 | points.append({"coordinate": [int(n) for n in re.findall(r'-?\d+', line)]}) 20 | for point in points: 21 | point["velocity"] = [0, 0, 0] 22 | return points 23 | 24 | 25 | def check_seen(seen, first_overlap, points, move): 26 | for idx, coord in enumerate(seen): 27 | if not first_overlap[idx]: 28 | coords = ''.join([str(i["coordinate"][idx]) for i in points] + [str(i["velocity"][idx]) for i in points]) 29 | if coords not in seen[idx]: 30 | seen[idx].add(coords) 31 | else: 32 | first_overlap[idx] = move 33 | return seen, first_overlap 34 | 35 | 36 | def move_points(points): 37 | for point in points: 38 | for idx, (coord, velocity) in enumerate(zip(point["coordinate"], point["velocity"])): 39 | point["coordinate"][idx] += velocity 40 | return points 41 | 42 | 43 | def change_velocity(points): 44 | point_pairs = combinations(points, 2) 45 | for point, other_point in point_pairs: 46 | for idx, coord in enumerate(point["coordinate"]): 47 | other_coord = other_point["coordinate"][idx] 48 | if coord > other_coord: 49 | point["velocity"][idx] -= 1 50 | other_point["velocity"][idx] += 1 51 | elif coord < other_coord: 52 | point["velocity"][idx] += 1 53 | other_point["velocity"][idx] -= 1 54 | return points 55 | 56 | 57 | def calculate_energy(points): 58 | total_energy = 0 59 | for point in points: 60 | x, y, z = point["coordinate"] 61 | vx, vy, vz = point["velocity"] 62 | total_energy += (abs(x) + abs(y) + abs(z)) * (abs(vx) + abs(vy) + abs(vz)) 63 | print(f"Part 1: {total_energy}") 64 | 65 | 66 | def simulate_motion(points): 67 | seen = [set(), set(), set()] 68 | first_overlap = [None, None, None] 69 | move = 0 70 | while None in first_overlap: 71 | seen, first_overlap = check_seen(seen, first_overlap, points, move) 72 | move += 1 73 | points = change_velocity(points) 74 | points = move_points(points) 75 | if move == 1000: 76 | calculate_energy(points) 77 | return first_overlap 78 | 79 | 80 | points = create_data() 81 | first_overlap = simulate_motion(points) 82 | 83 | print(f"Part 2: {int(least_common_multiple(least_common_multiple(first_overlap[0], first_overlap[1]), first_overlap[2]))}") 84 | -------------------------------------------------------------------------------- /2019/dec-13/script.py: -------------------------------------------------------------------------------- 1 | def get_modes(modes): 2 | return [int(mode) for mode in [modes[2], modes[1], modes[0], modes[3:]]] 3 | 4 | 5 | class Computer: 6 | def __init__(self, data): 7 | self.idx = 0 8 | self.data = data[:] + [0] * 3000 9 | self.done = False 10 | self.output = None 11 | self.inputs = [] 12 | self.relative_base = 0 13 | 14 | def get_params(self, mode1, mode2, mode3): 15 | return self.get_param(mode1, 1), self.get_param(mode2, 2), self.get_param(mode3, 3) 16 | 17 | def get_param(self, mode, increment): 18 | if mode == 0: 19 | return self.data[self.idx + increment] 20 | elif mode == 1: 21 | return self.idx + increment 22 | else: 23 | return self.relative_base + self.data[self.idx + increment] 24 | 25 | def add(self, mode1, mode2, mode3): 26 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 27 | self.data[param3] = self.data[param1] + self.data[param2] 28 | self.idx += 4 29 | 30 | def multiply(self, mode1, mode2, mode3): 31 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 32 | self.data[param3] = self.data[param1] * self.data[param2] 33 | self.idx += 4 34 | 35 | def take_input(self, mode1): 36 | param1 = self.get_param(mode1, 1) 37 | self.data[param1] = input_data 38 | self.idx += 2 39 | 40 | def create_output(self, mode1): 41 | param1 = self.get_param(mode1, 1) 42 | self.output = self.data[param1] 43 | self.idx += 2 44 | return self.output 45 | 46 | def less_than(self, mode1, mode2, mode3): 47 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 48 | self.data[param3] = 1 if self.data[param1] < self.data[param2] else 0 49 | self.idx += 4 50 | 51 | def equals(self, mode1, mode2, mode3): 52 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 53 | self.data[param3] = 1 if self.data[param1] == self.data[param2] else 0 54 | self.idx += 4 55 | 56 | def jump_if_true(self, mode1, mode2, mode3): 57 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 58 | self.idx = self.data[param2] if self.data[param1] != 0 else self.idx + 3 59 | 60 | def jump_if_false(self, mode1, mode2, mode3): 61 | param1, param2, param3 = self.get_params(mode1, mode2, mode3) 62 | self.idx = self.data[param2] if self.data[param1] == 0 else self.idx + 3 63 | 64 | def relative_offset(self, mode1): 65 | param1 = self.get_param(mode1, 1) 66 | self.relative_base += self.data[param1] 67 | self.idx += 2 68 | 69 | def calculate(self, input_val=None): 70 | if input_val is not None: self.inputs.append(input_val) 71 | modes = { 72 | 1: lambda: self.add(mode1, mode2, mode3), 73 | 2: lambda: self.multiply(mode1, mode2, mode3), 74 | 3: lambda: self.take_input(mode1), 75 | 5: lambda: self.jump_if_true(mode1, mode2, mode3), 76 | 6: lambda: self.jump_if_false(mode1, mode2, mode3), 77 | 7: lambda: self.less_than(mode1, mode2, mode3), 78 | 8: lambda: self.equals(mode1, mode2, mode3), 79 | 9: lambda: self.relative_offset(mode1) 80 | } 81 | while True: 82 | mode1, mode2, mode3, opcode = get_modes(f"{self.data[self.idx]:05}") 83 | if opcode in modes: 84 | modes[opcode]() 85 | elif opcode == 4: 86 | return self.create_output(mode1) 87 | elif opcode == 99: 88 | self.done = True 89 | return self.output 90 | 91 | 92 | def parse_file(): 93 | with open("input.txt") as _file: 94 | for line in _file: 95 | return [int(num) for num in line.split(",")] 96 | 97 | 98 | def block_count(data): 99 | computer = Computer(data) 100 | block_count = 0 101 | while not computer.done: 102 | computer.calculate() 103 | computer.calculate() 104 | if computer.calculate() == 2: 105 | block_count += 1 106 | return block_count 107 | 108 | 109 | input_data = 0 110 | def move_joystick(paddle, ball): 111 | global input_data 112 | if paddle[0] < ball[0]: 113 | input_data = 1 114 | elif paddle[0] > ball[0]: 115 | input_data = -1 116 | elif paddle[0] == ball[0]: 117 | input_data = 0 118 | 119 | 120 | def score(data): 121 | data[0] = 2 122 | computer = Computer(data) 123 | score = 0 124 | ball = (0, 0) 125 | paddle = (0, 0) 126 | while not computer.done: 127 | move_joystick(paddle, ball) 128 | 129 | x = computer.calculate(0) 130 | y = computer.calculate() 131 | tile_id = computer.calculate() 132 | 133 | if x == -1 and y == 0: 134 | score = tile_id 135 | else: 136 | if tile_id == 4: 137 | ball = (x, y) 138 | elif tile_id == 3: 139 | paddle = (x, y) 140 | return score 141 | 142 | 143 | input_vals = parse_file() 144 | print(block_count(input_vals)) 145 | print(score(input_vals)) -------------------------------------------------------------------------------- /2019/dec-14/script.py: -------------------------------------------------------------------------------- 1 | chemicals = {} 2 | 3 | with open("input.txt") as _file: 4 | for line in _file: 5 | inp, out = line.strip().split(" => ") 6 | inp_vals = [i.split(", ") for i in inp] 7 | out_vals = [o.split(" ") for o in out] 8 | chemicals[out] = inp 9 | 10 | print(chemicals) -------------------------------------------------------------------------------- /2020/dec-01/script.py: -------------------------------------------------------------------------------- 1 | def part_one(nums, set_nums): 2 | for num in nums: 3 | if 2020 - num in set_nums: 4 | return num * (2020 - num) 5 | 6 | 7 | def part_two(nums, set_nums): 8 | for num in nums: 9 | for num2 in nums: 10 | if (2020 - num - num2) in set_nums: 11 | return num * (2020 - num - num2) * num2 12 | 13 | 14 | with open("input.txt") as _file: 15 | nums = [int(line) for line in _file] 16 | set_nums = set(nums) 17 | 18 | print("Part 1", part_one(nums, set_nums)) 19 | print("Part 2", part_two(nums, set_nums)) 20 | -------------------------------------------------------------------------------- /2020/dec-02/script.py: -------------------------------------------------------------------------------- 1 | def check_count_in_range(password, letter, start, stop): 2 | return password.count(letter) >= start and password.count(letter) <= stop 3 | 4 | 5 | def check_indexes(password, letter, start, stop): 6 | return (password[start] == letter or password[stop] == letter) and (password[start] != password[stop]) 7 | 8 | 9 | with open('input.txt') as file: 10 | letters = [num.split(": ") for num in file] 11 | part1_tally = 0 12 | part2_tally = 0 13 | for policy, password in letters: 14 | length, letter = policy.split(" ") 15 | start, stop = length.split("-") 16 | start, stop = int(start), int(stop) 17 | 18 | # part 1 19 | if check_count_in_range(password, letter, start, stop): part1_tally += 1 20 | 21 | # part 2 22 | if check_indexes(password, letter, start - 1, stop - 1): part2_tally += 1 23 | 24 | 25 | print("Part 1", part1_tally) 26 | print("Part 2", part2_tally) -------------------------------------------------------------------------------- /2020/dec-03/script.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | right_list = [1, 3, 5, 7, 1] 4 | down_list = [1, 1, 1, 1, 2] 5 | 6 | def get_trees_for_slope(right, down, lines): 7 | x = right 8 | y = down 9 | trees = 0 10 | while y < len(lines): 11 | if x > len(lines[y]) - 1: 12 | x = x % len(lines[y]) 13 | if lines[y][x] == '#': 14 | trees += 1 15 | x += right 16 | y += down 17 | return trees 18 | 19 | 20 | with open('input.txt') as inp: 21 | lines = [line for line in inp] 22 | height = len(lines) 23 | width = len(lines[0]) 24 | lines = [list(line.rstrip()) for line in lines] 25 | 26 | print("Part 1", get_trees_for_slope(3, 1, lines)) 27 | 28 | all_trees = 1 29 | for (right, down) in zip(right_list, down_list): 30 | all_trees *= get_trees_for_slope(right, down, lines) 31 | 32 | print("Part 2", all_trees) -------------------------------------------------------------------------------- /2020/dec-04/script.py: -------------------------------------------------------------------------------- 1 | class Validator: 2 | def __init__(self, passport): 3 | self.passport = passport 4 | 5 | def check_field_count(self): 6 | return len(self.passport) == 8 or (len(self.passport) == 7 and 'cid' not in self.passport) 7 | 8 | def check_year(self, key, start, end): 9 | return len(self.passport[key]) == 4 and int(self.passport[key]) >= start and int(self.passport[key]) <= end 10 | 11 | def check_byr(self): 12 | return self.check_year('byr', 1920, 2002) 13 | 14 | def check_iyr(self): 15 | return self.check_year('iyr', 2010, 2020) 16 | 17 | def check_eyr(self): 18 | return self.check_year('eyr', 2020, 2030) 19 | 20 | def check_hcl(self): 21 | return self.passport['hcl'][0] == "#" and self.passport['hcl'][1:].isalnum() 22 | 23 | def check_ecl(self): 24 | return self.passport['ecl'] in ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'] 25 | 26 | def check_pid(self): 27 | return len(self.passport['pid']) == 9 28 | 29 | def check_hgt(self): 30 | if self.passport['hgt'][-2:] == "cm": 31 | return int(self.passport['hgt'][:-2]) >= 150 and int(self.passport['hgt'][:-2]) <= 193 32 | elif self.passport['hgt'][-2:] == "in": 33 | return int(self.passport['hgt'][:-2]) >= 59 and int(self.passport['hgt'][:-2]) <= 76 34 | 35 | def is_valid(self): 36 | return (self.check_field_count() and self.check_byr() and self.check_iyr() and self.check_eyr() 37 | and self.check_hcl() and self.check_ecl() and self.check_pid() and self.check_hgt()) 38 | 39 | 40 | def get_passports(inp): 41 | passports = [] 42 | passport = {} 43 | for line in inp: 44 | if line != "\n": 45 | line = line.rstrip().split(" ") 46 | line = [field.split(":") for field in line] 47 | for field in line: 48 | passport[field[0]] = field[1] 49 | else: 50 | passports.append(passport) 51 | passport = {} 52 | passports.append(passport) 53 | return passports 54 | 55 | 56 | with open('input.txt') as inp: 57 | passports = get_passports(inp) 58 | validators = [Validator(passport) for passport in passports] 59 | part_1_count = 0 60 | part_2_count = 0 61 | for validator in validators: 62 | if validator.check_field_count(): 63 | part_1_count += 1 64 | if validator.is_valid(): 65 | part_2_count += 1 66 | 67 | print(part_1_count) 68 | print(part_2_count) 69 | 70 | -------------------------------------------------------------------------------- /2020/dec-05/script.py: -------------------------------------------------------------------------------- 1 | ROW_COUNT = 127 2 | COL_COUNT = 7 3 | 4 | def binary_search(li, up, down, top): 5 | _min = 0 6 | _max = top 7 | for seat in li: 8 | half = (_max + _min) // 2 9 | if seat == up: 10 | _max = half 11 | elif seat == down: 12 | _min = half + 1 13 | return _min 14 | 15 | 16 | with open('input.txt') as seats: 17 | seat_ids = [] 18 | max_seat = 0 19 | for line in seats: 20 | col = binary_search(line[:7], 'F', 'B', ROW_COUNT) 21 | row = binary_search(line[7:], 'L', 'R', COL_COUNT) 22 | seat_id = col * 8 + row 23 | max_seat = max(max_seat, seat_id) 24 | seat_ids.append(seat_id) 25 | print("Part 1", max_seat) 26 | 27 | seat_ids = sorted(seat_ids) 28 | prev = seat_ids[0] 29 | for seat_id in seat_ids[1:]: 30 | if prev != seat_id - 1: 31 | print("Part 2", prev) 32 | break 33 | prev += 1 34 | -------------------------------------------------------------------------------- /2020/dec-06/script.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def get_group_count(group): 4 | group_count = 0 5 | letter_counts = Counter(group) 6 | for letter in letter_counts: 7 | if letter_counts[letter] == group_len: 8 | group_count += 1 9 | return group_count 10 | 11 | 12 | with open('input.txt') as inp: 13 | group = [] 14 | groups_anyone = [] 15 | groups_everyone = [] 16 | group_len = 0 17 | for line in inp: 18 | if line != "\n": 19 | group_len += 1 20 | for letter in line.rstrip(): 21 | group.append(letter) 22 | else: 23 | groups_everyone.append(get_group_count(group)) 24 | groups_anyone.append(len(set(group))) 25 | group_len = 0 26 | group = [] 27 | 28 | groups_anyone.append(len(set(group))) 29 | groups_everyone.append(get_group_count(group)) 30 | 31 | print("Part 1", sum(groups_anyone)) 32 | print("Part 2", sum(groups_everyone)) 33 | -------------------------------------------------------------------------------- /2020/dec-07/script.py: -------------------------------------------------------------------------------- 1 | # def traverse(val, tree): 2 | # if 'no other' in val: 3 | # return False 4 | # if 'shiny gold' in val: 5 | # return True 6 | # return any([traverse(tree[i], tree) for i in val]) 7 | 8 | 9 | # with open('input.txt') as _file: 10 | # tree = {} 11 | # tally = 0 12 | # for line in _file: 13 | # rule = line.replace("bags", "").replace("bag", "").replace(".", "").rstrip().split(" contain ") 14 | # tree[rule[0]] = [l.lstrip() for l in''.join(letter for letter in rule[1] if letter.isalpha() or letter == " ").rstrip().split(" ")] 15 | # for value in tree.values(): 16 | # if traverse(value, tree): 17 | # tally += 1 18 | # print("Part 1", tally) 19 | 20 | def traverse(key, tree): 21 | if key == 'no other': 22 | return 0 23 | _sum = sum([i for i in tree[key].values()]) 24 | return _sum + sum([tree[key][i] * traverse(i, tree) for i in tree[key]]) 25 | 26 | with open('input.txt') as _file: 27 | tree = {} 28 | tally = 0 29 | for line in _file: 30 | rule = line.replace("bags", "").replace("bag", "").replace(".", "").rstrip().split(" contain ") 31 | rules = rule[1].split(", ") 32 | rule_dict = {} 33 | for color_rule in rules: 34 | color = ''.join(letter for letter in color_rule if letter.isalpha() or letter == " ").strip() 35 | number = int(''.join(num for num in color_rule if num.isdigit())) if 'no' not in color_rule else 0 36 | rule_dict[color] = number 37 | tree[rule[0]] = rule_dict 38 | print("Part 2", traverse('shiny gold', tree)) 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /2020/dec-08/script.py: -------------------------------------------------------------------------------- 1 | lines = [] 2 | with open('input.txt') as file: 3 | for line in file: 4 | line = line.rstrip().split(' ') 5 | lines.append([line[0], int(line[1])]) 6 | 7 | 8 | def move(lines, part_1=False): 9 | seen = set() 10 | accumulator = 0 11 | idx = 0 12 | while True: 13 | if idx >= len(lines): 14 | return accumulator 15 | move, arg = lines[idx] 16 | if idx in seen: 17 | return accumulator if part_1 else False 18 | seen.add(idx) 19 | if move == 'nop': 20 | idx += 1 21 | elif move == 'acc': 22 | accumulator += arg 23 | idx += 1 24 | elif move == "jmp": 25 | idx += arg 26 | 27 | 28 | def flip(val): 29 | return 'jmp' if val == 'nop' else 'nop' 30 | 31 | 32 | def change_piece(lines): 33 | for idx, turn in enumerate(lines): 34 | if turn[0] == 'nop' or turn[0] == 'jmp': 35 | prev = turn[0] 36 | lines[idx][0] = flip(turn[0]) 37 | if accumulator:= move(lines): 38 | return accumulator 39 | lines[idx][0] = prev 40 | 41 | print("Part 1", move(lines, True)) 42 | print("Part 2", change_piece(lines)) 43 | 44 | -------------------------------------------------------------------------------- /2020/dec-09/script.py: -------------------------------------------------------------------------------- 1 | def check_valid(num, stack): 2 | current_sum = 0 3 | for val in stack: 4 | if num - val in stack: 5 | return True 6 | 7 | 8 | looking_for = 1038347917 9 | with open('input.txt') as file: 10 | nums = [int(num) for num in file] 11 | stack = nums[:25] 12 | for num in nums[25:]: 13 | if not check_valid(num, stack): 14 | print("Part 1", num) 15 | break 16 | stack.pop(0) 17 | stack.append(num) 18 | 19 | for idx, num in enumerate(nums): 20 | vals = [num] 21 | tracking_sum = 0 22 | curr_idx = idx 23 | while tracking_sum < looking_for: 24 | tracking_sum += nums[curr_idx] 25 | vals.append(nums[curr_idx]) 26 | curr_idx += 1 27 | if tracking_sum == looking_for: 28 | print("Part 2", max(vals) + min(vals)) 29 | break -------------------------------------------------------------------------------- /2020/dec-10/script.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | with open('input.txt') as file: 4 | voltages = [0] + sorted([int(n) for n in file]) 5 | voltages += [voltages[-1] + 3] 6 | _abs = [] 7 | for v, v1 in zip(voltages, voltages[1:]): 8 | _abs.append(abs(v - v1)) 9 | print(Counter(_abs)) 10 | _sum = 0 11 | 12 | 13 | with open('input.txt') as file: 14 | voltages = [0] + sorted([int(n) for n in file]) 15 | voltages += [voltages[-1] + 3] 16 | set_voltages = set(voltages) 17 | finish = voltages[-1] 18 | diffs = [1, 2, 3] 19 | curr_len = 0 20 | done = 0 21 | val_counts = {0: 1} 22 | new_val_counts = {} 23 | while curr_len <= len(voltages): 24 | for count in val_counts: 25 | for diff in diffs: 26 | _sum = diff + count 27 | if _sum in set_voltages: 28 | if _sum in new_val_counts: 29 | new_val_counts[_sum] += val_counts[count] 30 | else: 31 | new_val_counts[_sum] = val_counts[count] 32 | if finish in new_val_counts: done += new_val_counts[finish] 33 | val_counts = new_val_counts 34 | new_val_counts = {} 35 | curr_len += 1 36 | print(done) 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /2020/dec-11/script-p2.py: -------------------------------------------------------------------------------- 1 | def check_valid_seat(seats, row, col): 2 | if row < 0 or col < 0: 3 | return False 4 | if row >= len(seats): 5 | return False 6 | if col >= len(seats[row]): 7 | return False 8 | return True 9 | 10 | def check_seat(seats, row, col, rd, cd): 11 | row += rd 12 | col += cd 13 | if not check_valid_seat(seats, row, col): return False 14 | while seats[row][col] == '.': 15 | row += rd 16 | col += cd 17 | if not check_valid_seat(seats, row, col): return False 18 | if seats[row][col] =='L': 19 | return False 20 | if seats[row][col] =='#': 21 | return True 22 | return False 23 | 24 | 25 | def count_open(seats, row, col): 26 | count = 0 27 | moves = [0, 1, -1] 28 | for rd in moves: 29 | for cd in moves: 30 | if rd != 0 or cd != 0: 31 | if check_seat(seats, row, col, rd, cd): 32 | count += 1 33 | return count 34 | 35 | 36 | def str_seats(seats): 37 | str_seats = [''.join(line) for line in seats] 38 | return ''.join(str_seats) 39 | 40 | 41 | def pretty_print(seats): 42 | for row in seats: 43 | print(''.join(row)) 44 | print('----------------') 45 | 46 | 47 | with open('input.txt') as file: 48 | seats = [list(row.replace('L', '#').strip()) for row in file] 49 | new_seats = [x[:] for x in seats] 50 | counts = [x[:] for x in seats] 51 | times = 0 52 | while True: 53 | changes = 0 54 | for row_num, row in enumerate(seats): 55 | for col_num, col in enumerate(row): 56 | if col != '.': 57 | count = count_open(seats, row_num, col_num) 58 | counts[row_num][col_num] = str(count) 59 | if col == '#' and count >= 5: 60 | new_seats[row_num][col_num] = 'L' 61 | changes += 1 62 | if col == 'L' and count == 0: 63 | new_seats[row_num][col_num] = '#' 64 | changes += 1 65 | if changes == 0: 66 | print(str_seats(seats).count('#')) 67 | break 68 | times += 1 69 | changes = 0 70 | seats = [x[:] for x in new_seats] 71 | counts = [x[:] for x in new_seats] 72 | 73 | -------------------------------------------------------------------------------- /2020/dec-11/script.py: -------------------------------------------------------------------------------- 1 | def check_seat(seats, row, col): 2 | if row < 0 or col < 0: 3 | return False 4 | if row >= len(seats): 5 | return False 6 | if col >= len(seats[row]): 7 | return False 8 | if seats[row][col] =='L': 9 | return False 10 | if seats[row][col] =='#': 11 | return True 12 | return False 13 | 14 | 15 | def count_open(seats, row, col): 16 | count = 0 17 | if check_seat(seats, row + 1, col): 18 | count += 1 19 | if check_seat(seats, row - 1, col): 20 | count += 1 21 | if check_seat(seats, row, col + 1): 22 | count += 1 23 | if check_seat(seats, row, col - 1): 24 | count += 1 25 | if check_seat(seats, row + 1, col + 1): count += 1 26 | if check_seat(seats, row - 1, col - 1): count += 1 27 | if check_seat(seats, row + 1, col - 1): count += 1 28 | if check_seat(seats, row - 1, col + 1): count += 1 29 | return count 30 | 31 | 32 | def str_seats(seats): 33 | str_seats = [''.join(line) for line in seats] 34 | return ''.join(str_seats) 35 | 36 | def pretty_print(seats): 37 | for row in seats: 38 | print(''.join(row)) 39 | print('----------------') 40 | 41 | with open('input.txt') as file: 42 | seats = [list(row.replace('L', '#').strip()) for row in file] 43 | new_seats = [x[:] for x in seats] 44 | times = 0 45 | while True: 46 | changes = 0 47 | for row_num, row in enumerate(seats): 48 | for col_num, col in enumerate(row): 49 | if col != '.': 50 | count = count_open(seats, row_num, col_num) 51 | if col == '#' and count >= 4: 52 | new_seats[row_num][col_num] = 'L' 53 | changes += 1 54 | if col == 'L' and count == 0: 55 | new_seats[row_num][col_num] = '#' 56 | changes += 1 57 | if changes == 0: 58 | print(str_seats(seats).count('#')) 59 | break 60 | times += 1 61 | changes = 0 62 | seats = [x[:] for x in new_seats] 63 | 64 | -------------------------------------------------------------------------------- /2020/dec-12/script-2.py: -------------------------------------------------------------------------------- 1 | def spin(dir, coord, spin): 2 | directions = ['N', 'E', 'S', 'W'] 3 | to_move = coord // 90 4 | if spin == 'L': to_move *= -1 5 | idx = (directions.index(dir) + to_move) % len(directions) 6 | return directions[idx] 7 | 8 | 9 | def move_waypoint(_dir, oppdir, unit1, unit2, facing1, facing2): 10 | if facing1 == _dir: 11 | unit1 += coord 12 | elif facing1 == oppdir: 13 | unit1 -= coord 14 | elif facing2 == _dir: 15 | unit2 += coord 16 | else: 17 | unit2 -= coord 18 | return unit1, unit2 19 | 20 | with open('input.txt') as file: 21 | ns = 0 22 | es = 0 23 | unit1 = 1 24 | unit2 = 10 25 | facing1 = 'N' 26 | facing2 = 'E' 27 | directions = ['N', 'E', 'S', 'W'] 28 | for move in file: 29 | direction = move[0] 30 | coord = int(move[1:]) 31 | if direction == 'R': 32 | facing1 = spin(facing1, coord, 'R') 33 | facing2 = spin(facing2, coord, 'R') 34 | if direction == 'L': 35 | facing1 = spin(facing1, coord, 'L') 36 | facing2 = spin(facing2, coord, 'L') 37 | if direction == 'F': 38 | if facing1 in ['N', 'S']: 39 | if facing1 == 'S': 40 | ns -= unit1 * coord 41 | else: 42 | ns += unit1 * coord 43 | if facing2 == 'E': 44 | es += unit2 * coord 45 | else: 46 | es -= unit2 * coord 47 | else: 48 | if facing1 == 'E': 49 | es += unit1 * coord 50 | else: 51 | es -= unit1 * coord 52 | if facing2 == 'S': 53 | ns -= unit2 * coord 54 | else: 55 | ns += unit2 * coord 56 | if direction == 'N': 57 | unit1, unit2 = move_waypoint('N', 'S', unit1, unit2, facing1, facing2) 58 | if direction == 'S': 59 | unit1, unit2 = move_waypoint('S', 'N', unit1, unit2, facing1, facing2) 60 | if direction == 'E': 61 | unit1, unit2 = move_waypoint('E', 'W', unit1, unit2, facing1, facing2) 62 | if direction == 'W': 63 | unit1, unit2 = move_waypoint('W', 'E', unit1, unit2, facing1, facing2) 64 | print(abs(ns) + abs(es)) -------------------------------------------------------------------------------- /2020/dec-12/script.py: -------------------------------------------------------------------------------- 1 | with open('input.txt') as file: 2 | n = 0 3 | e = 0 4 | facing = 'E' 5 | directions =['N', 'E', 'S', 'W'] 6 | for move in file: 7 | direction = move[0] 8 | coord = int(move[1:]) 9 | if direction == 'R': 10 | to_move = coord // 90 11 | idx = (directions.index(facing) + to_move) % len(directions) 12 | facing = directions[idx] 13 | if direction == 'L': 14 | to_move = coord // 90 15 | idx = (directions.index(facing) - to_move) % len(directions) 16 | facing = directions[idx] 17 | if direction == 'F': 18 | direction = facing 19 | if direction == 'N': 20 | n += coord 21 | if direction == 'S': 22 | n -= coord 23 | if direction == 'E': 24 | e += coord 25 | if direction == 'W': 26 | e -= coord 27 | print(abs(n) + abs(e)) -------------------------------------------------------------------------------- /2020/dec-13/script.py: -------------------------------------------------------------------------------- 1 | START_TIME = 939 2 | BUSES = [ 3 | 17, 4 | "x", 5 | "x", 6 | "x", 7 | "x", 8 | "x", 9 | "x", 10 | 41, 11 | "x", 12 | "x", 13 | "x", 14 | "x", 15 | "x", 16 | "x", 17 | "x", 18 | "x", 19 | "x", 20 | 937, 21 | "x", 22 | "x", 23 | "x", 24 | "x", 25 | "x", 26 | "x", 27 | "x", 28 | "x", 29 | "x", 30 | "x", 31 | "x", 32 | "x", 33 | "x", 34 | "x", 35 | "x", 36 | "x", 37 | "x", 38 | 13, 39 | "x", 40 | "x", 41 | "x", 42 | "x", 43 | 23, 44 | "x", 45 | "x", 46 | "x", 47 | "x", 48 | "x", 49 | 29, 50 | "x", 51 | 397, 52 | "x", 53 | "x", 54 | "x", 55 | "x", 56 | "x", 57 | 37, 58 | "x", 59 | "x", 60 | "x", 61 | "x", 62 | "x", 63 | "x", 64 | "x", 65 | "x", 66 | "x", 67 | "x", 68 | "x", 69 | "x", 70 | 19, 71 | ] 72 | filtered_buses = [bus for bus in BUSES if bus != "x"] 73 | times = [] 74 | 75 | for bus in filtered_buses: 76 | time = START_TIME // bus 77 | next_time = (time + 1) * bus 78 | times.append(next_time) 79 | 80 | print("Part 1", (min(times) - START_TIME) * filtered_buses[times.index(min(times))]) 81 | 82 | 83 | def extended_euclid(a, b): 84 | # FROM: https://github.com/TheAlgorithms/Python/blob/master/blockchain/chinese_remainder_theorem.py 85 | if b == 0: 86 | return (1, 0) 87 | (x, y) = extended_euclid(b, a % b) 88 | return (y, x - (a // b) * y) 89 | 90 | 91 | def chinese_remainder_theorem(num1, rem1, num2, rem2): 92 | # FROM: https://github.com/TheAlgorithms/Python/blob/master/blockchain/chinese_remainder_theorem.py 93 | (x, y) = extended_euclid(num1, num2) 94 | m = num1 * num2 95 | n = (rem2 * x * num1) + (rem1 * y * num2) 96 | return (m, (n % m + m) % m) 97 | 98 | 99 | print(extended_euclid(19, 13)) 100 | # Solved first by finding the formulae for the sequences. Then in trying to combine, I found 101 | # the Chinese Remainder Theorem. 102 | # I used: https://pages.mtu.edu/~dcclark/MA4908/dnt/chinese3.html and 103 | start_bus = BUSES[0] 104 | start_idx = 0 105 | for idx, bus in enumerate(BUSES[1:]): 106 | if bus == "x": 107 | continue 108 | start_bus, start_idx = chinese_remainder_theorem(start_bus, start_idx, bus, idx + 1) 109 | 110 | print("Part 2", start_bus - start_idx) 111 | -------------------------------------------------------------------------------- /2020/dec-14/script.py: -------------------------------------------------------------------------------- 1 | memories = {} 2 | 3 | def mask_mem(mask, mem): 4 | to_bin = list("{0:b}".format(mem[1]).zfill(36)) 5 | for m, v in mask: 6 | to_bin[m] = v 7 | memories[mem[0]] = int(''.join(to_bin), 2) 8 | 9 | def get_mask_idx(mask): 10 | mask_vals = [] 11 | for idx, val in enumerate(mask): 12 | if val != 'X': 13 | mask_vals.append((idx, val)) 14 | return mask_vals 15 | 16 | with open('input.txt') as file: 17 | mask = '' 18 | mems = [] 19 | for line in file: 20 | line = line.rstrip() 21 | if line.startswith('mask'): 22 | if mask: 23 | mask = get_mask_idx(mask) 24 | for mem in mems: 25 | mask_mem(mask, mem) 26 | mask = line.split("mask = ")[1] 27 | mems = [] 28 | else: 29 | mem = line.split(" = ") 30 | mems.append((int(mem[0][4:-1]), int(mem[1]))) 31 | mask = get_mask_idx(mask) 32 | for mem in mems: 33 | mask_mem(mask, mem) 34 | print(sum(memories.values())) -------------------------------------------------------------------------------- /2020/dec-14/script2.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | 3 | memories = {} 4 | 5 | def mask_mem(maskx, mask1, mem): 6 | to_bin = list("{0:b}".format(mem[0]).zfill(36)) 7 | for m in mask1: 8 | to_bin[m] = '1' 9 | for combo in product([0, 1], repeat=len(maskx)): 10 | for i, m in enumerate(maskx): 11 | to_bin[m] = str(combo[i]) 12 | memories[int(''.join(to_bin), 2)] = mem[1] 13 | 14 | 15 | def get_mask_idx(mask): 16 | mask_1s = [] 17 | mask_xs = [] 18 | for idx, val in enumerate(mask): 19 | if val == '1': 20 | mask_1s.append(idx) 21 | if val == 'X': 22 | mask_xs.append(idx) 23 | return mask_1s, mask_xs 24 | 25 | 26 | with open('input.txt') as file: 27 | mask = '' 28 | mems = [] 29 | for line in file: 30 | line = line.rstrip() 31 | if line.startswith('mask'): 32 | if mask: 33 | mask1, maskx = get_mask_idx(mask) 34 | for mem in mems: 35 | mask_mem(maskx, mask1, mem) 36 | mask = line.split("mask = ")[1] 37 | mems = [] 38 | else: 39 | mem = line.split(" = ") 40 | mems.append((int(mem[0][4:-1]), int(mem[1]))) 41 | mask1, maskx = get_mask_idx(mask) 42 | for mem in mems: 43 | mask_mem(maskx, mask1, mem) 44 | print(sum(memories.values())) -------------------------------------------------------------------------------- /2020/dec-15/script.py: -------------------------------------------------------------------------------- 1 | moves = {} 2 | turns = 1 3 | with open('input.txt') as file: 4 | nums = file.readlines()[0] 5 | nums = [int(n) for n in nums.split(',')] 6 | move = nums.pop() 7 | for n in nums: 8 | moves[n] = turns 9 | turns += 1 10 | 11 | # for the popped move 12 | turns += 1 13 | 14 | while turns < 30000001: 15 | if move in moves: 16 | last_time = moves[move] 17 | next_move = turns - 1 - last_time 18 | else: 19 | next_move = 0 20 | moves[move] = turns - 1 21 | turns += 1 22 | move = next_move 23 | print(move) 24 | -------------------------------------------------------------------------------- /2020/dec-16/script-2.py: -------------------------------------------------------------------------------- 1 | rules = """class: 0-1 or 4-19 2 | row: 0-5 or 8-19 3 | seat: 0-13 or 16-19 4 | """ 5 | 6 | my_ticket = [11,12,13] 7 | 8 | nearby_tickets = """3,9,18 9 | 15,1,5 10 | 5,14,9""" 11 | 12 | nearby_tickets = nearby_tickets.split("\n") 13 | nearby_tickets = [[int(i) for i in n.split(",")] for n in nearby_tickets] 14 | 15 | split_rules = rules.split("\n") 16 | rules = [(rule.split(": ")[1].split(" or ")) for rule in split_rules] 17 | keys = [rule.split(": ")[0] for rule in split_rules] 18 | 19 | ranges = [] 20 | for rule in rules: 21 | _range = set() 22 | for r in rule: 23 | r = r.split('-') 24 | _range.update(range(int(r[0]), int(r[1]) + 1)) 25 | ranges.append(_range) 26 | 27 | def valid_ticket(ticket, ranges): 28 | new_ranges = set() 29 | for r in ranges: 30 | new_ranges.update(r) 31 | for val in ticket: 32 | if val not in new_ranges: 33 | return False 34 | return True 35 | 36 | 37 | def get_possibilities(valid_tickets): 38 | vals = [] 39 | for i in range(0, len(valid_tickets[0])): 40 | v = set(t[i] for t in valid_tickets) 41 | vals.append(v) 42 | return vals 43 | 44 | valid_tickets = [] 45 | for ticket in nearby_tickets: 46 | if valid_ticket(ticket, ranges): 47 | valid_tickets.append(ticket) 48 | 49 | vals = get_possibilities(valid_tickets) 50 | 51 | possibilities = [] 52 | 53 | for t in vals: 54 | p = [] 55 | for idx, r in enumerate(ranges): 56 | if t.issubset(r): 57 | p.append(idx) 58 | possibilities.append(p) 59 | 60 | vals = {} 61 | 62 | while len(vals) < len(possibilities): 63 | for idx, p in enumerate(possibilities): 64 | if len(p) == 1: 65 | val = p[0] 66 | vals[keys[p[0]]] = idx 67 | for x in possibilities: 68 | if val in x: 69 | x.remove(val) 70 | 71 | keys = [] 72 | for x in vals: 73 | if x.startswith("departure"): 74 | keys.append(vals[x]) 75 | 76 | prod = 1 77 | for i in keys: 78 | prod *= my_ticket[i] 79 | print(prod) 80 | -------------------------------------------------------------------------------- /2020/dec-16/script.py: -------------------------------------------------------------------------------- 1 | rules = """class: 0-1 or 4-19 2 | row: 0-5 or 8-19 3 | seat: 0-13 or 16-19""" 4 | 5 | my_ticket = "11,12,13" 6 | 7 | nearby_tickets = """3,9,18 8 | 15,1,5 9 | 5,14,9""" 10 | 11 | nearby_tickets = nearby_tickets.split("\n") 12 | nearby_tickets = [[int(i) for i in n.split(",")] for n in nearby_tickets] 13 | 14 | rules = rules.split("\n") 15 | rules = [(rule.split(": ")[1].split(" or ")) for rule in rules] 16 | ranges = set() 17 | for rule in rules: 18 | for r in rule: 19 | r = r.split('-') 20 | ranges.update(range(int(r[0]), int(r[1]) + 1)) 21 | 22 | invalid_tickets = [] 23 | 24 | for ticket in nearby_tickets: 25 | for val in ticket: 26 | if val not in ranges: 27 | invalid_tickets.append(val) 28 | 29 | print("Part 1", sum(invalid_tickets)) -------------------------------------------------------------------------------- /2021/01/script.py: -------------------------------------------------------------------------------- 1 | 2 | count3 = 0 3 | count = 0 4 | with open('input.txt', 'r') as _file: 5 | li = [int(n) for n in _file] 6 | n = 0 7 | 8 | # Part 1 9 | for i, j in zip(li, li[1:]): 10 | if j > i: 11 | count += 1 12 | 13 | # Part 2 14 | while n < len(li) - 3: 15 | count1 = li[n] + li[n+1] + li[n+2] 16 | count2 = li[n+1] + li[n+2] + li[n+3] 17 | if li[n] + li[n+1] + li[n+2] < li[n+1] + li[n+2] + li[n+3]: 18 | count3 += 1 19 | n += 1 20 | 21 | print(count, count3) -------------------------------------------------------------------------------- /2021/02/script.py: -------------------------------------------------------------------------------- 1 | horizontal1 = 0 2 | depth1 = 0 3 | 4 | horizontal2 = 0 5 | depth2 = 0 6 | aim = 0 7 | 8 | with open('input.txt', 'r') as _file: 9 | li = [n.strip().split(" ") for n in _file] 10 | li = [(n[0], int(n[1])) for n in li] 11 | for direction, coord in li: 12 | if direction == "forward": 13 | horizontal1 += coord 14 | horizontal2 += coord 15 | depth2 += aim * coord 16 | if direction == "down": 17 | aim += coord 18 | depth1 += coord 19 | if direction == "up": 20 | aim -= coord 21 | depth1 -= coord 22 | 23 | print(horizontal1 * depth1) 24 | print(horizontal2 * depth2) -------------------------------------------------------------------------------- /2021/03/1.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | gamma_rate = '' 4 | epsilon_rate = '' 5 | 6 | def most_frequent(grid, col_number): 7 | col = "" 8 | for row in grid: 9 | col += row[col_number] 10 | return Counter(col).most_common(1)[0][0] 11 | 12 | 13 | with open('input.txt', 'r') as _file: 14 | li = [list(n.strip()) for n in _file] 15 | for i in range(len(li[0])): 16 | more_frequent = most_frequent(li, i) 17 | gamma_rate += str(more_frequent) 18 | epsilon_rate += '0' if more_frequent == '1' else '1' 19 | 20 | gamma_rate = int(gamma_rate, 2) 21 | epsilon_rate = int(epsilon_rate, 2) 22 | print(gamma_rate * epsilon_rate) 23 | -------------------------------------------------------------------------------- /2021/03/2.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | gamma_rate = '' 4 | epsilon_rate = '' 5 | 6 | def oxygen(grid, col_number): 7 | col = "" 8 | for row in grid: 9 | col += row[col_number] 10 | return '1' if Counter(col)['1'] >= Counter(col)['0'] else '0' 11 | 12 | def co2(grid, col_number): 13 | col = "" 14 | for row in grid: 15 | col += row[col_number] 16 | return '1' if Counter(col)['0'] > Counter(col)['1'] else '0' 17 | 18 | with open('input.txt', 'r') as _file: 19 | oxyli = [list(n.strip()) for n in _file] 20 | co2li = oxyli[::] 21 | 22 | for i in range(len(oxyli[0])): 23 | more_frequent = oxygen(oxyli, i) 24 | oxyli = [n for n in oxyli if n[i] == more_frequent] 25 | if len(oxyli) == 1: o = int(''.join(oxyli[0]), 2) 26 | 27 | least_frequent = co2(co2li, i) 28 | co2li = [n for n in co2li if n[i] == least_frequent] 29 | if len(co2li) == 1: c = int(''.join(co2li[0]), 2) 30 | 31 | print(o * c) 32 | -------------------------------------------------------------------------------- /2021/04/1.py: -------------------------------------------------------------------------------- 1 | def clean_line(line, char): 2 | return [int(n) for n in line.split(char) if n] 3 | 4 | with open('input.txt', 'r') as _file: 5 | inputs = [n.strip() for n in _file] 6 | 7 | draws = clean_line(inputs[0], ',') 8 | boards = [] 9 | board = [] 10 | 11 | for line in inputs[2:]: 12 | if line.strip() == '': 13 | boards.append(board) 14 | board = [] 15 | else: 16 | board.append(clean_line(line.strip(), ' ')) 17 | 18 | 19 | def find_bingo(boards, draws): 20 | for d in draws: 21 | for board in range(len(boards)): 22 | for row in range(len(boards[board])): 23 | for val in range(len(boards[board][row])): 24 | if boards[board][row][val] == d: 25 | boards[board][row][val] = -1 26 | if sum(boards[board][row]) == -5: 27 | return boards[board], d 28 | total = 0 29 | for r in boards[board]: 30 | total += r[val] 31 | if total == -5: return boards[board], d 32 | 33 | 34 | board, d = find_bingo(boards, draws) 35 | _sum = 0 36 | for row in board: 37 | for val in row: 38 | if val != -1: 39 | _sum += val 40 | 41 | print(_sum * d) 42 | print('-----') 43 | print(board) 44 | 45 | 46 | -------------------------------------------------------------------------------- /2021/04/2.py: -------------------------------------------------------------------------------- 1 | def clean_line(line, char): 2 | return [int(n) for n in line.split(char) if n] 3 | 4 | with open('input.txt', 'r') as _file: 5 | inputs = [n.strip() for n in _file] 6 | 7 | draws = clean_line(inputs[0], ',') 8 | boards = [] 9 | board = [] 10 | 11 | for line in inputs[2:]: 12 | if line.strip() == '': 13 | boards.append(board) 14 | board = [] 15 | else: 16 | board.append(clean_line(line.strip(), ' ')) 17 | 18 | 19 | def find_bingo(boards, draws): 20 | for d in draws: 21 | for board in range(len(boards)): 22 | for row in range(len(boards[board])): 23 | for val in range(len(boards[board][row])): 24 | if boards[board][row][val] == d: 25 | boards[board][row][val] = -1 26 | if sum(boards[board][row]) == -5: 27 | return d, board 28 | total = 0 29 | for r in boards[board]: 30 | total += r[val] 31 | if total == -5: return d, board 32 | 33 | while len(boards): 34 | d, board = find_bingo(boards, draws) 35 | final_board = boards.pop(board) 36 | 37 | _sum = 0 38 | for row in final_board: 39 | for val in row: 40 | if val != -1: 41 | _sum += val 42 | 43 | print(_sum * d) 44 | 45 | -------------------------------------------------------------------------------- /2021/06/1.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | n_days = 256 5 | 6 | with open('input.txt', 'r') as _file: 7 | for line in _file: 8 | fish = [int(n) for n in line.split(',')] 9 | 10 | fish = dict(Counter(fish)) 11 | 12 | new_count = {} 13 | while n_days > 0: 14 | for days, count in fish.items(): 15 | if days != 0: 16 | if (days - 1) in new_count: 17 | new_count[days-1] += count 18 | else: 19 | new_count[days-1] = count 20 | else: 21 | if 6 in new_count: 22 | new_count[6] += count 23 | else: 24 | new_count[6] = count 25 | new_count[8] = count 26 | fish = new_count 27 | new_count = {} 28 | n_days -= 1 29 | 30 | print(sum(fish.values())) -------------------------------------------------------------------------------- /2022/01/script.py: -------------------------------------------------------------------------------- 1 | running_sum = 0 2 | sums = [] 3 | with open('input.txt', 'r') as _file: 4 | for line in _file: 5 | if line == "\n": 6 | sums.append(running_sum) 7 | running_sum = 0 8 | else: 9 | running_sum += int(line) 10 | sums.append(running_sum) 11 | 12 | # part 1 13 | print(max(sums)) 14 | 15 | # part 2 16 | print(sum(sorted(sums, reverse=True)[0:3])) 17 | 18 | -------------------------------------------------------------------------------- /2022/02/script.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | losses = {2: 3, 3: 1, 1: 2} 4 | wins = {3: 2, 1: 3, 2: 1} 5 | 6 | score = 0 7 | with open('input.txt', 'r') as _file: 8 | for line in _file: 9 | [elf, me] = line.strip().split(' ') 10 | elf, me = string.ascii_uppercase.index(elf) + 1, string.ascii_uppercase.index(me) - 22 11 | score += me 12 | if elf == me: score += 3 13 | if wins[me] == elf: score += 6 14 | # Part 1 15 | print(score) 16 | 17 | score = 0 18 | with open('input.txt', 'r') as _file: 19 | for line in _file: 20 | [elf, me] = line.strip().split(' ') 21 | elf = string.ascii_uppercase.index(elf) + 1 22 | if me == 'Y': score += elf + 3 23 | elif me == 'X': score += wins[elf] 24 | elif me == 'Z': score += 6 + losses[elf] 25 | # Part 2 26 | print(score) -------------------------------------------------------------------------------- /2022/03/script.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | priorities = 0 4 | with open('input.txt', 'r') as _file: 5 | for line in _file: 6 | halfway = len(line)//2 7 | c1, c2 = line[0:halfway], line[halfway:] 8 | (letter,) = set(c1).intersection(c2) 9 | priorities += string.ascii_letters.find(letter) + 1 10 | print(priorities) 11 | 12 | priorities = 0 13 | with open('input.txt', 'r') as _file: 14 | badges = [badge.strip() for badge in _file] 15 | groups = [badges[x:x+3] for x in range(0, len(badges), 3)] 16 | for group in groups: 17 | (priority,) = set(group[0].strip()).intersection(group[1]).intersection(group[2]) 18 | priorities += string.ascii_letters.find(priority) + 1 19 | print(priorities) -------------------------------------------------------------------------------- /2022/04/script.py: -------------------------------------------------------------------------------- 1 | count = 0 2 | p2_count = 0 3 | with open('input.txt', 'r') as _file: 4 | ranges = [line.strip().split(',') for line in _file] 5 | for pair in ranges: 6 | r_pair = [] 7 | for _range in pair: 8 | (start, end) = _range.split('-') 9 | start, end = int(start), int(end) 10 | r_pair.append((start, end)) 11 | if (r_pair[0][0] >= r_pair[1][0] and r_pair[0][1] <= r_pair[1][1]) or (r_pair[1][0] >= r_pair[0][0] and r_pair[1][1] <= r_pair[0][1]): 12 | count += 1 13 | if r_pair[0][0] <= r_pair[1][0] <= r_pair[0][1] or r_pair[1][0] <= r_pair[0][0] <= r_pair[1][1]: 14 | p2_count += 1 15 | print(count) 16 | print(p2_count) 17 | 18 | -------------------------------------------------------------------------------- /2022/05/script.py: -------------------------------------------------------------------------------- 1 | crates = { 2 | 1: ['P', 'V', 'Z', 'W', 'D', 'T'], 3 | 2: ['D', 'J', 'F', 'V', 'W', 'S', 'L'], 4 | 3: ['H', 'B', 'T', 'V', 'S', 'L', 'M', 'Z'], 5 | 4: ['J', 'S', 'R'], 6 | 5: ['W', 'L', 'M', 'F', 'G', 'B', 'Z', 'C'], 7 | 6: ['B', 'G', 'R', 'Z', 'H', 'V', 'W', 'Q'], 8 | 7: ['N', 'D', 'B', 'C', 'P', 'J', 'V'], 9 | 8: ['Q', 'B', 'T', 'P'], 10 | 9: ['C', 'R', 'Z', 'G', 'H'] 11 | } 12 | 13 | # crates = { 14 | # 1: ['N', 'Z'], 15 | # 2: ['D', 'C', 'M'], 16 | # 3: ['P'] 17 | # } 18 | 19 | # with open('input.txt', 'r') as _file: 20 | # for move in _file: 21 | # moves = move.strip().split(' ') 22 | # to_move, start, end = [int(moves[1]), int(moves[3]), int(moves[5])] 23 | # crates[end] = crates[start][0:to_move][::-1] + crates[end] 24 | # del crates[start][0:to_move] 25 | # message = '' 26 | # for _, crate in crates.items(): 27 | # message += crate[0] 28 | # print(message) 29 | 30 | with open('input.txt', 'r') as _file: 31 | for move in _file: 32 | moves = move.strip().split(' ') 33 | to_move, start, end = [int(moves[1]), int(moves[3]), int(moves[5])] 34 | crates[end] = crates[start][0:to_move] + crates[end] 35 | del crates[start][0:to_move] 36 | message = '' 37 | for _, crate in crates.items(): 38 | message += crate[0] 39 | print(message) -------------------------------------------------------------------------------- /2022/06/script.py: -------------------------------------------------------------------------------- 1 | _file = open("input.txt", "r") 2 | word = _file.readline() 3 | 4 | MARKER_LENGTH = 14 5 | 6 | for char in range(MARKER_LENGTH, len(word)): 7 | substr = word[char - MARKER_LENGTH:char] 8 | if len(set(substr)) == MARKER_LENGTH: 9 | print(char) 10 | break 11 | 12 | -------------------------------------------------------------------------------- /2022/07/script.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | with open('input.txt', 'r') as _file: 4 | working_directory = [''] 5 | files = defaultdict(lambda: 0) 6 | for command in _file: 7 | command = command.strip().split() 8 | if command[0] == "$": 9 | if command[1] == "cd": 10 | if command[2] == "..": 11 | working_directory.pop() 12 | elif command[2] == "/": 13 | working_directory = [''] 14 | else: 15 | working_directory.append(command[2]) 16 | elif command[0] != "dir": 17 | wd_str = '' 18 | for dir in working_directory: 19 | wd_str += dir 20 | files[wd_str] += int(command[0]) 21 | 22 | total_size = 0 23 | unused_space = 70000000 - files[''] 24 | space_to_free = 30000000 - unused_space 25 | 26 | to_del = files[''] 27 | for dir, size in files.items(): 28 | if size <= 100000: 29 | total_size += size 30 | if size >= space_to_free and size < to_del: 31 | to_del = size 32 | 33 | print(total_size) 34 | print(to_del) 35 | -------------------------------------------------------------------------------- /2022/08/script.py: -------------------------------------------------------------------------------- 1 | def check_right(height, row, to_check): 2 | while to_check < len(row): 3 | if height <= row[to_check]: 4 | return False 5 | to_check += 1 6 | return True 7 | 8 | 9 | def check_left(height, row, to_check): 10 | while to_check >= 0: 11 | if height <= row[to_check]: 12 | return False 13 | to_check -= 1 14 | return True 15 | 16 | 17 | def check_down(grid, height, to_check, col_idx): 18 | while to_check < len(grid): 19 | if height <= grid[to_check][col_idx]: return False 20 | to_check += 1 21 | return True 22 | 23 | 24 | def check_up(grid, height, to_check, col_idx): 25 | while to_check >= 0: 26 | if height <= grid[to_check][col_idx]: return False 27 | to_check -= 1 28 | return True 29 | 30 | 31 | def is_visible(grid, row_idx, col_idx): 32 | height = grid[row_idx][col_idx] 33 | row = grid[row_idx] 34 | return (check_right(height, row, col_idx + 1) 35 | or check_left(height, row, col_idx - 1) or 36 | check_down(grid, height, row_idx + 1, col_idx) or 37 | check_up(grid, height, row_idx - 1, col_idx)) 38 | 39 | with open('input.txt', 'r') as _file: 40 | grid = [] 41 | for line in _file: 42 | grid.append([int(n) for n in line.strip()]) 43 | count = 0 44 | for idx, _ in enumerate(grid): 45 | for cidx, _ in enumerate(grid): 46 | if is_visible(grid, idx, cidx): 47 | count += 1 48 | print(count) 49 | -------------------------------------------------------------------------------- /2022/08/script2.py: -------------------------------------------------------------------------------- 1 | def check_right(row, height, to_check): 2 | visible_trees = 0 3 | while to_check < len(row): 4 | visible_trees += 1 5 | if row[to_check] >= height: 6 | return visible_trees 7 | to_check += 1 8 | return visible_trees 9 | 10 | 11 | def check_left(row, height, to_check): 12 | visible_trees = 0 13 | while to_check >= 0: 14 | visible_trees += 1 15 | if row[to_check] >= height: 16 | return visible_trees 17 | to_check -= 1 18 | return visible_trees 19 | 20 | 21 | def check_down(grid, height, to_check, col_idx): 22 | visible_trees = 0 23 | while to_check < len(grid): 24 | visible_trees += 1 25 | if grid[to_check][col_idx] >= height: 26 | return visible_trees 27 | to_check += 1 28 | return visible_trees 29 | 30 | 31 | def check_up(grid, height, to_check, col_idx): 32 | visible_trees = 0 33 | while to_check >= 0: 34 | visible_trees += 1 35 | if grid[to_check][col_idx] >= height: 36 | return visible_trees 37 | to_check -= 1 38 | return visible_trees 39 | 40 | 41 | def is_visible(grid, row_idx, col_idx): 42 | height = grid[row_idx][col_idx] 43 | row = grid[row_idx] 44 | return (check_right(row, height, col_idx + 1) 45 | * check_left(row, height, col_idx - 1) * 46 | check_down(grid, height, row_idx + 1, col_idx) * 47 | check_up(grid, height, row_idx - 1, col_idx)) 48 | 49 | 50 | with open('input.txt', 'r') as _file: 51 | grid = [] 52 | for line in _file: 53 | grid.append([int(n) for n in line.strip()]) 54 | max_surround = 0 55 | max_coords = None 56 | for idx, _ in enumerate(grid): 57 | for cidx, _ in enumerate(grid): 58 | surrounds = is_visible(grid, idx, cidx) 59 | if surrounds > max_surround: 60 | max_coords = (idx, cidx) 61 | max_surround = surrounds 62 | print(max_surround) 63 | print(max_coords) 64 | --------------------------------------------------------------------------------