from __future__ import annotations from dataclasses import dataclass from .aoc import Aoc2, AocParseLinesSameParser @dataclass(frozen=True) class GameSet: red: int green: int blue: int @staticmethod def from_line(line: str) -> GameSet: cubes = line.split(", ") gather_dict = {} for cube_str in cubes: amount, color = cube_str.split(" ") gather_dict[color] = int(amount) return GameSet( gather_dict.get("red", 0), gather_dict.get("green", 0), gather_dict.get("blue", 0), ) @dataclass(frozen=True) class Game: game_id: int sets: list[GameSet] def power(self) -> int: return self.maxblue * self.maxred * self.maxgreen @property def maxblue(self) -> int: return max(s.blue for s in self.sets) @property def maxred(self) -> int: return max(s.red for s in self.sets) @property def maxgreen(self) -> int: return max(s.green for s in self.sets) @property def valid(self) -> bool: return self.maxred <= 12 and self.maxgreen <= 13 and self.maxblue <= 14 @staticmethod def from_line(line: str) -> Game: game_str, sets_str = line.split(": ") _, gameid = game_str.split(" ") set_str_list = sets_str.split("; ") return Game(int(gameid), [GameSet.from_line(s) for s in set_str_list]) class Day02(AocParseLinesSameParser[Game], Aoc2[list[Game], list[Game]]): def __init__(self) -> None: Aoc2.__init__(self, 2023, 2) def parseline(self, inpt: str) -> Game: return Game.from_line(inpt) def part1(self, games: list[Game]) -> int: return sum(game.game_id for game in games if game.valid) def part2(self, games: list[Game]) -> int: return sum(g.power() for g in games) def main() -> None: day2_aoc = Day02() day2_aoc.run() if __name__ == "__main__": main()