diff --git a/python/day01.py b/python/day01.py new file mode 100644 index 0000000..6fea513 --- /dev/null +++ b/python/day01.py @@ -0,0 +1,66 @@ +from utils.load import get_input +from utils.day import DayBase +from dataclasses import dataclass +import logging + +@dataclass +class Day01(DayBase): + def __init__(self, *args, **kargs): + super().__init__(*args, **kargs) + + def parse_data(self, input: str): + return input.splitlines() + + def solve_part1(self, data: list[str])-> int: + count = 0 + current = 50 + + for value in data: + if value[0] == 'L': + current = (current - int(value[1:])) % 100 + else: + current = (current + int(value[1:])) % 100 + + if current == 0: + count += 1 + logging.debug("%s -> %s (count: %s)", value, current, count) + return count + + def solve_part2(self, data: list[str]) -> int: + count = 0 + current = 50 + for value in data: + if value[0] == 'L': + value = - int(value[1:]) + else: + value = int(value[1:]) + + new_current = current + value + div = abs(new_current) // 100 + nb_rotation = div + if new_current < 0: + if current != 0: + nb_rotation += 1 + new_current += 100 * nb_rotation + elif new_current > 0: + new_current -= 100 * nb_rotation + else: + nb_rotation = 1 + new_current %= 100 + + print(f"{current} + {value} = {new_current} (+{nb_rotation})") + current = new_current + count += nb_rotation + + return count + + def test_custom_2_1(self): + return self.solve_part2(["R48", "L498"]) == 5 + + def test_custom_2_2(self): + assert self.solve_part2(["R1000"]) == 10 + +if __name__ == "__main__": + day = Day01(1, "L68\nL30\nR48\nL5\nR60\nL55\nL1\nL99\nR14\nL82", excepted_part1 = 3, excepted_part2=6) + day.run_tests() + day.run() diff --git a/python/utils/day.py b/python/utils/day.py new file mode 100644 index 0000000..ad65472 --- /dev/null +++ b/python/utils/day.py @@ -0,0 +1,49 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass +from .load import get_input +import logging +logging.basicConfig(level=logging.DEBUG) + +@dataclass +class DayBase(ABC): + day_number: int + test_data: str + excepted_part1: str + excepted_part2: str + + def __post_init__(self): + if self.__class__ == DayBase: + raise TypeError("Cannot instantiate abstract class.") + + @abstractmethod + def parse_data(self, input: str): + pass + + def test_part1(self): + data = self.parse_data(self.test_data) + assert self.solve_part1(data) == self.excepted_part1 + + def test_part2(self): + data = self.parse_data(self.test_data) + assert self.solve_part2(data) == self.excepted_part2 + + @abstractmethod + def solve_part1(self, data): + pass + + @abstractmethod + def solve_part2(self, data): + pass + + def run_tests(self): + classes = list(self.__class__.__bases__) + [self.__class__] + for klass in classes: + for element in klass.__dict__: + if callable(getattr(self, element)) and element.startswith("test_"): + logging.debug("Found test: %s", element) + getattr(self, element)() + + def run(self): + data = self.parse_data(get_input(self.day_number)) + logging.info("Part 01 (day %s): %s", self.day_number, self.solve_part1(data)) + logging.info("Part 02 (day %s): %s", self.day_number, self.solve_part2(data)) \ No newline at end of file