2020-12-22 - Crab Combat
(original .ipynb)
Day 22 input is a listing of the cards two players have (mine is here). Part 1 involves applying the rules of a game until one player has no more cards left. Part 2 playing the game with a small modification - it can recurse into many sub-games.
puzzle_input_str = open("puzzle_input/day22.txt", "r").read() test_input_str = """Player 1: 9 2 6 3 1 Player 2: 5 8 4 7 10""" def parse_player(player_str): return [int(card) for card in player_str.split("\n")[1:]] def calc_score(player): return sum((1+i) * card for i,card in enumerate(reversed(player))) def play_combat(player1, player2): while len(player1) != 0 and len(player2) != 0: card1 = player1.pop(0) card2 = player2.pop(0) if card1 > card2: player1 += [card1, card2] else: player2 += [card2, card1] return calc_score(player1), calc_score(player2) def part1(input_str): player1, player2 = [parse_player(player_str) for player_str in input_str.split("\n\n")] return max(play_combat(player1, player2)) assert 306 == part1(test_input_str) print(part1(puzzle_input_str))
31957
%%time # ^^ turning on timing so we can see that this is NOT a fast solution def serialize_hands(player1, player2): player1_str = ",".join(str(card) for card in player1) player2_str = ",".join(str(card) for card in player2) return ":".join([player1_str,player2_str]) def play_recursive_combat(player1, player2): previous_hands = set() while len(player1) != 0 and len(player2) != 0: card1 = player1.pop(0) card2 = player2.pop(0) serialized_hands = serialize_hands(player1, player2) if serialized_hands in previous_hands: return 1, 0 elif len(player1) >= card1 and len(player2) >= card2: score1, score2 = play_recursive_combat(player1[:card1], player2[:card2]) if score1 > score2: player1 += [card1, card2] else: player2 += [card2, card1] else: if card1 > card2: player1 += [card1, card2] else: player2 += [card2, card1] previous_hands.add(serialized_hands) return calc_score(player1), calc_score(player2) def part2(input_str): player1, player2 = [parse_player(player_str) for player_str in input_str.split("\n\n")] return max(play_recursive_combat(player1, player2)) assert 291 == part2(test_input_str) potentially_infinite_game = """Player 1: 43 19 Player 2: 2 29 14""" # it'll terminate with whatever we determine to be the player1 score # for an infinite loop - which I have set as 1 assert 1 == part2(potentially_infinite_game) print(part2(puzzle_input_str))
33212 CPU times: user 12.2 s, sys: 35.8 ms, total: 12.3 s Wall time: 12.5 s