# -*- coding: utf-8 -*- from abc import ABC from enum import Enum from functools import reduce from typing import Iterator from aoc import BaseAssignment, I, T class Color(Enum): red = 'red' green = 'green' blue = 'blue' ColorCount = tuple[int, Color] class Assignment(BaseAssignment, ABC): def parse_item(self, item: str) -> list[tuple[ColorCount, ...]]: _, items = item.split(': ') return [ tuple( ColorCount(( int(_.split(' ')[0]), Color(_.split(' ')[1]) )) for _ in pair.split(', ') ) for pair in items.split('; ') ] class AssignmentOne(Assignment): example_result = 8 inventory = { Color.red: 12, Color.green: 13, Color.blue: 14, } def is_possible(self, game: list[tuple[ColorCount, ...]]): for item in game: for count, color in item: if count > self.inventory[color]: return False return True def run(self, input: Iterator[list[tuple[ColorCount, ...]]]) -> int: possible_games = [] for index, game in enumerate(input): if self.is_possible(game): possible_games.append(index + 1) return sum(possible_games) class AssignmentTwo(Assignment): example_result = 2286 def get_least_numbers(self, game: list[tuple[ColorCount, ...]]): counts = {} for item in game: for count, color in item: if color not in counts or count > counts[color]: counts[color] = count return counts def run(self, input: Iterator[list[tuple[ColorCount, ...]]]) -> int: powers = [] for game in input: counts = self.get_least_numbers(game) powers.append( reduce( lambda total, item: total * item, counts.values(), 1 ) ) return sum(powers)