aoc2023/day07.py
2023-12-07 07:06:35 +01:00

91 lines
2.6 KiB
Python

from collections import Counter
from tools.aoc import AOCDay
from typing import Any
F_ORDER = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"]
class CardSet:
def __init__(self, card_string: str, bid: str, part2: bool = False):
self.bid = int(bid)
self.cards = [F_ORDER.index(x) + 1 for x in card_string]
if part2:
for i, c in enumerate(self.cards):
if c == 11:
self.cards[i] = 1
if not part2:
self.strength = self.type_rank()
else:
self.strength = self.joker_type_rank()
def type_rank(self) -> int:
card_set = set(self.cards)
if len(card_set) == 5: # high card
return 0
elif len(card_set) == 4: # one pair
return 1
elif len(card_set) == 3: # two pair or three of a kind
for c in self.cards:
if self.cards.count(c) == 3:
return 3
return 2
elif len(card_set) == 2: # full house or four of a kind
for c in self.cards:
if self.cards.count(c) == 4:
return 5
return 4
else:
return 6
def joker_type_rank(self) -> int:
if 1 not in self.cards:
return self.type_rank()
orig_cards = self.cards.copy()
max_strength = 0
for i in range(2, 15):
self.cards = [x if x != 1 else i for x in self.cards]
max_strength = max(max_strength, self.type_rank())
self.cards = orig_cards.copy()
return max_strength
def __lt__(self, other):
if self.strength < other.strength:
return True
elif self.strength > other.strength:
return False
else:
for i, c in enumerate(self.cards):
if c < other.cards[i]:
return True
elif c > other.cards[i]:
return False
class Day(AOCDay):
inputs = [
[
(6440, "input7_test"),
(247815719, "input7"),
],
[
(5905, "input7_test"),
(248747492, "input7"),
],
]
def parse_input(self, part2: bool = False) -> list:
return [CardSet(*line.split(), part2) for line in self.getInput()]
def part1(self) -> Any:
return sum(c.bid * (i + 1) for i, c in enumerate(sorted(self.parse_input())))
def part2(self) -> Any:
return sum(c.bid * (i + 1) for i, c in enumerate(sorted(self.parse_input(True))))
if __name__ == "__main__":
day = Day(2023, 7)
day.run(verbose=True)