diff --git a/advent/days/day02/__init__.py b/advent/days/day02/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/advent/days/day02/data/input.txt b/advent/days/day02/data/input.txt new file mode 100644 index 0000000..cb4efdf --- /dev/null +++ b/advent/days/day02/data/input.txt @@ -0,0 +1,2500 @@ +B Z +A X +B Z +B Z +C Z +B Z +A Z +B X +C Y +C Y +A X +A X +A Z +B Z +A X +A Z +B X +C Y +A Y +A Y +C Y +B Y +C X +C Y +B Z +A X +A Y +B Y +A X +A Z +B X +B Y +B Z +B Z +B Z +C Y +B X +A X +C Y +B Z +B Z +C X +A Z +B Z +B Z +C X +C X +B X +B X +A X +B X +C Z +C Y +C Y +C Y +C X +B Z +B Y +C X +A X +C X +C Y +C Y +C Y +B X +B Y +A Z +B Z +A X +B Z +C Y +B Y +B Z +B X +C Y +B Y +A Y +A X +B Z +B Z +B Z +B Z +C X +A X +B Y +C Y +C Y +B Z +B Z +A Z +B Y +A X +A Z +B Z +A X +B X +B X +B X +B X +A X +A Z +B X +B Z +B X +B Z +B X +C Y +C Y +C X +B X +A Z +C Y +B Z +C Z +B X +B Z +B Z +C Z +C Y +B X +B X +C Y +A Y +A X +C Z +B X +B X +C X +C X +C Y +C X +C Y +C Y +C Y +B Z +B Z +A X +C Y +C Y +A Y +C Y +A Z +B Z +A Y +C Y +C Y +A X +B X +B Z +C Y +C Y +B Z +B X +C Y +B Y +A Z +A Z +C Y +B X +C Y +B Z +C Y +B Z +B Z +B X +C Y +C X +B Z +C Z +A Y +C Y +C Y +A Y +C X +A Y +B Z +B Y +C X +A Y +C Y +C X +C Y +C Y +B Z +A Y +B Z +A Y +B Z +B Z +B Z +C Y +A Y +A X +B Z +C Y +C Y +C Y +B X +B Z +C Y +C Y +C Y +B X +C X +B X +A X +B Z +B X +C Z +A X +A X +A X +C Y +C Y +B Z +A Z +C X +B X +C Y +A Y +A Z +A Z +A X +A X +C Y +B Z +A Z +B Z +B X +C Z +B X +B X +B Y +A Z +B Z +C Y +B X +C X +C X +A X +B Z +B X +A Y +B Z +A X +B X +B Z +A X +B Z +C Y +B Y +C Y +A Z +B X +B X +B X +B Z +B Z +B Z +A X +B X +B Z +B Z +A X +B X +C Z +B X +A Z +A Z +C Z +A Y +C Y +B X +B Z +A X +B Z +B X +C Y +C Y +B X +C Y +C X +C Y +B Z +A Z +C Y +A Z +B X +B Z +B Z +A X +A Y +A X +B Z +B Z +B Y +A Z +C Y +B Z +B X +B Z +A Y +C X +B Z +C Y +A Y +A X +A Z +C Y +C Z +A Y +B X +A X +B X +C Y +C Z +B Y +B Z +B Z +C Y +B Z +C Z +B Y +A Z +A Z +B Z +B X +B X +A Z +C Y +B X +B Z +A Y +C Y +B Z +C Y +B X +C Y +C Y +C Y +A Y +C Y +C X +A X +C Y +C Y +A X +C Y +C Z +B X +B X +C Y +A X +A Y +C Y +A X +C X +A Y +A Z +A X +B Z +B Z +C X +C Y +B X +A X +A Z +B X +B Z +A X +B Z +B Z +B Z +B X +B Z +B Z +A Y +C X +A X +B X +B Z +C Y +C Y +C Y +C Y +B Z +C Y +B Y +C Y +A Z +C Y +B Z +B X +B Z +B Z +B X +C Y +A Z +B X +B Z +B Z +B X +C Y +B X +C X +C X +A X +C Y +A X +B Y +C Y +B Z +B X +C Y +B Y +B X +B X +B Y +B X +A Z +B X +B X +B X +B Z +B Y +A X +B X +C Y +C Y +B Y +B X +A Y +C Z +B X +C Y +B X +C Y +A Z +B Y +A Z +B Z +A Y +A X +C Y +B X +B X +A X +B Y +A Z +B X +B Z +A X +C Z +B Y +A X +A X +A X +A X +B Y +C Z +C Y +B Y +C Y +B X +B Z +A X +C Y +A Y +A X +C Y +C Y +B X +B Y +A X +C Y +A Y +A Z +A X +A Y +C Y +A X +C Z +C Y +B Z +B Y +C Y +C Z +A X +A X +C X +B X +C X +B X +A Z +B Z +C Y +C Y +A Z +C Y +A X +C X +B Z +C X +C Z +B X +B X +C Y +B X +A Y +B X +B Z +C X +C Y +B X +B X +B Z +B X +C Y +B Z +C Y +C Y +A Z +C Y +C Y +C Y +B X +B X +A X +C Y +B X +B X +C Y +B Z +A X +B X +C Y +B Z +B Y +B Z +A X +B Y +B Z +C X +C Y +B Z +B Z +B Z +B Z +B Z +C X +B Z +C Y +C X +B Y +B X +B X +C Y +B X +B X +C Y +C Y +A X +C Y +C Z +A Z +C Y +C Y +C Z +A X +C Y +A Y +B X +C X +C Y +C Z +C Y +C Y +B X +A X +B Z +A Y +B Z +B Z +B X +B Z +A Z +B Y +B Y +C Y +A Y +C Y +B X +A X +C Z +B Z +B X +A Z +C Y +C Y +C X +A Z +C Y +C Y +A Y +B Y +B Y +B Z +B Z +B X +B X +B Z +B X +B X +B Z +A Y +A Y +C Y +C Y +B X +A Y +A X +C Y +A Z +C X +B Y +B Y +B Y +A Z +C Y +B Z +B Z +A Y +B Z +B Z +C Z +C X +C X +B X +C Y +B X +B X +C Y +A X +A Z +C X +B X +A X +B Z +A X +B X +A Y +B X +B Z +B X +B X +C Z +A Z +B Z +C Z +B X +B X +A X +B Z +B Z +B Z +B Z +B Z +B Z +B X +C Y +B Z +B X +B X +C Y +C Y +B Z +B Z +B X +A Y +A X +A Z +C Z +A X +B Z +B X +B Z +B X +C Y +A X +A Y +C Y +C Y +B X +B X +B X +B Z +B X +B Z +A Y +A X +C Y +A Z +C Y +A X +C Y +B Z +A Y +C Y +C Y +C Y +B Z +B Z +A Z +A X +B X +C Y +A X +B Y +C Y +B X +B Z +B Z +A Z +B Z +C Y +B Z +A X +C X +B Z +B X +A X +C Y +C Y +A Z +C Y +C Z +A Z +A Z +B X +B X +B Z +C Y +B Z +B Z +C Y +B X +B Y +B Z +C Y +A X +C Y +A Y +C Y +C Y +C Y +B X +B X +B Z +B Y +C Y +B Y +A Z +A Z +B X +A Z +C X +C Y +B Z +B X +B Z +B X +B Z +B Z +B X +B Z +B Z +C X +C Y +A Z +C Y +B Y +A X +B Z +B Y +A Z +A X +B X +C Y +B Z +C Y +B X +C Y +B Z +B Y +B X +A Z +B Y +C Y +B X +C Y +A X +B Y +B X +C Y +C X +B X +B X +C Y +C Y +B Z +A X +B X +B Z +A X +B X +A X +B X +B X +B Y +C Y +A X +C X +C Y +C X +B Y +A Z +A X +C Y +B X +B X +B Z +C Y +B Z +B X +B Z +B Y +B Y +B Z +B X +C Y +B Y +A X +C Y +B Z +B Z +C Y +A Z +C Y +B Y +C Y +B Y +B X +B Z +B X +C Y +B X +C Y +B Z +C Y +B Z +B X +B X +B Z +A X +C Y +A X +B X +C Y +B X +C Z +C Y +B Z +A Y +A Y +C Y +B Z +A Z +B Z +C Y +A Z +B X +A X +B X +C Y +B Z +A X +B X +A Y +B X +B Z +A Z +C Y +A Z +C X +A Z +B X +C Y +B Z +B Z +A X +B Y +C Z +B Z +A Z +C Y +B X +C Y +B X +C Y +B Y +B Z +C Y +B Z +C Y +C Y +B Y +B Y +C Y +C Y +A Y +B Y +B X +C Y +C Y +C X +C Y +C Y +B Z +B X +B X +C Y +C Y +A X +C Y +C Y +B X +A Y +B X +A X +B Y +B X +B Z +B X +C Y +B Z +A Z +B Z +C X +B Z +B Y +B Z +B Z +C Y +B X +B X +C Y +B Z +B Z +B Z +B Z +A X +C Y +A Z +A X +C X +B Z +B Y +A Y +B X +C Y +B X +C Y +C Z +A Z +C Y +C Y +C Y +B Z +B Y +A X +C Y +B X +B X +B Z +B X +C Y +C Y +A X +B Z +B Z +C Y +B Y +B Y +B Z +A X +B Z +A X +B Y +C X +A Z +B Z +B Z +B X +C Y +B Y +B Y +B X +C Y +B X +B Z +C Y +B Z +A X +A Z +B Y +C Y +B X +B Z +C Y +B X +B X +B Z +B Y +C X +B X +A X +B X +B Z +B Z +B Z +A Z +A Z +B X +C X +B X +B Y +C Z +C Y +B Y +A X +A Z +B Z +B X +B Z +B Z +A Y +A Z +C Y +C Y +C Y +A Y +B Z +C X +C Y +C Y +A Z +B Z +C Y +B Z +C Y +A X +C Y +C Y +B X +A X +B X +A X +A Z +A X +B Y +B X +A X +B Z +B Z +B X +A Z +B X +A X +B Z +B Z +B Z +A X +B X +C Y +C Y +B Z +A X +A X +B Z +C X +B Z +C Y +C Y +C Y +A Y +B X +C Z +C Y +B X +A Y +A Z +C X +B Y +B Z +C Y +B X +A Z +C Z +C Y +C Y +B Z +B X +B Z +A Z +C Y +B X +A X +C Y +C Y +B X +B Y +B X +B X +C Y +B Y +C Y +B Z +B X +A Y +A X +B Z +A Z +B Z +B Z +A Y +C Y +A X +B X +B X +A X +C Y +B Z +B Y +B Z +B Z +B X +C Y +C Y +C Z +B Y +B Y +B Z +B X +B Z +C Y +B X +A Z +C Y +B Z +B X +C Y +C Y +C Y +B Z +C Y +B Z +C Y +B Z +B Z +B Z +C Y +C Y +B Z +C Z +A Y +A Z +A Z +C Y +C Y +A Z +B X +B X +A X +B Z +B Z +A X +A Z +C Y +B X +A Z +B X +C Y +A Z +C Y +B Z +B X +B X +B Z +B X +C Y +C Z +C Z +B X +A X +A Y +B Y +B X +B X +A Y +A X +B X +C Y +C Y +B Z +B Z +A X +C Y +B Z +B X +B Z +C Y +B X +C Y +B Z +B Y +B Z +B X +B X +C Y +B Z +B Z +B Z +A X +B Z +B Z +B Z +A Y +A X +C Y +B Z +B X +A X +B Z +C Y +B X +B Z +C Z +C Y +C Y +B Y +B Y +C Y +A Y +B Y +A Y +C Y +A Z +B X +B Y +C Y +A X +B Z +C Y +A X +B X +C Y +B X +A Y +C Z +C X +C Z +B Z +C X +A Z +C X +B Z +B Z +B Z +A X +C Y +B X +A Y +C Y +B Z +A Y +A Z +B X +A Z +C Y +C Y +C Y +B Z +B Y +A X +C Y +C X +A Y +B Z +A X +A Z +C Y +A Z +B Z +B Z +C X +B X +C Y +A X +C Y +A Z +B Z +B Z +B X +C Y +C Y +C X +C Z +C Y +C X +C X +C Y +B X +C X +C Z +C Y +B Y +C X +A X +C Y +A X +C Z +C X +C Y +B X +A Z +B Z +B X +B Z +B X +C Y +B Y +B Z +B X +B Z +C Y +C Z +B X +B Y +C Y +C Y +C Y +C X +A Y +B X +C X +B X +B Y +B Z +C X +B Z +B Z +A X +A X +B Z +B Z +A Y +A Z +B Y +A X +B X +B X +C Y +A X +A Y +B X +B Z +C Z +B Z +B X +C Y +C Y +B Z +A Z +B X +A Y +A Y +C Y +B Z +B X +A X +B Y +A Y +B Z +B Z +B Z +B Y +C Z +A X +C X +B Y +A Y +B Z +C Y +A X +B Z +C Y +A X +B X +B Z +B X +B Z +B Z +C Y +A Z +B X +C Y +B Z +A Y +B X +C X +B X +B X +B Z +B X +B Z +B X +B Z +B Z +C Y +B Z +C Y +B X +B Z +B X +B Z +C Y +B X +C Y +A Z +A Z +B Z +B X +B Z +B X +C Y +A Y +A X +B Z +B X +B X +A Z +A X +C Z +A X +A X +C Z +C Y +B X +B X +B Z +A Z +B X +C Y +B X +B Z +C X +C Y +C Y +A Z +B X +B X +C Z +C Y +B X +A X +C X +B Z +B Z +B X +C Y +B Z +A X +B X +B Z +A Z +B X +A Y +B Z +B X +C Y +B Y +C Y +A Z +A X +C Y +A Z +A X +C Y +C Y +C Y +C Y +C Y +B X +C X +B Y +A Z +B Z +C Y +A X +B Z +C X +C Y +B X +A Y +B X +B Z +C Y +B X +A Y +B Z +C Y +B Z +A X +B X +C Y +A Y +B Z +B X +A Z +C Y +B Y +A Y +A Z +B Y +C Y +B Z +B Z +B Z +C X +C X +B Y +B Z +A X +C Y +C Y +A Y +A X +A X +C Y +A Y +B Z +B Z +B Z +B X +A X +B X +C Y +A Z +B X +A Y +A X +A X +B Z +B Z +C Y +B X +B Z +C Y +B Z +A Z +C Y +B X +B Z +C X +C Y +C Y +C Z +B Z +B X +A X +B Z +C Z +C Y +C Y +C Y +B Z +A Y +C Y +B X +C Y +C Y +B X +B X +C Y +C Y +B Z +B X +A Z +C Z +B Z +A X +B Y +B Z +A X +C Y +C Y +B Z +A Y +C Y +B Y +B Z +C Y +A X +C Y +C X +C Y +C Y +A Y +B Z +C Y +C Y +B X +C Y +B Z +B Z +C Z +B Z +C Y +B Z +B Z +C Y +A X +C Y +A Z +B X +C X +B X +C X +A Z +C Y +A X +A X +B Z +C Y +B Z +B X +A Y +B Z +C X +B Z +A Y +C Y +B X +A Z +B Z +B Z +B Z +B Z +B Z +C Y +C Y +C Y +B X +A Y +A Z +B Z +C Y +B Y +C X +B X +B Z +B X +C Y +A X +C Z +C Y +A X +B X +C Y +B X +A X +C Z +C Y +C Y +C Z +C Y +C Y +B X +C Y +A Y +B X +B Z +B Z +C Y +A X +B Z +B Z +C Y +B X +B Z +B Z +C Y +C X +B Z +B Z +A Z +B X +B Z +B Z +B X +B X +B X +A X +A Z +B Z +B Z +B X +B X +C Y +C Y +B X +A Y +C Y +B Z +C Z +B Y +B Z +C X +A X +B X +C Y +C Y +A Y +C X +B Z +B Z +B Z +B Z +A Z +A Y +A X +A Y +B Y +A Y +B Z +C Y +C X +C X +B Z +C Y +A X +B Y +B X +B X +B X +A Y +B Z +B X +B Z +B Z +B Z +A Z +C Y +C Y +C Y +B Z +C X +B Z +A X +A Y +B Z +C Z +B Z +A X +B Z +A X +B Z +A Z +A X +B Z +B Z +B Z +B X +A Z +B X +C Y +B Y +B X +A X +B Z +A Z +B Z +B Z +B Y +C X +B X +B Z +A X +B X +B Z +B X +C Y +C Z +A Y +B Y +A X +B Z +B Y +A Z +C X +C Y +B Z +A X +C Y +A Y +C Y +C X +A Y +B X +B X +B Z +C Y +B Y +A X +B Z +B X +A X +A X +B X +A X +B Z +B X +B Y +C Y +B Z +C Y +C X +B Z +B Z +B Z +C Y +A X +B Z +A Y +A X +C Y +B Z +C Y +C X +C Y +C Y +A X +B Z +A X +A X +B X +B Y +C Y +C Y +A X +B Z +C Y +C X +B Z +B Z +B Z +B X +A Y +B X +C Y +A X +C Y +B Z +C Y +C Y +A X +B Y +B Z +B Y +A Y +B Z +B Y +B Z +A Y +C Y +A Y +A X +A Z +A X +B X +C Y +C Y +B X +A Z +B X +B Z +B X +B X +B Z +C Y +B Z +B Z +B X +A Z +A Y +C Y +B Y +C Y +C Y +B Z +C Y +C Y +B Y +B Z +B X +C Y +B Z +B Z +A Y +A Y +B X +B X +C Y +B Z +B Z +B X +B X +C Y +A Z +B X +B X +A Z +B X +B Z +B X +B X +A X +C Y +C Y +C Y +B X +A Z +C Y +C Y +B Z +B X +B Z +B Z +B Z +B Y +A X +A Z +C Y +C Y +B X +B Y +C X +A Z +C X +C Y +C X +C Y +C Y +C X +A X +B Z +B X +B Z +C Y +A Y +B X +B Z +C X +B X +B Y +B Z +B Z +A Z +C X +B X +B X +B Y +B Z +C Y +C Y +C Y +A Z +B Z +A Z +B Z +B X +C Y +B X +B X +A Y +C Y +A X +B Z +C Y +B Z +B Z +B Z +B Y +C Y +A Z +B X +C Y +B Z +C X +B X +A X +B Z +B X +A Y +B Z +B Z +C X +B X +B X +B Z +B Z +B X +C Y +B Z +A Y +B X +C X +C Y +B Y +B Z +B X +C X +C Y +B X +B Z +B Z +B X +C Z +B Z +B X +C X +C X +B Z +B Z +C Y +B X +C Y +A Z +A Z +B Z +B X +A Z +B X +B Z +B Y +B Z +C Y +B Z +A Z +C X +B Z +B Z +C Y +A Z +C Y +C Y +C Y +A X +A Z +A Z +B Z +C X +A X +C Y +B X +B X +C Y +C X +A Z +B X +B Z +B X +B Y +C Y +A X +C Y +C Y +A X +C Y +B Z +B X +C Y +C Y +B X +C Y +C Y +C Y +A X +B Z +B X +B Z +B Y +A Z +B Z +C Y +B Z +A X +A Z +A Y +B Y +B Z +B Z +A X +B Y +A Z +B Z +B Z +A Y +C Y +B X +B Z +A X +B Z +B Z +A X +B Z +B Z +B X +A Z +B X +B Z +A Y +A Y +A X +C Y +B Z +A X +B Z +C Y +B Z +B X +C Y +C Y +C Y +B X +A Z +C Y +B Y +B Z +B Z +B Z +B X +C Y +C X +A X +B Z +A X +C Y +C Y +B X +B X +B Z +C Z +C Y +C Y +A Y +C Y +B Z +B X +B X +B Z +C Y +B Z +B X +B X +C Z +B X +C X +C Y +C Y +C X +C Y +C Y +B Z +B X +B X +C Y +C Y +C Y +B Y +A X +B Z +B Y +A Z +B Z +C X +B Y +B X +B Z +B X +A Z +A Z +C Y +C X +C Y +A Z +B Y +A Y +C Y +B Z +A Z +A Z +C Y +B Z +B X +B Z +C Z +C Y +C X +B Z +B X +A X +A Y +B Z +B X +A Y +B X +B X +C Y +B X +B Z +A Z +C Y +C Y +A Y +B Z +C Y +B Y +C Y +C Y +C Y +B Z +A Y +B Z +A X +B X +B Z +B Z +B Z +A X +C X +B X +C X +A Z +C Y +B X +B Z +B Y +C Y +C Y +B Y +B Y +C Y +C Y +A X +C Y +B Y +B X +B X +A Z +B X +C Y +B Z +A Z +C Y +C X +A Z +B Z +A Z +C Y +B Z +B X +C Y +B Z +B Z +B X +C Z +B X +B Z +B Y +B Y +B X +B Z +C Y +B Z +B Z +B X +B Z +B Z +B Z +C X +B X +C Y +B Z +C X +C Y +C X +C X +B Y +B Z +A X +C X +B Z +A Z +A X +B Z +B Z +B Z +C Y +B X +B X +C Y +B X +C Y +B Z +B Y +B X +B Y +A X +B Z +A X +C X +C X +B Z +C Y +A Y +B X +B X +C Y +C Y +C Y +C Y +B Z +B Z +C Y +B Z +B X +B X +B Z +B X +B X +B Z +B Y +C Z +C X +C Y +B X +B X +A X +B X +C Y +A Z +B Z +B X +C Y +B Z +B Z +B Z +B Z +B Z +B Z +A Y +C Y +C X +C Y +C Y +A X +B X +B Z +B Y +B Z +C Y +B Y +A Y +A Z +B Z +B Y +C Z +B Z +C Y +B Z +C Y +B Z +B Z +C Y +C Z +A X +C Y +C Y +A Z +A X +C Y +B Z +C X +C Y +B Z +B Z +B Z +C Z +B Y +B Z +B Z +C Y +C Y +A Y +B Y +B X +B X +B Z +B Y +A Z +A X +A Y +C Y +B Z +C Z +A Y +B X +B Y +C Y +C X +C Y +B X +B X +C X +C Y +B Z +C Y +C Y +C Z +B Z +B X +A X +C X +C Y +B Z +B X +B Z +B Z +B Z +C Y +A X +C X +B Y +B X +A X +A Y +B X +C Y +B X +C Z +C X +B X +A Z +B Z +B X +B Z +A Y +C X +A Z +B Y +B Z +C X +C Z +B X +B Z +B X +B Z +B Z +C X +B X +B X +A Z +C Y +B X +C Y +B Z +B Z +C X +C Y +B Z +A X +B Z +C Y +B X +A X +C Y +A X +A X +C Y diff --git a/advent/days/day02/data/test01.txt b/advent/days/day02/data/test01.txt new file mode 100644 index 0000000..25097e8 --- /dev/null +++ b/advent/days/day02/data/test01.txt @@ -0,0 +1,3 @@ +A Y +B X +C Z \ No newline at end of file diff --git a/advent/days/day02/solution.py b/advent/days/day02/solution.py new file mode 100644 index 0000000..53c9487 --- /dev/null +++ b/advent/days/day02/solution.py @@ -0,0 +1,195 @@ +from __future__ import annotations + +from typing import Iterator +from enum import Enum + +day_num = 2 + + +def part1(lines: Iterator[str]) -> int: + return sum(player.score(opponent) for opponent, player in (Shape.parse(line) for line in lines)) + + +def part2(lines: Iterator[str]) -> int: + return sum(result.score(opponent) + for opponent, result in (Result.parse(line) for line in lines)) + + +class Shape(Enum): + """ + A class that prepresents the Shapes of Rock Paper Scissors. + Rock beats Scissors + Paper beats Rock + Scissors beats Paper + """ + Rock = 1 + Paper = 2 + Scissors = 3 + + @staticmethod + def parse(line: str) -> tuple[Shape, Shape]: + """ + Parses a line into a game of RPC + Parameters + ---------- + line : str + The line to be parsed + + Returns + ------- + tuple[Shape, Shape] + a tuple of the Shapes given. The first is the opponent, the second the player + + Raises + ------ + Exception + If either the line does not contain exactly two shapes, + or either of the shapes is unknown + """ + match line.strip().split(): + case [o, p]: return Shape.parse_opponent(o), Shape.parse_player(p) + case _: raise Exception(f"Unknown line: {line}") + + @staticmethod + def parse_opponent(char: str) -> Shape: + """ + Parses a shape for RPC + A -> Rock + B -> Paper + C -> Scissors + Parameters + ---------- + char : str + The character to be parsed into a shape + + Returns + ------- + Shape + The shape described by the character + + Raises + ------ + Exception + If the character does not describe a valid shape + """ + match char.strip().upper(): + case 'A': return Shape.Rock + case 'B': return Shape.Paper + case 'C': return Shape.Scissors + case _: raise Exception(f"Unknown char : {char}") + + @staticmethod + def parse_player(char: str) -> Shape: + """ + Parses a shape for RPC using rules for player shapes + X -> Rock + Y -> Paper + Z -> Scissors + Parameters + ---------- + char : str + The character to be parsed into a shape + + Returns + ------- + Shape + The shape described by the character + + Raises + ------ + Exception + If the character does not describe a valid shape + """ + match char.strip().upper(): + case 'X': return Shape.Rock + case 'Y': return Shape.Paper + case 'Z': return Shape.Scissors + case _: raise Exception(f"Unknown char : {char}") + + def prev(self) -> Shape: + """ The Shape preceding the curent one """ + return Shape((self.value + 1) % 3 + 1) + + def next(self) -> Shape: + """ The Shape following the curent one """ + return Shape(self.value % 3 + 1) + + def beats(self, other: Shape) -> bool: + """ true if this shape beats the other one """ + return self == other.next() + + def score(self, other: Shape) -> int: + """ The score according to elf RPC rules """ + if self == other: + points = 3 + elif self.beats(other): + points = 6 + else: + points = 0 + + return self.value + points + + +class Result(Enum): + Lose = 1 + Draw = 2 + Win = 3 + + @staticmethod + def parse(line: str) -> tuple[Shape, Result]: + """ + Parses a line into a game of RPC with anm expected outcome + Parameters + ---------- + line : str + The line to be parsed + + Returns + ------- + tuple[Shape, Result] + a tuple of the Shape the other play will use and an expected result + + Raises + ------ + Exception + If either the line does not contain exactly two items, + or either the shape or result is unknown + """ + match line.strip().split(): + case [o, r]: return Shape.parse_opponent(o), Result.parse_result(r) + case _: raise Exception(f"Unknown line: {line}") + + @staticmethod + def parse_result(char: str) -> Result: + """ + Parses an expected result for RPC + X -> Lose + Y -> Draw + Z -> Win + Parameters + ---------- + char : str + The character to be parsed into a result + + Returns + ------- + Result + The result described by the character + + Raises + ------ + Exception + If the character does not describe a valid result + """ + match char.strip().upper(): + case 'X': return Result.Lose + case 'Y': return Result.Draw + case 'Z': return Result.Win + case _: raise Exception(f"Unknown char : {char}") + + def score(self, other: Shape) -> int: + """ The score we get by the given shape and the expected result """ + match self: + case Result.Lose: return other.prev().score(other) + case Result.Draw: return other.score(other) + case Result.Win: return other.next().score(other) diff --git a/advent/days/day02/test_solution.py b/advent/days/day02/test_solution.py new file mode 100644 index 0000000..68d9cac --- /dev/null +++ b/advent/days/day02/test_solution.py @@ -0,0 +1,45 @@ +from advent.common import utils + +from .solution import day_num, part1, part2, Shape, Result + + +def test_part1(): + data = utils.read_data(day_num, 'test01.txt') + expected = 15 + result = part1(data) + assert result == expected + + +def test_part2(): + data = utils.read_data(day_num, 'test01.txt') + expected = 12 + result = part2(data) + assert result == expected + + +def test_parse_line(): + input = "A Y" + expected = Shape.Rock, Shape.Paper + result = Shape.parse(input) + assert result == expected + + +def test_round1(): + input = "A Y" + expected = 8 + opponent, player = Shape.parse(input) + assert player.score(opponent) == expected + + +def test_round2(): + input = "A Y" + expected = 4 + opponent, player = Result.parse(input) + assert player.score(opponent) == expected + + +def test_round3(): + input = "B X" + expected = 1 + opponent, player = Result.parse(input) + assert player.score(opponent) == expected