-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday02.py
More file actions
114 lines (84 loc) · 2.51 KB
/
day02.py
File metadata and controls
114 lines (84 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import re
from dataclasses import dataclass
from pathlib import Path
from loguru import logger
from typer import Typer
from utils import timer
main = Typer()
@dataclass
class MaxDraw:
"""Represent the maximum number of cubes drawn per game"""
red: int
green: int
blue: int
id: int = -1
def __le__(self, other: "MaxDraw") -> bool:
"""self <= other iff it has less cubes then other for all colors"""
return all(
getattr(self, color) <= getattr(other, color)
for color in ["red", "green", "blue"]
)
@classmethod
def from_line(cls, line: str) -> "MaxDraw":
"""Parse a single line."""
game, rest = line.split(":")
id = int(game.split(" ")[-1])
splits = re.split(r"\W+", rest.strip())
counts: dict[str, int] = {}
for number, color in zip(splits[::2], splits[1::2]):
counts[color] = max(counts.get(color, 0), int(number))
return cls(id=id, **counts)
@property
def power(self) -> int:
"""Compute the power by multiplying all the cube counts"""
return self.red * self.green * self.blue
@timer
def sum_valid_games(input: str, ref: MaxDraw | None = None) -> int:
"""Compute the sum of the game ids of valid games
A game is valid if it has less cubes than the reference game.
If ref is None, the reference from the advent of code task is
inserted.
Args:
input: Input string
ref: Reference Draw representing the number of available cubes. Defaults to None.
Returns:
Sum of valid game ids
"""
if ref is None:
ref = MaxDraw(red=12, green=13, blue=14)
res = 0
for line in input.splitlines():
line = line.strip()
if len(line) == 0:
continue
draw = MaxDraw.from_line(line)
if draw <= ref:
res += draw.id
return res
@timer
def total_power(input: str) -> int:
"""Compute the power of all games
Args:
input: String input
Returns:
Sum of power
"""
return sum(
MaxDraw.from_line(line.strip()).power
for line in input.split("\n")
if len(line.strip()) != 0
)
@main.command()
def entrypoint(path: Path):
"""Entrypoint
Args:
path: Path to input file
"""
with open(path, "r") as f:
input = f.read()
logger.info("Task 01")
logger.info(sum_valid_games(input))
logger.info("Task02")
logger.info(total_power(input))
if __name__ == "__main__":
main()