Skip to content
Snippets Groups Projects
Verified Commit 1ba0b5b1 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Completed 2023 Day 09, plus part 1 of 07 & part 1 (maybe part 2) of 08

parent 16bdb96e
Branches
No related tags found
No related merge requests found
from typing import List, Optional, Tuple
from ImportData import import_data
day: int = 7
sample_data: List[str] = '''
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
'''.split('\n')[1:-1]
class Hand:
part: int = 1
def __init__(self, cards: str, bid: str):
self.bid: int = int(bid)
self.cards_string = cards
self._strength_of_hand = None
self.original_cards: List[int] = []
self.sorted_cards = []
self.reset_hand()
@staticmethod
def face_to_int(card: str) -> int:
number: int
try:
number = int(card)
except ValueError: # it's pythonic but it stinks
if card == 'T':
number = 10
elif card == 'J':
number = 11 if Hand.part == 1 else 1
elif card == 'Q':
number = 12
elif card == 'K':
number = 13
elif card == 'A':
number = 14
else:
number = 0
return number
@property
def strength_of_hand(self) -> int:
"""
6 = five of a kind
5 = four of a kind
4 = full house
3 = three of a kind
2 = two pair
1 = one pair
0 = high card
:return: strength of the hand
"""
if self._strength_of_hand is not None:
return self._strength_of_hand
number_of_pairs: int = 0
number_of_triples: int = 0
number_of_quartets: int = 0
number_of_quintets: int = 0
number_of_wildcards: int = 0
i: int = 0
while i < len(self.original_cards) - 1:
card: int = self.sorted_cards[i]
card_count: int = self.sorted_cards[i:].count(card)
if card == 1:
number_of_wildcards = card_count
elif card_count == 2:
number_of_pairs += 1
elif card_count == 3:
number_of_triples += 1
elif card_count == 4:
number_of_quartets += 1
elif card_count == 5:
number_of_quintets += 1
i += card_count
# yahtzee
if (number_of_quintets == 1 or
(number_of_quartets == 1 and number_of_wildcards == 1) or
(number_of_triples == 1 and number_of_wildcards == 2) or
(number_of_pairs == 1 and number_of_wildcards == 3) or
number_of_wildcards == 4):
self._strength_of_hand = 6
# four of a kind
elif (number_of_quartets == 1 or
(number_of_triples == 1 and number_of_wildcards == 1) or
(number_of_pairs == 1 and number_of_wildcards == 2) or
number_of_wildcards == 3):
self._strength_of_hand = 5
# full house, or three of a kind
elif number_of_triples == 1:
self._strength_of_hand = 4 if number_of_pairs == 1 else 3
# full house, or two pair
elif number_of_pairs == 2:
self._strength_of_hand = 4 if number_of_wildcards == 1 else 2
# three of a kind
elif ((number_of_pairs == 1 and number_of_wildcards == 1) or
number_of_wildcards == 2):
self._strength_of_hand = 3
# one pair
elif (number_of_pairs == 1
or number_of_wildcards == 1):
self._strength_of_hand = 1
else:
self._strength_of_hand = 0
return self._strength_of_hand
def is_stronger_than(self, other: "Hand") -> bool:
if self.strength_of_hand > other._strength_of_hand:
return True
if other._strength_of_hand > self.strength_of_hand:
return False
is_stronger: bool = False
i: int = 0
while i < len(self.original_cards) and not is_stronger:
if self.original_cards[i] > other.original_cards[i]:
is_stronger = True
return is_stronger
def get_sortable_key(self) -> Tuple[int, ...]:
keys: List[int] = self.original_cards.copy()
keys.insert(0, self.strength_of_hand)
return_value = tuple(keys)
return return_value
def reset_hand(self):
self._strength_of_hand = None
self.original_cards: List[int] = [Hand.face_to_int(card) for card in self.cards_string]
self.sorted_cards = sorted(self.original_cards)
data_structure: type = List[Hand]
def parse_data(data: List[str]) -> data_structure:
return [Hand(datum.split()[0], datum.split()[1]) for datum in data]
def part_x(data: data_structure, part: int) -> int:
Hand.part = part
for hand in data:
hand.reset_hand()
sorted_hands: List[Hand] = sorted(data, key=lambda h: h.get_sortable_key())
winnings: int = 0
for rank, hand in enumerate(sorted_hands):
winning = (rank + 1) * hand.bid
winnings += winning
return winnings
def part1(data: data_structure) -> int:
return part_x(data, 1)
def part2(data: data_structure) -> int:
return part_x(data, 2)
if __name__ == '__main__':
production_ready = False
raw_data = import_data(day) if production_ready else sample_data
print(part1(parse_data(raw_data)))
print(part2(parse_data(raw_data)))
import functools
from typing import List, Dict, Tuple
from ImportData import import_data
day: int = 8
sample_data: List[List[str]] = [
'''
RL
AAA = (BBB, CCC)
BBB = (DDD, EEE)
CCC = (ZZZ, GGG)
DDD = (DDD, DDD)
EEE = (EEE, EEE)
GGG = (GGG, GGG)
ZZZ = (ZZZ, ZZZ)
'''.split('\n')[1:-1],
'''
LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)
'''.split('\n')[1:-1],
'''
LR
11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
'''.split('\n')[1:-1]
]
data_structure: type = Tuple[str, Dict[str, Tuple[str, str]]]
def parse_data(data: List[str]) -> data_structure:
directions: str = data[0]
nodes: Dict[str, Tuple[str, str]] = {}
for line in data[2:]:
key = line[:3]
left = line[7:10]
right = line[12:15]
nodes[key] = (left, right)
return directions, nodes
def part1(data: data_structure) -> int:
directions, nodes = data
steps = 0
modulus = len(directions)
node = 'AAA'
while node != 'ZZZ':
direction = 0 if directions[steps % modulus] == 'L' else 1
node = nodes[node][direction]
steps += 1
return steps
def part2(data: data_structure) -> int:
directions, nodes = data
steps = 0
modulus = len(directions)
locations = [location for location in nodes.keys() if location[-1] == 'A']
while functools.reduce(lambda x, y: x + y, map(lambda z: (1 if z[-1] == 'Z' else 0), locations)) != len(locations):
direction = 0 if directions[steps % modulus] == 'L' else 1
locations = [nodes[location][direction] for location in locations]
steps += 1
return steps
if __name__ == '__main__':
production_ready = True
# raw_data = import_data(day) if production_ready else sample_data
# print(part1(parse_data(raw_data)))
# print(part2(parse_data(raw_data)))
if not production_ready:
print(part1(parse_data(sample_data[0])))
print(part1(parse_data(sample_data[1])))
print(part2(parse_data(sample_data[2])))
else:
raw_data = import_data(day)
print(part1(parse_data(raw_data)))
print(part2(parse_data(raw_data)))
import functools
from typing import List, Tuple
from ImportData import import_data
day: int = 9
sample_data: List[str] = '''
0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45
'''.split('\n')[1:-1]
data_structure: type = List[List[int]]
def parse_data(data: List[str]) -> data_structure:
reports: List[List[int]] = []
for line in data:
reports.append([int(datum) for datum in line.split()])
return reports
def extrapolator(report: List[int]) -> Tuple[int, int]:
differences: List[int] = []
no_differences: bool = True
for i in range(1, len(report)):
difference = report[i] - report[i - 1]
differences.append(difference)
if difference != 0:
no_differences = False
if no_differences:
return report[0], report[0]
else:
left, right = extrapolator(differences)
return report[0] - left, report[-1] + right
def part1(data: data_structure) -> int:
return functools.reduce(lambda x, y: x + y, map(lambda report: extrapolator(report)[1], data))
def part2(data: data_structure) -> int:
return functools.reduce(lambda x, y: x + y, map(lambda report: extrapolator(report)[0], data))
if __name__ == '__main__':
production_ready = True
raw_data = import_data(day) if production_ready else sample_data
print(part1(parse_data(raw_data)))
print(part2(parse_data(raw_data)))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment