Advertisement
Guest User

Advent of Code Day 22

a guest
Dec 22nd, 2020
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.69 KB | None | 0 0
  1. """Day 22 of Advent of Code 2020 Solution"""
  2. from collections import deque
  3. from operator import itemgetter
  4.  
  5.  
  6. def hand_io(file_location) -> tuple[deque[int], deque[int]]:
  7.     with open(file_location, "r") as f:
  8.         data = f.read().split('\n\n')
  9.         p1 = [int(i) for i in data[0].split('\n')[1:]]
  10.         p2 = [int(i) for i in data[1].split('\n')[1:]]
  11.     return p1, p2
  12.  
  13.  
  14. class CrabCombat:
  15.     def __init__(self, starting_hands):
  16.         self.hands = {f"p{i}": deque(hand) for i, hand in enumerate(starting_hands, 1)}
  17.         self.winner = None
  18.         self.score = None
  19.  
  20.     def __str__(self):
  21.         output = f""
  22.         for k, v in self.hands.items():
  23.             output += f"{k}:\t{v}\n"
  24.         return output
  25.  
  26.     def __repr__(self):
  27.         return f"{self.__class__.__name__}(starting_hands={tuple([t for t in self.hands.values()])})"
  28.  
  29.     def __iter__(self):
  30.         return self
  31.  
  32.     def __next__(self):
  33.         if not self.winner:
  34.             draw = self._draw_cards()
  35.             turn_winner = self._evaluate_turn_winner(draw)
  36.             self._resolve_turn(draw, turn_winner)
  37.             self._evaluate_game_win_condition()
  38.  
  39.     def _draw_cards(self):
  40.         return {k: self.hands[k].popleft() for k in self.hands}
  41.  
  42.     def _evaluate_turn_winner(self, draw):
  43.         return max(draw.items(), key=itemgetter(1))[0]
  44.  
  45.     def _resolve_turn(self, draw, turn_winner):
  46.         if turn_winner == 'p1':
  47.             self.hands['p1'].append(draw['p1'])
  48.             self.hands['p1'].append(draw['p2'])
  49.         else:
  50.             self.hands['p2'].append(draw['p2'])
  51.             self.hands['p2'].append(draw['p1'])
  52.  
  53.     def _evaluate_game_win_condition(self):
  54.         if self.hands['p1'] and not self.hands['p2']:
  55.             self.winner = 'p1'
  56.         if self.hands['p2'] and not self.hands['p1']:
  57.             self.winner = 'p2'
  58.  
  59.     def _score(self):
  60.         score = 0
  61.         for idx, card in enumerate(self.hands[self.winner],
  62.                                    start=-len(self.hands[self.winner])):
  63.             score += abs(idx) * card
  64.         self.score = score
  65.  
  66.     def play(self):
  67.         while not self.winner:
  68.             next(self)
  69.         self._score()
  70.         return self.winner
  71.  
  72.  
  73. class RecursiveCombat(CrabCombat):
  74.     def __init__(self, starting_hands):
  75.         super().__init__(starting_hands)
  76.         self.played = set()
  77.  
  78.     @property
  79.     def _hands_tuple(self):
  80.         return tuple([tuple(hand) for hand in self.hands.values()])
  81.  
  82.     def _evaluate_turn_winner(self, draw):
  83.         if all([len(self.hands[k]) >= draw[k] for k in self.hands]):
  84.             return self.recurse([tuple(self.hands[k])[:draw[k]] for k in draw])
  85.         else:
  86.             return super()._evaluate_turn_winner(draw)
  87.  
  88.     def __next__(self):
  89.         if self._hands_tuple in self.played:
  90.             self.winner = 'p1'
  91.         else:
  92.             self.played.add(self._hands_tuple)
  93.         if not self.winner:
  94.             draw = self._draw_cards()
  95.             turn_winner = self._evaluate_turn_winner(draw)
  96.             self._resolve_turn(draw, turn_winner)
  97.             self._evaluate_game_win_condition()
  98.  
  99.     @classmethod
  100.     def recurse(cls, starting_hands):
  101.         recursive_game = cls(starting_hands)
  102.         recursive_game.play()
  103.         return recursive_game.winner
  104.  
  105.  
  106. def part_a(file_location):
  107.     hands = hand_io(file_location)
  108.     cc = CrabCombat(hands)
  109.     cc.play()
  110.     return cc.score
  111.  
  112.  
  113. def part_b(file_location):
  114.     hands = hand_io(file_location)
  115.     rc = RecursiveCombat(hands)
  116.     rc.play()
  117.     return rc.score
  118.  
  119.  
  120. if __name__ == '__main__':
  121.     file_location = r"data/day22.txt"
  122.     print(part_a(file_location))
  123.     print(part_b(file_location))
  124.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement