96 lines
3.1 KiB
Python
Raw Normal View History

2020-12-16 15:39:11 +01:00
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 Akumatic
#
#https://adventofcode.com/2020/day/16
def parseInput(blocks: list) -> dict:
data = {"rules": dict(), "you": list(), "tickets": list()}
# 1st block, rules
for rule in blocks[0]:
rule = rule.split(": ")
data["rules"][rule[0]] = []
vals = [int(n) for r in rule[1].split(" or ") for n in r.split("-")]
for i in range(0, len(vals), 2):
data["rules"][rule[0]].append(range(vals[i], vals[i+1] + 1))
# 2nd block, your ticket
data["you"] += [int(num) for num in blocks[1][1].split(",")]
# 3rd block, nearby tickets
for ticket in blocks[2][1:]:
data["tickets"].append([int(num) for num in ticket.split(",")])
return data
def readFile() -> dict:
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
blocks = [block.split("\n") for block in f.read().strip().split("\n\n")]
return parseInput(blocks)
def check_rule(rule: list, number: int) -> bool:
return any([number in r for r in rule])
def check_rules(rules: dict, number: int) -> bool:
for rule in rules:
if check_rule(rules[rule], number):
return True
return False
def validate_ticket(rules: dict, ticket: list) -> bool:
for number in ticket:
if not check_rules(rules, number):
return False
return True
def get_valid_tickets(data: dict) -> list:
valid_tickets = [data["you"]]
for ticket in data["tickets"]:
if validate_ticket(data["rules"], ticket):
valid_tickets.append(ticket)
return valid_tickets
def get_possible_positions(rules: dict, valid_tickets: list) -> dict:
possible_positions = dict()
size = len(rules)
for rule in rules:
pos = []
for i in range(size):
if all([check_rule(rules[rule], t[i]) for t in valid_tickets]):
pos.append(i)
possible_positions[rule] = pos
return possible_positions
def determine_positions(possible_positions: dict) -> dict:
positions = dict()
keys = list(possible_positions.keys())
while keys:
for key in keys:
if len(possible_positions[key]) == 1:
positions[key] = possible_positions[key][0]
keys.remove(key)
for pos in keys:
if positions[key] in possible_positions[pos]:
possible_positions[pos].remove(positions[key])
continue
return positions
def part1(data: dict) -> int:
error_rate = 0
for ticket in data["tickets"]:
for number in ticket:
if not check_rules(data["rules"], number):
error_rate += number
return error_rate
def part2(data: dict) -> int:
valid_tickets = get_valid_tickets(data)
possible_positions = get_possible_positions(data["rules"], valid_tickets)
positions = determine_positions(possible_positions)
result = 1
for rule in positions:
if rule.startswith("departure"):
result *= data["you"][positions[rule]]
return result
if __name__ == "__main__":
input = readFile()
print(f"Part 1: {part1(input)}")
print(f"Part 2: {part2(input)}")