def score(state, offset): r = 0 for i in range(len(state)): if state[i] == "#": r += i + offset return r def solve(data, target_i): state = None map = {} for line in data.splitlines(): if "initial state" in line: _, rest = line.split(":") state = rest.strip() if "=>" in line: lhs, rhs = line.split(" => ") assert lhs not in map map[lhs] = rhs assert state is not None seen = {} offset = 0 for i in range(target_i): while not state.startswith("...."): state = "." + state offset -= 1 while not state.endswith("...."): state += "." if state in seen: prev_i, prev_score = seen[state] assert (i - prev_i) == 1 current_score = score(state, offset) delta_score = current_score - prev_score final_score = current_score + (target_i - i) * delta_score print(final_score) return else: seen[state] = (i, score(state, offset)) ns = "" for i in range(2, len(state) - 2): s = state[i - 2 : i + 3] ns += map[s] state = ns offset += 2 print(score(state, offset)) def main(): input_file = __file__.replace(".py", ".txt") with open(input_file) as f: data = f.read() solve(data, 20) solve(data, 50 * 10**9) if __name__ == "__main__": main()