day11_part2.py (1891B)
1 #!/usr/bin/env python 2 """Advent of Code 2021, day 11 (part 2): Flashing octopuses 3 For part 2, we're simulating bioluminescent octopuses again, and this time we 4 want to find the `step` at which they all flash simultaneously.""" 5 6 # I think I can pretty much use everything from part 1 here and just update the 7 # solving code 8 9 import numpy as np 10 from day11_part1 import (EXAMPLE_INPUT, 11 simulate_step) 12 from utils import get_puzzle_input, convert_input_to_array 13 14 def all_flashed(energy_levels: np.ndarray) -> bool: 15 """Detects the moment when all energy levels have been reset to 0""" 16 return not energy_levels.any() 17 18 def run_simulation_until_synchronized(energy_levels: np.ndarray) -> int: 19 """Run the simulation from the initial 2d array of energy levels until all 20 octopuses flash at the same time, and return the step number at which it 21 occurred""" 22 # Leaning on Python's nice iterator behavior and for/else syntax: no need 23 # to risk an infinite loop, we can set a "reasonable" limit of iterations 24 # up front. Also I just love underscores in numeric literals. 25 for num_steps in range(1_000_000): 26 energy_levels = simulate_step(energy_levels)[0] 27 if all_flashed(energy_levels): 28 break 29 else: 30 raise RuntimeError("No synchronized flash detected after many steps") 31 32 # We're counting steps from 1 apparently 33 return num_steps + 1 34 35 def solve_puzzle(input_string: str) -> int: 36 """Return the numeric solution to the puzzle""" 37 return run_simulation_until_synchronized( 38 convert_input_to_array(input_string) 39 ) 40 41 def main() -> None: 42 """Run when the file is called as a script""" 43 assert solve_puzzle(EXAMPLE_INPUT) == 195 44 # Is that you, Shevek? 45 print("Number of steps to simultaneity:", 46 solve_puzzle(get_puzzle_input(11))) 47 48 if __name__ == "__main__": 49 main()