From 5736f8d4a21b51c47b7f47ca5ccb62f4fb9f651b Mon Sep 17 00:00:00 2001 From: Ettore Dreucci Date: Tue, 22 Dec 2020 14:20:02 +0100 Subject: [PATCH] AoC 2020: day22 Signed-off-by: Ettore Dreucci --- 2020-python/inputs/day_22 | 53 +++++++++++++++ 2020-python/solutions/day_22.py | 110 ++++++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 164 insertions(+) create mode 100644 2020-python/inputs/day_22 create mode 100644 2020-python/solutions/day_22.py diff --git a/2020-python/inputs/day_22 b/2020-python/inputs/day_22 new file mode 100644 index 0000000..f854947 --- /dev/null +++ b/2020-python/inputs/day_22 @@ -0,0 +1,53 @@ +Player 1: +1 +43 +24 +34 +13 +7 +10 +36 +14 +12 +47 +32 +11 +3 +9 +25 +37 +21 +2 +45 +26 +8 +23 +6 +49 + +Player 2: +44 +5 +46 +18 +39 +50 +4 +41 +17 +28 +30 +42 +33 +38 +35 +22 +16 +27 +40 +48 +19 +29 +15 +31 +20 diff --git a/2020-python/solutions/day_22.py b/2020-python/solutions/day_22.py new file mode 100644 index 0000000..265e9ba --- /dev/null +++ b/2020-python/solutions/day_22.py @@ -0,0 +1,110 @@ +"""AOC 2020 Day 22""" + +import pathlib +import time +import collections +import itertools + +TEST_INPUT = """Player 1: +9 +2 +6 +3 +1 + +Player 2: +5 +8 +4 +7 +10""" + +def read_input(input_path: str) -> str: + """take input file path and return a str with the file's content""" + with open(input_path, 'r') as input_file: + input_data = input_file.read().strip() + return input_data + +def extract(input_data: str) -> tuple: + """take input data and return the appropriate data structure""" + deck1, deck2 = input_data.split('\n\n') + deck1, deck2 = deck1.splitlines(), deck2.splitlines() + deck1 = collections.deque(map(int, deck1[1:])) + deck2 = collections.deque(map(int, deck2[1:])) + + return deck1, deck2 + +def play_space_cards(deck1: collections.deque, deck2: collections.deque) -> collections.deque: + """return the winner's deck after a space cards game""" + assert len(deck1) == len(deck2) + while deck1 and deck2: + card1, card2 = deck1.popleft(), deck2.popleft() + assert card1 != card2 + if card1 > card2: + deck1.extend((card1, card2)) + else: + deck2.extend((card2, card1)) + + return deck1 if deck1 else deck2 + +def play_recursive_space_cards(deck1: collections.deque, deck2: collections.deque) -> tuple: + """return the winner and its deck after a recursive space cards game""" + configurations = set() + + while deck1 and deck2: + current_config = (tuple(deck1), tuple(deck2)) + if current_config in configurations: + return 1, deck1 + configurations.add(current_config) + + card1, card2 = deck1.popleft(), deck2.popleft() + assert card1 != card2 + if card1 <= len(deck1) and card2 <= len(deck2): + sub_deck1 = collections.deque(itertools.islice(deck1, card1)) + sub_deck2 = collections.deque(itertools.islice(deck2, card2)) + winner, _ = play_recursive_space_cards(sub_deck1, sub_deck2) + else: + winner = 1 if card1 > card2 else 2 + + if winner == 1: + deck1.extend((card1, card2)) + else: + deck2.extend((card2, card1)) + + return (1, deck1) if deck1 else (2, deck2) + +def part1(entries: tuple) -> int: + """part1 solver""" + deck1, deck2 = entries[0].copy(), entries[1].copy() + winner = play_space_cards(deck1, deck2) + return sum(index * card for index, card in enumerate(reversed(winner), 1)) + +def part2(entries: tuple) -> str: + """part2 solver""" + deck1, deck2 = entries + _, winner = play_recursive_space_cards(deck1, deck2) + return sum(index * card for index, card in enumerate(reversed(winner), 1)) + +def test_input_day_22(): + """pytest testing function""" + entries = extract(TEST_INPUT) + assert part1(entries) == 306 + assert part2(entries) == 291 + +def test_bench_day_22(benchmark): + """pytest-benchmark function""" + benchmark(main) + +def main(): + """main function""" + input_path = str(pathlib.Path(__file__).resolve().parent.parent) + "/inputs/" + str(pathlib.Path(__file__).stem) + start_time = time.time() + input_data = read_input(input_path) + entries = extract(input_data) + print("Part 1: %d" % part1(entries)) + print("Part 2: %s" % part2(entries)) + end_time = time.time() + print("Execution time: %f" % (end_time-start_time)) + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index f4a85ce..6ce50ab 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,4 @@ | [Day 19](https://adventofcode.com/2020/day/19) | [145.980ms](./2020-python/solutions/day_19.py) | [259.030ms](./2020-python/solutions/day_19.py) | | [Day 20](https://adventofcode.com/2020/day/19) | | | | [Day 21](https://adventofcode.com/2020/day/21) | [2.177ms](./2020-python/solutions/day_21.py) | [1.578ms](./2020-python/solutions/day_21.py) | +| [Day 22](https://adventofcode.com/2020/day/22) | [1.516s](./2020-python/solutions/day_22.py) | [1.353s](./2020-python/solutions/day_22.py) |