Created
January 2, 2021 04:14
-
-
Save napisani/44d5826aee3c1322510ce355e037654d to your computer and use it in GitHub Desktop.
AoC2020-day22pt2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import List | |
def parse_decks(f): | |
player1_deck = [] | |
player2_deck = [] | |
current_deck = player1_deck | |
for line in f.readlines(): | |
if line == '' or line == "\n" or line.lower().startswith('player 1'): | |
continue | |
if line.lower().startswith('player 2'): | |
current_deck = player2_deck | |
continue | |
current_deck.append(int(line.strip())) | |
return player1_deck, player2_deck | |
def cycle_with_idx(deck, starting_idx): | |
while True: | |
if starting_idx >= len(deck): | |
starting_idx = 0 | |
for idx in range(starting_idx, len(deck)): | |
yield idx, deck[idx] | |
starting_idx = 0 | |
def add_to_end(deck, idx, item): | |
deck.insert(idx, item) | |
return idx + 1 | |
def calc_score(deck, gen): | |
multiplier = len(deck) | |
total = 0 | |
while multiplier > 0: | |
idx, card = next(gen) | |
print(f'multi {multiplier} * card {card}') | |
total += multiplier * card | |
multiplier -= 1 | |
return total | |
def get_game_id(deck, idx, deck2, idx2): | |
return f'{str(idx)}-{",".join([str(item) for item in deck])} against {str(idx2)}-{",".join([str(item) for item in deck2])}' | |
def deck_in_order(deck, idx): | |
gen = cycle_with_idx(deck, idx) | |
return [next(gen)[1] for x in range(0, len(deck))] | |
def play_rounds(deck1: List[int], deck2: List[int], p1_starting_idx=0, p2_starting_idx=0): | |
game_id = get_game_id(deck1, p1_starting_idx, deck2, p2_starting_idx) | |
gen1 = cycle_with_idx(deck1, p1_starting_idx) | |
gen2 = cycle_with_idx(deck2, p2_starting_idx) | |
round_num = 1 | |
previous_round_ids = set() | |
while len(deck1) > 0 and len(deck2) > 0: | |
round_id = get_game_id(deck1, 0, deck2, 0) | |
if round_id in previous_round_ids: | |
return 1, 0 | |
previous_round_ids.add(round_id) | |
p1_idx, p1_card = next(gen1) | |
p2_idx, p2_card = next(gen2) | |
print(f'ROUND: {round_num} -- game_id: {game_id}') | |
print(f'before deck1: {deck_in_order(deck1, p1_idx)}') | |
print(f'before deck2: {deck_in_order(deck2, p2_idx)}') | |
print(f'p1_idx: {p1_idx} p1_card:{p1_card}') | |
print(f'p2_idx: {p2_idx} p2_card:{p2_card}') | |
def handle_p1_wins(): | |
nonlocal p1_idx | |
nonlocal gen1 | |
nonlocal gen2 | |
print('p1 wins') | |
deck2.pop(p2_idx) | |
add_to_end(deck1, p1_idx + 1, p2_card) | |
p1_idx += 2 | |
gen1 = cycle_with_idx(deck1, p1_idx) | |
gen2 = cycle_with_idx(deck2, p2_idx) | |
def handle_p2_wins(): | |
nonlocal p2_idx | |
nonlocal gen1 | |
nonlocal gen2 | |
print('p2 wins') | |
deck1.pop(p1_idx) | |
add_to_end(deck2, p2_idx + 1, p1_card) | |
p2_idx += 2 | |
gen1 = cycle_with_idx(deck1, p1_idx) | |
gen2 = cycle_with_idx(deck2, p2_idx) | |
if len(deck1) - 1 >= p1_card and len(deck2) - 1 >= p2_card: | |
gen1_recurse = cycle_with_idx(deck1, p1_idx + 1) | |
gen2_recurse = cycle_with_idx(deck2, p2_idx + 1) | |
deck1_recurse = [next(gen1_recurse)[1] for _ in range(0, p1_card)] | |
deck2_recurse = [next(gen2_recurse)[1] for _ in range(0, p2_card)] | |
winner, score = play_rounds(deck1_recurse, deck2_recurse, 0, 0) | |
if winner == 1: | |
handle_p1_wins() | |
else: | |
handle_p2_wins() | |
elif p1_card > p2_card: | |
handle_p1_wins() | |
elif p1_card < p2_card: | |
handle_p2_wins() | |
round_num += 1 | |
print('-------------------------------') | |
if len(deck1) == 0: | |
return 2, calc_score(deck2, gen2) | |
return 1, calc_score(deck1, gen1) | |
def day22(): | |
with open('day22input.txt', 'r') as f: | |
deck1, deck2 = parse_decks(f) | |
print(deck1) | |
print(deck2) | |
print(play_rounds(deck1, deck2)) | |
if __name__ == '__main__': | |
day22() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment