<jupyter_start><jupyter_text>Day 2: Password Philosophyhttps://adventofcode.com/2020/day/2 Part 1<jupyter_code>from pathlib import Path
import re

INPUTS = Path('input.txt').resolve().read_text().strip().split('\n')

# Pattern match lines of the input
pattern = re.compile(r"(?P<min>\d+)-(?P<max>\d+)\s(?P<target>[a-z]):\s(?P<password>[a-z]+)")
# Pull those matches out
matches = [
    {
        # Convert the min and max keys to int here, just to make things easier.
        k: int(v) if k in ('min', 'max') else v
        for k, v
        in pattern.match(x).groupdict().items()
    }
    for x in INPUTS
]

# Start a counter
count_valid = 0

for match in matches:
    # Find number of occurrences of the target character in the password
    target_occurrences = len([c for c in match['password'] if c == match['target']])
    # Test if that target occurrence falls within the accepted range
    if match['min'] <= target_occurrences <= match['max']:
        count_valid += 1

print(f"{count_valid} valid passwords found.")<jupyter_output>546 valid passwords found.<jupyter_text>Part 2<jupyter_code># We can use all the same contents, but now they mean different things

new_count_valid = 0
for match in matches:
    # Positions in the input are 1-indexed.
    # Convert these down to 0-index for brevity
    pos1 = match['min'] - 1
    pos2 = match['max'] - 1
    target = match['target']
    password = match['password']
    if (password[pos1] == target and password[pos2] != target) or (password[pos1] != target and password[pos2] == target):
        new_count_valid += 1

print(f"{new_count_valid} valid passwords found.")<jupyter_output>275 valid passwords found.