def load_data(file): with open(file) as f: data = f.read() return [int(n) for n in data.split("\n") if len(n) != 0] def mix(secret, value): return secret ^ value def prune(secret): return secret % 16777216 def evolve(secret): # Step 1 secret = prune(mix(secret, secret * 64)) # Step 2 secret = prune(mix(secret, int(secret / 32))) # Step 3 secret = prune(mix(secret, secret * 2048)) return secret def evolve_n_steps(secret, N): for n in range(N): secret = evolve(secret) return secret # file = "test.txt" file = "input.txt" data = load_data(file) results = {secret: evolve_n_steps(secret, 2000) for secret in data} print(sum(results.values())) ## Part 2 def get_price(secret): return int(str(secret)[-1]) def get_buying_info(secret, n_steps=2000): prices = [get_price(secret)] secrets = [secret] changes = [None] for _ in range(n_steps): secret = evolve(secret) secrets.append(secret) prices.append(get_price(secret)) changes.append(prices[-1] - prices[-2]) return secrets, prices, changes def get_price_from_pattern(pattern, changes, prices): for idx in range(len(changes) - 3): if changes[idx:idx+4] == pattern: return prices[idx+3] return None def get_max_patterns(changes, prices): patterns = [] max_price = max(prices[5:]) print(max_price) print() for idx in range(4, len(prices) - 3): if prices[idx] == max_price: pattern = tuple(changes[idx-3:idx+1]) patterns.append(pattern) return patterns def get_patterns_at(changes, prices, set_price): patterns = [] for idx in range(4, len(prices) - 3): if prices[idx] == set_price: pattern = tuple(changes[idx-3:idx+1]) patterns.append(pattern) return patterns def get_all_patterns(changes): p = set() for idx in range(1, len(changes) - 4): p.add(tuple(changes[idx:idx+4])) return p from collections import defaultdict # file = "test2.txt" file = "input.txt" data = load_data(file) all_patterns = defaultdict(list) all_prices = {} all_changes = {} for secret in data: secrets, prices, changes = get_buying_info(secret) # max_patterns = set(get_max_patterns(changes, prices)) # max_patterns = set(get_patterns_at(changes, prices, 7)) all_changes[secret] = changes all_prices[secret] = prices patterns = get_all_patterns(changes) # all_patterns.append(p) for p in patterns: all_patterns[p].extend([secret]) pattern_counts = {p: len(s) for p, s in all_patterns.items()} sorted_pattern_counts = sorted(list((pattern_counts.values())))[::-1] # Sorted in ascending order # 200 is kind of arbitrary, there was a bit of guessing and checking involved... top_n_counts = sorted_pattern_counts[:200] # Could speed it up by ordering in order of count possible_patterns = [list(p) for p,c in pattern_counts.items() if c in top_n_counts] max_bananas = 0 for pattern in possible_patterns: bananas = 0 for secret in data: prices = all_prices[secret] changes = all_changes[secret] sell_price = get_price_from_pattern(pattern, changes, prices) if sell_price: bananas += sell_price if bananas >= max_bananas: # print("New max: ", bananas) max_bananas = bananas # print(max_bananas)