Skip to content

Instantly share code, notes, and snippets.

@napisani
Created January 2, 2021 04:14
Show Gist options
  • Save napisani/44d5826aee3c1322510ce355e037654d to your computer and use it in GitHub Desktop.
Save napisani/44d5826aee3c1322510ce355e037654d to your computer and use it in GitHub Desktop.
AoC2020-day22pt2
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