From 9f35281f5e3de0f2a2be4c54a20d29f3d3a32fd1 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 27 Dec 2023 18:54:06 +0000 Subject: [PATCH] day 4 part 1 solution --- Makefile | 3 +- README.md | 2 +- src/aoc_2023/days/4.py | 15 +++++++ src/aoc_2023/solvers/day_4_solvers.py | 62 +++++++++++++++++++++++++++ tests/test_day_4_solvers.py | 30 +++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/aoc_2023/days/4.py create mode 100644 src/aoc_2023/solvers/day_4_solvers.py create mode 100644 tests/test_day_4_solvers.py diff --git a/Makefile b/Makefile index 73e90c8..b13041c 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,5 @@ solutions: python3 src/aoc_2023/days/1.py --input_file inputs/1.txt --part 1 python3 src/aoc_2023/days/1.py --input_file inputs/1.txt --part 2 python3 src/aoc_2023/days/2.py --input_file inputs/2.txt - python3 src/aoc_2023/days/3.py --input_file inputs/3.txt \ No newline at end of file + python3 src/aoc_2023/days/3.py --input_file inputs/3.txt + python3 src/aoc_2023/days/4.py --input_file inputs/4.txt \ No newline at end of file diff --git a/README.md b/README.md index e4353d1..28a69f1 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,4 @@ docker run aoc-2023-app | 01 | ⭐️ | ⭐️ | | 02 | ⭐️ | ⭐️ | | 03 | ⭐️ | ⭐️ | -| 04 | todo | todo | +| 04 | ⭐️ | todo | diff --git a/src/aoc_2023/days/4.py b/src/aoc_2023/days/4.py new file mode 100644 index 0000000..d7e28a8 --- /dev/null +++ b/src/aoc_2023/days/4.py @@ -0,0 +1,15 @@ +from aoc_2023.solvers.day_4_solvers import ( + solve_day_4, +) +from aoc_2023.utils.input_handling import read_input, parse_args + + +def main(): + args = parse_args() + input = read_input(args.input_file) + result_part_1 = solve_day_4(input) + print(f"Day 4. Total points for part 1 is {result_part_1}. ") + + +if __name__ == "__main__": + main() diff --git a/src/aoc_2023/solvers/day_4_solvers.py b/src/aoc_2023/solvers/day_4_solvers.py new file mode 100644 index 0000000..0975fc1 --- /dev/null +++ b/src/aoc_2023/solvers/day_4_solvers.py @@ -0,0 +1,62 @@ +import re + + +class Card: + def __init__(self, card_number, winning_numbers, numbers_i_have): + self.card_number = card_number + self.winning_numbers = winning_numbers + self.numbers_i_have = numbers_i_have + self.n_winners = None + self.points = None + + def __str__(self): + return ( + f"Card {self.card_number}: {self.winning_numbers} | " + f"{self.numbers_i_have} | " + f"n_winners: {self.n_winners} | points: {self.points}" + ) + + def find_n_winners(self): + self.n_winners = sum( + [1 for n in self.numbers_i_have if n in self.winning_numbers] + ) + + def compute_points(self): + if self.n_winners > 0: + self.points = 2 ** (self.n_winners - 1) + else: + self.points = 0 + + +def parse_input_line(line): + card_number = re.findall(r"(\d+)", line.split(":")[0])[0] + all_numbers = line.split(":")[1] + [winning_numbers, numbers_i_have] = all_numbers.split("|") + winning_numbers = re.findall(r"(\d+)", winning_numbers) + numbers_i_have = re.findall(r"(\d+)", numbers_i_have) + + return (card_number, winning_numbers, numbers_i_have) + + +def create_cards(input_txt): + cards = [] + for line in input_txt: + (card_number, winning_numbers, numbers_i_have) = parse_input_line(line) + card = Card(card_number, winning_numbers, numbers_i_have) + cards.append(card) + return cards + + +def compute_total_score(cards): + total_score = 0 + for card in cards: + card.find_n_winners() + card.compute_points() + total_score += card.points + return total_score + + +def solve_day_4(input) -> int: + cards = create_cards(input) + total_score = compute_total_score(cards) + return total_score diff --git a/tests/test_day_4_solvers.py b/tests/test_day_4_solvers.py new file mode 100644 index 0000000..77dac7b --- /dev/null +++ b/tests/test_day_4_solvers.py @@ -0,0 +1,30 @@ +import pytest +from aoc_2023.solvers.day_4_solvers import solve_day_4 + + +@pytest.fixture +def day_4_test_input(): + return [ + "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53", + "Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19", + "Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1", + "Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83", + "Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36", + "Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11", + ] + + +@pytest.fixture +def day_4_expected_scores(): + return [ + 8, + 2, + 2, + 1, + 0, + 0, + ] + + +def test_solve_day_4(day_4_test_input, day_4_expected_scores): + assert solve_day_4(day_4_test_input) == sum(day_4_expected_scores)