We are asked to find the single common element between two compartments in a rucksack. This is what sets are really great for, the intersection of the two sets of letters.
import string
priorities = {letter: i for i, letter in enumerate(string.ascii_letters, 1)}
def misplaced_item(rucksack: str) -> str:
half = len(rucksack) // 2
[letter] = set(rucksack[:half]) & set(rucksack[half:])
return letter
example = """\
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
""".splitlines()
assert sum(priorities[misplaced_item(r)] for r in example) == 157
import aocd
rucksacks = aocd.get_data(day=3, year=2022).splitlines()
print("Part 1:", sum(priorities[misplaced_item(r)] for r in rucksacks))
Part 1: 7763
The problem hasn't really changed, we now have to intersect 3 rucksacks to find the single item. Since the set().intersection()
method can take multiple inputs, this is trivial to achieve.
from typing import Iterator
def badge(rucksack: str, *rucksacks: str) -> str:
[letter] = set(rucksack).intersection(*rucksacks)
return letter
def badges(*rucksacks: str) -> Iterator[str]:
it = iter(rucksacks)
for group in zip(it, it, it):
yield badge(*group)
assert sum(priorities[badge] for badge in badges(*example)) == 70
print("Part 2:", sum(priorities[badge] for badge in badges(*rucksacks)))
Part 2: 2569