2024-12-22 09:01:48 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
|
|
|
|
|
|
|
# Author: Sebastian Mark
|
|
|
|
# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de)
|
|
|
|
|
|
|
|
# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string
|
|
|
|
|
|
|
|
|
|
|
|
def readinput():
|
|
|
|
with open("input", "r", encoding="utf-8") as file:
|
|
|
|
lines = [int(line.strip()) for line in file.readlines()]
|
|
|
|
return lines
|
|
|
|
|
|
|
|
|
|
|
|
def mix_and_prune(i: int, j: int) -> int:
|
|
|
|
return (i ^ j) % 16777216
|
|
|
|
|
|
|
|
|
2024-12-23 08:01:54 +00:00
|
|
|
def calc_secret(num: int) -> (int, list, list):
|
|
|
|
changes = []
|
|
|
|
numbers = []
|
|
|
|
prev_num = num
|
|
|
|
|
2024-12-22 09:01:48 +00:00
|
|
|
for _ in range(2000):
|
|
|
|
# step 1
|
|
|
|
tmp = num * 64
|
|
|
|
num = mix_and_prune(num, tmp)
|
|
|
|
|
|
|
|
# step 2
|
|
|
|
tmp = num // 32
|
|
|
|
num = mix_and_prune(num, tmp)
|
|
|
|
|
|
|
|
# step 3
|
|
|
|
tmp = num * 2048
|
|
|
|
num = mix_and_prune(num, tmp)
|
|
|
|
|
2024-12-23 08:01:54 +00:00
|
|
|
numbers.append(num)
|
|
|
|
changes.append(num % 10 - prev_num % 10)
|
|
|
|
prev_num = num
|
|
|
|
|
|
|
|
return num, numbers, changes
|
|
|
|
|
|
|
|
|
|
|
|
def find_in_list(lst: list, seq: list) -> int:
|
|
|
|
seq_len = 4
|
|
|
|
for i in range(len(lst) - seq_len + 1):
|
|
|
|
if lst[i : i + seq_len] == seq:
|
|
|
|
return i
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
|
|
def get_subsequences(lsts):
|
|
|
|
sequences = set()
|
|
|
|
length = 4
|
|
|
|
for lst in lsts:
|
|
|
|
sequences.update(
|
|
|
|
tuple(lst[i : i + length]) for i in range(len(lst) - length + 1)
|
|
|
|
)
|
|
|
|
return sequences
|
2024-12-22 09:01:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2024-12-23 08:01:54 +00:00
|
|
|
intial_secrets = readinput()
|
2024-12-22 09:01:48 +00:00
|
|
|
|
|
|
|
# part 1
|
2024-12-23 08:01:54 +00:00
|
|
|
new_secrets = {}
|
|
|
|
for num in intial_secrets:
|
|
|
|
new_secrets[num], _, _ = calc_secret(num)
|
|
|
|
print("Sum: %d" % sum(new_secrets.values()))
|
|
|
|
|
|
|
|
# part 2 (very ugly and very slow brute force)
|
|
|
|
secret_list = {}
|
|
|
|
changes = {}
|
|
|
|
for num in intial_secrets:
|
|
|
|
_, secret_list[num], changes[num] = calc_secret(num)
|
|
|
|
|
|
|
|
bananas = {}
|
|
|
|
sequences = get_subsequences(changes.values())
|
|
|
|
for i, sequence in enumerate(sequences):
|
|
|
|
print(f"\rProcessing sequence {i}/{len(sequences) - 1}", end="", flush=True)
|
|
|
|
for secret, change_values in changes.items():
|
|
|
|
seq_pos = find_in_list(change_values, list(sequence))
|
|
|
|
if seq_pos != -1:
|
|
|
|
bananas[sequence] = (
|
|
|
|
bananas.get(sequence, 0) + secret_list[secret][seq_pos + 3] % 10
|
|
|
|
)
|
|
|
|
print("\nBananas: %d " % max(bananas.values()))
|
2024-12-22 09:01:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|