Advent of Code 2021
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
aoc21/day2/password_philosophy.py

80 lines
2.2 KiB

from utils import read_input_data
from collections import Counter
from typing import List, Dict, Tuple
class TestClass:
test_data = """1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc
"""
def test_count_valid_passwords(self):
parsed = parse_input_data(self.test_data)
assert count_valid_passwords(parsed) == 2
def test_parse_input_data(self):
parsed = parse_input_data(self.test_data)
assert parsed == [
(
{
'lower_bound': 1,
'upper_bound': 3,
'char': 'a',
},
'abcde'
),
(
{
'lower_bound': 1,
'upper_bound': 3,
'char': 'b',
},
'cdefg'
),
(
{
'lower_bound': 2,
'upper_bound': 9,
'char': 'c',
},
'ccccccccc'
),
]
def parse_input_data(data: str) -> List[Tuple[Dict, str]]:
lines = [line for line in data.split('\n') if line]
parsed_passwords = []
for line in lines:
policy, password = line.split(':')
password = password.strip()
policy_dict = parse_policy(policy)
parsed_passwords.append((policy_dict, password))
return parsed_passwords
def parse_policy(input_string: str) -> Dict[str, int]:
range, char = input_string.split()
lower_bound, upper_bound = range.split('-')
return {
'upper_bound': int(upper_bound),
'lower_bound': int(lower_bound),
'char': char,
}
def verify_password(policy, password) -> bool:
counter = Counter(password)
return policy['lower_bound'] <= counter[policy['char']] <= policy['upper_bound']
def count_valid_passwords(parsed_passwords: List[Tuple[Dict, str]]):
return sum([verify_password(pol, pwd) for pol, pwd in parsed_passwords])
if __name__ == '__main__':
raw_data = read_input_data('input.txt')
parsed_data = parse_input_data(raw_data)
result = count_valid_passwords(parsed_data)
print(f'There are {result} valid Passwords, according to their policies')