Files
adventofcode/2019/aoc2019/day22.py
2021-07-03 15:05:49 +02:00

91 lines
2.0 KiB
Python

from typing import List, TextIO
def shuffle(instructions: List[str], deck_size: int) -> List[int]:
deck = list(range(0, deck_size))
for instruction in instructions:
if "new stack" in instruction:
deck = list(reversed(deck))
continue
parts = instruction.split(" ")
if parts[0] == "cut":
by = int(parts[1])
new_deck = deck[by:]
new_deck += deck[:by]
deck = new_deck
else:
increment = int(parts[3])
new_deck = list(range(0, deck_size))
target_index = 0
for card in deck:
new_deck[target_index] = card
target_index = (target_index + increment) % len(deck)
deck = new_deck
return deck
def part1(data: TextIO) -> int:
instructions = [line.strip() for line in data]
result = shuffle(instructions, 10007)
for i, card in enumerate(result):
if card == 2019:
return i
raise Exception("Did not find card")
def modpow(a: int, b: int, m: int) -> int:
assert b >= 0
result = 1
n = a
while b > 0:
if b % 2:
result = (result * n) % m
b //= 2
n = (n * n) % m
return result
def inverse(a: int, m: int) -> int:
""" Computes the modulo multiplicative inverse """
return modpow(a, m - 2, m)
def part2(data: TextIO) -> int:
deck_size = 119315717514047
shuffles = 101741582076661
a, b = 1, 0
for line in data:
parts = line.split(' ')
if 'new stack' in line:
la, lb = -1, -1
elif parts[0] == 'deal':
la, lb = int(parts[-1]), 0
else:
la, lb = 1, -int(parts[-1])
a = (la * a) % deck_size
b = (la * b + lb) % deck_size
final_a = modpow(a, shuffles, deck_size)
final_b = ((b * (final_a - 1)) * inverse(a - 1, deck_size)) % deck_size
return ((2020 - final_b) * inverse(final_a, deck_size)) % deck_size