Files
aocpy/2019/d16.py
2024-09-02 14:32:35 -04:00

133 lines
3.8 KiB
Python

from lib import get_data
def part_1_with_numpy(data):
import numpy as np
def make_base_matrix(pattern, n):
xss = []
for round in range(n):
xs = [pattern[((i + 1) // (round + 1)) % len(pattern)] for i in range(n)]
xss.append(xs)
return np.array(xss)
pattern = [0, 1, 0, -1]
input = int(data.strip())
v = np.array(list(map(int, str(input))))
m = make_base_matrix(pattern, len(v))
func = np.vectorize(lambda x: abs(x) % 10)
for _ in range(100):
v = func(np.dot(m, v))
print("".join(map(str, v[:8].tolist())))
def phase(digits_in):
pattern = [0, 1, 0, -1]
digits_out = []
for round in range(len(digits_in)):
i, out = 0, 0
while i < len(digits_in):
pattern_i = ((i + 1) // (round + 1)) % len(pattern)
out += pattern[pattern_i] * digits_in[i]
i += 1
out = abs(out) % 10
digits_out.append(out)
return digits_out
def phase_with_offset(digits_in, pattern, offset):
digits_out = digits_in.copy()
for round in range(offset, len(digits_in)):
i, out = 0, 0
# print(round)
pattern_value = pattern[((i + 1) // (round + 1)) % len(pattern)]
if pattern_value == 0:
i += round
while i < len(digits_in):
pattern_i = ((i + 1) // (round + 1)) % len(pattern)
pattern_value = pattern[pattern_i]
if pattern_value != 0:
out += pattern_value * sum(
digits_in[i : min(i + 1 + round, len(digits_in))]
)
i += round + 1
out = abs(out) % 10
digits_out[round] = out
return digits_out
def part_1(data):
pattern = [0, 1, 0, -1]
input = list(map(int, (data.strip())))
for _ in range(100):
input = phase_with_offset(input, pattern, 0)
print("".join(map(str, input[:8])))
out = list(map(int, (data.strip()))) * 10_000
offset = int("".join(map(str, out[:7])))
for _ in range(100):
for i in range(len(out) - 2, len(out) - 1_000_000, -1):
out[i] = abs(out[i] + out[i + 1]) % 10
print("".join(map(str, out[offset : offset + 8])))
# digits = 40
# for round in range(digits):
# s = ""
# for i in range(digits):
# pattern_i = ((i + 1) // (round + 1)) % len(pattern)
# pattern_value = pattern[pattern_i]
# if pattern_value == 0:
# s += " "
# elif pattern_value == 1:
# s += "+"
# elif pattern_value == -1:
# s += "-"
# else:
# assert False
# print(s)
# return
# Just here to document my thought process. Mental hack: Assume that you
# have the capability to solve the problem easily.
#
# What do I know?
#
# 1. There is a solution. Other people have solved it.
# 2. The solution is not crazy. It will be rather obvious.
# 3. 6_500_000 * 6_500_000 is definitely too much to brute force.
# 4. Can we go from O(N^2) to O(N) somehow? Yes, that's what we have to do.
# The whole point of FFT is to get from O(N^2) to O(N*log(N)). Now,
# how exactly do we do that?
#
# Ways to improve performance:
#
# 1. Speed up `phase` significantly. Yes, but how?
# 2. Only compute a subset of the lists? - No!
# 3. Discover some kind of pattern? - No!
#
# Assumptions:
#
# 1. I need every digit of the previous round. - False!
# 2. I cannot just operate on a subset. - False!
#
# Non-approaches:
#
# 1. Fancy recursive algorithm that selectively picks fields.
# 2. Pattern detection or subset consideration.
def main():
data = get_data(__file__)
# part_1_with_numpy(data)
part_1(data)
if __name__ == "__main__":
main()