105 lines
2.8 KiB
Python
105 lines
2.8 KiB
Python
|
from enum import Enum
|
||
|
from typing import Tuple
|
||
|
|
||
|
|
||
|
class Command(Enum):
|
||
|
CUT = 1
|
||
|
INC = 2
|
||
|
STA = 4
|
||
|
|
||
|
|
||
|
def parse_data() -> list[Tuple[Command, int]]:
|
||
|
output = []
|
||
|
with open("input.txt") as file:
|
||
|
for line in file:
|
||
|
line = line.rstrip()
|
||
|
if not line:
|
||
|
continue
|
||
|
elif line[:3] == "cut":
|
||
|
output.append((Command.CUT, int(line[3:])))
|
||
|
elif line[:19] == "deal with increment":
|
||
|
output.append((Command.INC, int(line[19:])))
|
||
|
elif line[:19] == "deal into new stack":
|
||
|
output.append((Command.STA, 0))
|
||
|
return output
|
||
|
|
||
|
|
||
|
class Hand:
|
||
|
def __init__(self):
|
||
|
self.hand = []
|
||
|
|
||
|
def generate(self, n: int) -> 'Hand':
|
||
|
self.hand = [x for x in range(n)]
|
||
|
return self
|
||
|
|
||
|
def deal_into_new_stack(self) -> 'Hand':
|
||
|
self.hand = list(reversed(self.hand))
|
||
|
return self
|
||
|
|
||
|
def cut(self, n: int) -> 'Hand':
|
||
|
if n >= 0:
|
||
|
cache = self.hand[:n]
|
||
|
self.hand = self.hand[n:]
|
||
|
self.hand += cache
|
||
|
else:
|
||
|
cache = self.hand[n:]
|
||
|
self.hand = self.hand[:n]
|
||
|
self.hand = cache + self.hand
|
||
|
return self
|
||
|
|
||
|
def deal_with_increment(self, n: int) -> 'Hand':
|
||
|
cache = [0 for _ in range(len(self.hand))]
|
||
|
ptr_o = -1
|
||
|
ptr_n = -n
|
||
|
while (ptr_o := ptr_o + 1) < len(self.hand):
|
||
|
cache[(ptr_n := ptr_n + n) % len(cache)] = self.hand[ptr_o]
|
||
|
self.hand = cache
|
||
|
return self
|
||
|
|
||
|
def find_card(self, card: int) -> int:
|
||
|
for i in range(len(self.hand)):
|
||
|
if self.hand[i] == card:
|
||
|
return i
|
||
|
return -1
|
||
|
|
||
|
def find_position(self, position: int) -> int:
|
||
|
return self.hand[position]
|
||
|
|
||
|
def __str__(self):
|
||
|
return str(self.hand)
|
||
|
|
||
|
|
||
|
def solve_p1(tape: list[Tuple[Command, int]], cards: int) -> int:
|
||
|
my_hand = Hand()
|
||
|
my_hand.generate(cards)
|
||
|
for command, param in tape:
|
||
|
if command == Command.CUT:
|
||
|
my_hand.cut(param)
|
||
|
elif command == Command.INC:
|
||
|
my_hand.deal_with_increment(param)
|
||
|
elif command == Command.STA:
|
||
|
my_hand.deal_into_new_stack()
|
||
|
return my_hand.find_card(2019)
|
||
|
|
||
|
|
||
|
TAPE = parse_data()
|
||
|
print(solve_p1(TAPE, 10007))
|
||
|
|
||
|
|
||
|
def solve_p2(tape: list[Tuple[Command, int]], cards: int, repeats: int) -> int:
|
||
|
my_hand = Hand()
|
||
|
my_hand.generate(cards)
|
||
|
for _ in range(repeats):
|
||
|
for command, param in tape:
|
||
|
if command == Command.CUT:
|
||
|
my_hand.cut(param)
|
||
|
elif command == Command.INC:
|
||
|
my_hand.deal_with_increment(param)
|
||
|
elif command == Command.STA:
|
||
|
my_hand.deal_into_new_stack()
|
||
|
return my_hand.find_position(2020)
|
||
|
|
||
|
|
||
|
# Takes way too long, need better solution
|
||
|
print(solve_p2(TAPE, 119315717514047, 101741582076661))
|