diff --git a/2019/aoc2019/day22.py b/2019/aoc2019/day22.py index fc54e39..e3cdfb4 100644 --- a/2019/aoc2019/day22.py +++ b/2019/aoc2019/day22.py @@ -32,7 +32,7 @@ def shuffle(instructions: List[str], deck_size: int) -> List[int]: return deck -def part1(data: TextIO): +def part1(data: TextIO) -> int: instructions = [line.strip() for line in data] result = shuffle(instructions, 10007) @@ -42,3 +42,49 @@ def part1(data: TextIO): 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 +