generated from public/aoc_template
91 lines
2.6 KiB
Python
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)
|