Simulate any chain reactions.

        Arguments:
        potential_chain: a state to be tested for chain reactions
        already_used_bonus: boolean indicating whether a bonus turn was already
            applied during this action

        Return: final result state or None (if state is filtered out in capture)

        Note that if there is no chain reaction, the final result is the
        same as the original state received.

def _simulated_chain_result(self, potential_chain, already_used_bonus):
        """Simulate any chain reactions.

        Arguments:
        potential_chain: a state to be tested for chain reactions
        already_used_bonus: boolean indicating whether a bonus turn was already
            applied during this action

        Return: final result state or None (if state is filtered out in capture)

        Note that if there is no chain reaction, the final result is the
        same as the original state received.
        """
        while potential_chain:
            # hook for capture game optimizations. no effect in base
            # warning: only do this ONCE for any given state or it will
            # always filter the second time
            if self._disallow_state(potential_chain):
                potential_chain.graft_child(Filtered())
                return None  # no more simulation for this filtered state
            result_board, destroyed_groups = \
                potential_chain.board.execute_once(random_fill=
                                                   self.random_fill)
            # yield the state if nothing happened during execution (chain done)
            if not destroyed_groups:
                # yield this state as the final result of the chain
                return potential_chain
            # attach the transition
            chain = ChainReaction()
            potential_chain.graft_child(chain)
            # attach the result state
            if already_used_bonus:
                # disallow bonus action if already applied
                bonus_action = 0
            else:
                # allow bonus action once and then flag as used
                bonus_action = any(len(group) >= 4
                                   for group in destroyed_groups)
                already_used_bonus = True
            cls = potential_chain.__class__
            chain_result = cls(board=result_board,
                               turn=potential_chain.turn,
                               actions_remaining=
                               potential_chain.actions_remaining + bonus_action,
                               player=potential_chain.player.copy(),
                               opponent=potential_chain.opponent.copy())
            # update the player and opponent
            base_attack = \
                chain_result.active.apply_tile_groups(destroyed_groups)
            chain_result.passive.apply_attack(base_attack)
            chain.graft_child(chain_result)
            # prepare to try for another chain reaction
            potential_chain = chain_result