text: # SPDX-License-Identifier: MIT
  # Copyright (c) 2021 Akumatic
  #
  # https://adventofcode.com/2021/day/11
  
  class Octopus:
      def __init__(self, idx, energy):
          self.idx = idx
          self._get_neighbor_idx()
          self.energy = energy
          self.flashed = False
          self.neighbors = list()
  
      def _get_neighbor_idx(self):
          if self.idx == 0: # top left corner
              self.neighbor_idx = [self.idx + i for i in (1, 10, 11)]
          elif self.idx == 9: # top right corner
              self.neighbor_idx = [self.idx + i for i in (-1, 9, 10)]
          elif self.idx == 90: # bottom left corner
              self.neighbor_idx = [self.idx + i for i in (-10, -9, 1)]
          elif self.idx == 99: # bottom right corner
              self.neighbor_idx = [self.idx + i for i in (-11, -10, -1)]
          elif self.idx < 10: # top edge
              self.neighbor_idx = [self.idx + i for i in (-1, 1, 9, 10, 11)]
          elif self.idx > 90: # bottom edge
              self.neighbor_idx = [self.idx + i for i in (-11, -10, -9, -1, 1)]
          elif self.idx % 10 == 0: # left edge
              self.neighbor_idx = [self.idx + i for i in (-10, -9, 1, 10, 11)]
          elif self.idx % 10 == 9: # right edge
              self.neighbor_idx = [self.idx + i for i in (-11, -10, -1, 9, 10)]
          else:
              self.neighbor_idx = [self.idx + i for i in (-11, -10, -9, -1, 1, 9, 10, 11)]
  
      def add_neighbor(self, neighbor):
          self.neighbors.append(neighbor)
  
      def flash(self):
          self.flashed = True
          for neighbor in self.neighbors:
              neighbor.energy += 1
  
  def read_file(filename: str = "input.txt") -> list:
      with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f:
          lines = [line for line in f.read().strip().split("\n")]
      values = list()
      for line in lines:
          values += [int(x) for x in list(line)]
      return values
  
  def create_octopuses(vals: int) -> list:
      octopuses = [Octopus(i, vals[i]) for i in range(len(vals))]
      for octopus in octopuses:
          for i in octopus.neighbor_idx:
              octopus.add_neighbor(octopuses[i])
      return octopuses
  
  def step(octopuses: list) -> int:
      flashes = 0
      for octopus in octopuses:
          octopus.energy += 1
  
      repeat = True
      while repeat:
          repeat = False
          for octopus in octopuses:
              if octopus.energy > 9 and octopus.flashed == False:
                  octopus.flash()
                  flashes += 1
                  repeat = True
  
      for octopus in octopuses:
          if octopus.flashed:
              octopus.flashed = False
              octopus.energy = 0
  
      return flashes
  
  def part1(vals: list) -> int:
      flashes = 0
      octopuses = create_octopuses(vals)
      for _ in range(100):
          flashes += step(octopuses)
      return flashes
  
  def part2(vals: list) -> int:
      octopuses = create_octopuses(vals)
      count = 0
      flashes = 0
      while flashes != 100:
          flashes = step(octopuses)
          count += 1
      return count
      
  if __name__ == "__main__":
      vals = read_file()
      print(f"Part 1: {part1(vals)}")
      print(f"Part 2: {part2(vals)}")
  