from pathlib import Path from typing import TypedDict class Grab(TypedDict): red: int blue: int green: int def grab_in_bag(bag: Grab, grab: Grab) -> bool: for color, count in grab.items(): if count > bag[color]: return False return True class Game: def __init__(self, id: int, grabs: list[Grab] | None = None) -> None: self.id = id self.grabs = grabs if grabs else [] def possible(self, bag: Grab) -> bool: return all(grab_in_bag(bag, grab) for grab in self.grabs) def parse_line(line: str) -> Game: line = line.strip() game_parsed, _, grabs = line.partition(":") id = int("".join(c for c in game_parsed if c.isnumeric())) game = Game(id) for grab_draw in grabs.split(";"): grab = Grab(red=0, blue=0, green=0) for color_draw in grab_draw.split(","): color_draw = color_draw.strip() count, _, color = color_draw.partition(" ") grab[color] = int(count) game.grabs.append(grab) return game def part1(input: Path) -> int: bag = Grab(red=12, blue=14, green=13) total = 0 with input.open() as f: for line in f: game = parse_line(line) if game.possible(bag): total += game.id return total def part2(input: Path) -> int: total = 0 with input.open() as f: for line in f: bag = Grab(red=0, blue=0, green=0) game = parse_line(line) power = 1 for color in bag: bag[color] = max(grab[color] for grab in game.grabs) power *= bag[color] # print(bag, power) total += power return total if __name__ == "__main__": answer1 = part1(Path("./input.txt")) print("part 1", answer1) answer2 = part2(Path("./input.txt")) print("part 2", answer2)