This year I'll do my best to master the “Advent of Code”-Challenge. I'll update my Github every day, with my solution.
StarGo to...
-- Day 1: Report Repair --
Click here, to go to the challenge.
target = 2020
def parseNumList(filename):
with open(filename, 'r') as file:
return [int(line) for line in file]
def part_one(input, target):
for n in input:
if (target - n) in input: # If 2020 minus $number is in the input, we found the missing part
return n*(target-n)
def part_two(input, target):
for n in input:
b = part_one(input, target - n)
if b:
return n*b
input_data = parseNumList('input.txt')
print("Part 1: ", part_one(input_data, target))
print("Part 2: ", part_two(input_data, target))
-- Day 2: Password Philosophy --
Click here, to go to the challenge.
def line_to_in(in_line):
out = {}
in_line = in_line.split(" ")
out["min"] = int(in_line[0].split("-")[0])
out["max"] = int(in_line[0].split("-")[1])
out["char"] = in_line[1].replace(':', '')
out["pass"] = in_line[2]
return out
def parse_pw_data(filename):
with open(filename, 'r') as file:
return [line_to_in(line) for line in file]
def part_one(in_d):
c = 0
for char in in_d["pass"]:
if char == in_d["char"]:
c += 1
if c > in_d["max"]:
return False
return True if c >= in_d["min"] else False
def part_two(in_d):
o = 1 # Toboggan Corporate Policies have no concept of "index zero"!
return True if (in_d["pass"][in_d["min"]-o] == in_d["char"]) is not (in_d["pass"][in_d["max"]-o] == in_d["char"]) else False
input_data = parse_pw_data('input.txt')
p1_c = 0
p2_c = 0
for in_d in input_data:
p1_c += 1 if part_one(in_d) else 0
p2_c += 1 if part_two(in_d) else 0
print("Part1: ", p1_c, " - Part2: ", p2_c)
-- Day 3: Toboggan Trajectory --
Click here, to go to the challenge.
from functools import reduce
filepath = 'input.txt'
slopes = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
def expand_map(in_map):
return [x + x for x in in_map]
def get_count_for_slope(slope, w_map):
c = 0
pos = (0, 0)
while pos[1] < len(w_map)-1:
pos = tuple(map(sum, zip(pos, slope)))
if len(w_map[0]) <= pos[0]:
w_map = expand_map(w_map)
if w_map[pos[1]][pos[0]] is "#":
c += 1
return c
def part_one(slope, w_map):
return get_count_for_slope(slope, w_map)
def part_two(slopes, w_map):
return reduce(lambda x, y: x*y, [get_count_for_slope(s, w_map) for s in slopes])
with open(filepath, 'r') as file:
work_map = [list(line.replace("\n", "")) for line in file]
print('Part1: ', part_one((3, 1), work_map), ' - Part2: ', part_two(slopes, work_map))
-- Day 4: Passport Processing --
Click here, to go to the challenge.
import re
def is_digit_in_range(in_str, span):
return True if in_str.isdigit() and span[0] <= int(in_str) <= span[1] else False
def is_digit_with_len(in_str, t_len):
return True if len(in_str) is t_len and in_str.isdigit() else False
def check_pass_for_hgt(passport):
if re.compile(r'^\d{3}cm$').match(passport['hgt']):
return True if 150 <= int(passport['hgt'].replace("cm", "")) <= 193 else False
elif re.compile(r'^\d{2,3}in$').match(passport['hgt']):
return True if 59 <= int(passport['hgt'].replace("in", "")) <= 76 else False
return False
def check_pass_for_hcl(passport):
return True if re.compile(r'^#\w{6}$').match(passport['hcl']) else False
def check_pass_for_ecl(passport):
check_list = ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
return True if passport['ecl'] in check_list else False
def check_pass(passport, to_check):
return True if all(elem in passport.keys() for elem in to_check) \
and is_digit_in_range(passport['byr'], (1920, 2002)) \
and is_digit_in_range(passport['iyr'], (2010, 2020)) \
and is_digit_in_range(passport['eyr'], (2020, 2030)) \
and is_digit_with_len(passport['pid'], 9) \
and check_pass_for_ecl(passport) \
and check_pass_for_hcl(passport) \
and check_pass_for_hgt(passport) else False
to_check = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"] # cid is optional
with open('input.txt') as file:
passports = [{item.split(":")[0]:item.split(":")[1] for item in x.replace(
"\n", " ").split(" ") if len(item.split(":")) > 1} for x in file.read().split("\n\n")]
prat_one = len(list(filter(lambda d: all(elem in d.keys() for elem in to_check), passports)))
prat_two = len(list(filter(lambda d: check_pass(d, to_check), passports)))
print("Part1: ", prat_one, " - Part2: ", prat_two)
-- Day 5: Binary Boarding --
Click here, to go to the challenge.
import decimal
decimal.getcontext().rounding = decimal.ROUND_HALF_UP
input_file = 'input.txt'
plane_col_max = 7
plane_row_max = 127
def to_int(in_num):
return int(decimal.Decimal(in_num).to_integral_value())
def calc_pos(in_str, max_idx, up_c, down_c):
span = (0, max_idx)
for c in in_str:
if c == up_c:
span = (span[0]+to_int((span[1]-span[0])/2), span[1])
elif c == down_c:
span = (span[0], span[1]-to_int((span[1]-span[0])/2))
return min(span)
def calc_id(row, col):
return row*8+col
def part_one(file_path):
with open(file_path) as file:
return sorted([calc_id(calc_pos(f[:7], plane_row_max, 'B', 'F'), calc_pos(f[7:], plane_col_max, 'R', 'L')) for f in file])
def part_two(p1_out):
return set(range(p1_out[0], p1_out[-1])) - set(p1_out)
p1_out = part_one(input_file)
p2_out = part_two(p1_out)
print('Part1: ', max(p1_out), ' - Part2: ', max(p2_out))
-- Day 6: Custom Customs --
Click here, to go to the challenge.
from functools import reduce
def part_one(set_list):
return len(reduce(set.union, set_list))
def part_two(set_list):
return len(reduce(set.intersection, set_list))
with open('input.txt') as file:
p1_c = 0
p2_c = 0
parsed_input = [[set(x) for x in line.split('\n')] for line in file.read().split("\n\n")]
for decl in parsed_input:
p1_c += part_one(decl)
p2_c += part_two(decl)
print('Part1: ', p1_c, ' - Part2: ', p2_c)
-- Day 7: Handy Haversacks --
Click here, to go to the challenge.
import re
def parse_input_line(in_str):
def parse_contain(contain_str):
regex = r"(\d)\s(\w*\s\w*)\D*"
return {x[1]: int(x[0]) for x in re.findall(regex, contain_str)}
regex = r"^(.*) bags contain (.*)."
regex_res = re.search(regex, in_str)
return regex_res.group(1), parse_contain(regex_res.group(2))
def part_one(in_dict, search_str):
out_set = set()
for bag, colors in rule_dict.items():
if search_str in colors:
out_set.add(bag)
out_set.update(part_one(in_dict, bag))
return out_set
def part_two(in_dict, search_str):
sum = 0
for k, v in in_dict[search_str].items():
sum += v + part_two(in_dict, k)*v
return sum
with open('input.txt') as file:
rule_dict = {k: v for k, v in (parse_input_line(line) for line in file)}
print('Part1: ', len(part_one(rule_dict, 'shiny gold')), ' - Part2: ', part_two(rule_dict, 'shiny gold'))
-- Day 8: Handheld Halting --
Click here, to go to the challenge.
def accumulator(in_data):
done = []
acc = 0
cursor = 0
while cursor not in done:
if cursor >= len(in_data):
return {'acc': acc, 'terminated': True, 'positions': done}
cur_task = in_data[cursor]
done.append(cursor)
if cur_task[0] == 'jmp':
cursor += cur_task[1]
else:
if cur_task[0] == 'acc':
acc += cur_task[1]
cursor += 1
return {'acc': acc, 'terminated': False, 'positions': done}
def part_one(in_data):
return accumulator(in_data)
def part_two(in_data):
swap = {"nop": "jmp", "jmp": "nop"}
def modify_in_data(swap,in_data, idx):
n_in_data = in_data.copy()
n_in_data[idx] = (swap[n_in_data[idx][0]],n_in_data[idx][1])
return n_in_data
# Do a run to find potential swap-candidates:
acc_jmp = [i for i in accumulator(in_data)['positions'] if in_data[i][0] in swap.keys()]
for i in acc_jmp:
out = accumulator(modify_in_data(swap, in_data, i))
if out['terminated'] is True:
return out
with open('input.txt') as file:
in_data = [(op,int(arg)) for op, arg in (line.split() for line in file)]
print('Part1: ', part_one(in_data)['acc'], ' - Part2: ', part_two(in_data)['acc'])
-- Day 9: Encoding Error --
Click here, to go to the challenge.
def check_in_range(watch_list, val):
for i in watch_list:
if val-i in watch_list:
return True
def find_wrong_number(in_data, back_look=25):
for cursor in range(back_look, len(in_data)):
if not check_in_range(in_data[cursor-back_look:cursor], in_data[cursor]):
return in_data[cursor]
def find_encryption_weakness(in_data, invalid_val):
for l in range(2, len(in_data)):
for i in range(len(in_data)-l):
if sum(in_data[i:i+l]) == invalid_val:
return min(in_data[i:i+l]) + max(in_data[i:i+l])
with open('input.txt') as file:
in_data = [int(i) for i in file]
p1 = find_wrong_number(in_data)
p2 = find_encryption_weakness(in_data, p1)
print('Part1: ', p1, ' - Part2: ', p2)
-- Day 10: Encoding Error --
Click here, to go to the challenge.
from collections import Counter
def part_one(adapters):
adapters = [0]+adapters+[adapters[-1]+3]
differeces = [adapters[i+1]-x for i,
x in enumerate(adapters) if i+1 < len(adapters)]
return differeces.count(1)*differeces.count(3)
def part_two(jolts):
jolts.append(jolts[-1] + 3)
dp = Counter()
dp[0] = 1
for jolt in jolts:
dp[jolt] = dp[jolt - 1] + dp[jolt - 2] + dp[jolt - 3]
return dp[jolts[-1]]
with open('input.txt') as file:
adapters = [int(i) for i in file]
adapters.sort()
print('Part1: ', part_one(adapters), ' - Part2: ', part_two(adapters))