From 85a403a813afb011d81e1831b1881a462783df31 Mon Sep 17 00:00:00 2001 From: alexo Date: Sun, 24 Dec 2023 13:30:08 +1100 Subject: [PATCH] day07: tests --- day07/day7.py | 34 +++++++++++++++++++++++----------- day07/input-small.txt | 5 +++++ day07/tests/__init__.py | 0 day07/tests/test_day7.py | 23 +++++++++++++++++++++++ 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 day07/input-small.txt create mode 100644 day07/tests/__init__.py create mode 100644 day07/tests/test_day7.py diff --git a/day07/day7.py b/day07/day7.py index 8b27a45..bdaed62 100644 --- a/day07/day7.py +++ b/day07/day7.py @@ -1,10 +1,15 @@ """day7 solution""" from collections import defaultdict from dataclasses import dataclass, field +from functools import total_ordering from typing import Any, ClassVar, Self +INPUT = "day07/input.txt" +INPUT_SMALL = "day07/input-small.txt" -@dataclass + +@total_ordering +@dataclass(eq=False) class Hand: """Simple hand class, uses cards_inted and of_a_kind for sorting""" @@ -19,9 +24,9 @@ def __post_init__(self) -> None: """convert cards to ints""" self.cards_inted = [self.CARD_MAPPING.index(card) for card in self.cards] self.bet = int(self.bet) - self.of_a_kind = self.calculate_oak() + self.of_a_kind = self.calculate_of_a_kind() - def calculate_oak(self) -> list[int]: + def calculate_of_a_kind(self) -> list[int]: """Figure out card sets""" card_sets: dict[str, int] = defaultdict(int) for card in self.cards: @@ -30,6 +35,8 @@ def calculate_oak(self) -> list[int]: def __lt__(self, other: Self) -> Any: """Less than comparator function""" + if not isinstance(other, Hand): + raise ValueError("using __lt__ on non identical class") # compare our sets for ours, theirs in zip(self.of_a_kind, other.of_a_kind): if ours != theirs: @@ -37,6 +44,11 @@ def __lt__(self, other: Self) -> Any: # compare our individual cards return self.cards_inted < other.cards_inted # int lists easy to compare + def __eq__(self, other: object) -> bool: + if not isinstance(other, Hand): + raise ValueError("using __lt__ on non identical class") + return self.cards_inted == other.cards_inted + class HandPart2(Hand): """Part two; implements joker rule""" @@ -44,7 +56,7 @@ class HandPart2(Hand): CARD_MAPPING = "J23456789TQKA" # new card ordering # override - def calculate_oak(self) -> list[int]: + def calculate_of_a_kind(self) -> list[int]: """ Figure out card sets; jokers will be added to the biggest card set @@ -63,32 +75,32 @@ def calculate_oak(self) -> list[int]: return of_a_kind -def parse_lines(cls: type) -> list[Hand]: +def parse_lines(cls: type, path: str) -> list[Hand]: """open input file and parse into hand structures""" - with open("day07/input.txt", "r", encoding="utf8") as file: + with open(path, "r", encoding="utf8") as file: # wow super cool list comprehension thingo i'm so cool results = [cls(*line.split()) for line in file] return results -def calculate_hands(cls: type) -> None: +def calculate_hands(cls: type, input_path: str) -> int: """generates class `cls` then calculates points""" - hands = sorted(parse_lines(cls)) + hands = sorted(parse_lines(cls, input_path)) score = 0 for rank, hand in enumerate(hands): score += (rank + 1) * hand.bet - print(score) + return score def main() -> None: """main func""" # Q1 - calculate_hands(Hand) + print(calculate_hands(Hand, INPUT)) # Q2 - calculate_hands(HandPart2) + print(calculate_hands(HandPart2, INPUT)) if __name__ == "__main__": diff --git a/day07/input-small.txt b/day07/input-small.txt new file mode 100644 index 0000000..e3500c3 --- /dev/null +++ b/day07/input-small.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 diff --git a/day07/tests/__init__.py b/day07/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day07/tests/test_day7.py b/day07/tests/test_day7.py new file mode 100644 index 0000000..e57c5b1 --- /dev/null +++ b/day07/tests/test_day7.py @@ -0,0 +1,23 @@ +from day07.day7 import INPUT_SMALL, Hand, HandPart2, calculate_hands, parse_lines + + +def test_calculate_hands() -> None: + assert calculate_hands(Hand, INPUT_SMALL) == 6440 + assert calculate_hands(HandPart2, INPUT_SMALL) == 5905 + + +def test_parser() -> None: + hands: list[Hand] = parse_lines(Hand, INPUT_SMALL) + assert len(hands) == 5 + assert hands[0].cards == "32T3K" + assert hands[-1].cards == "QQQJA" + assert hands[0] == Hand("32T3K", 765) + + +def test_hand() -> None: + hand1 = Hand("KK677", 0) + hand2 = Hand("KTJJT", 0) + hand3 = Hand("KK677", 0) + assert hand2 < hand1 + assert hand1 > hand2 + assert hand1 == hand3