gt:             while (iterator.hasNext()) {
context: package org.cell2d;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.NoSuchElementException;
  import java.util.Queue;
  import java.util.Set;
  
  /**
   * <p>A Thinker is a collection of methods that contributes to the mechanics of
   * a GameState to which it is assigned. A Thinker can be a GameState itself, in
   * which case it is considered assigned to itself. It can also be a SubThinker
   * that can be assigned to another Thinker, in which case it is considered
   * assigned to a GameState if it is assigned to another Thinker that is itself
   * assigned to the GameState.</p>
   * 
   * <p>A Thinker's assigned GameState will keep track of time for the Thinker,
   * thus allowing the Thinker to take its own time-dependent actions, while the
   * GameState is active. A Thinker's <i>time factor</i> represents the average
   * number of discrete time units the Thinker will experience each frame while
   * assigned to an active GameState. If its time factor is negative, as it is by
   * default, a Thinker will use a time factor of one fracunit (if it is a
   * GameState) or share the time factor of the Thinker to which it is assigned
   * (if it is a SubThinker). If a Thinker is assigned to an inactive GameState or
   * none at all, time will not pass for it.</p>
   * 
   * <p>A Thinker has <i>timers</i> that can perform Events after a certain number
   * of time units. Timers have integer values, with a positive value <i>x</i>
   * indicating that the Event will be performed in <i>x</i> time units, a
   * negative value indicating that the timer is not running, and a value of 0
   * indicating that either the Event was performed, or the value was deliberately
   * set to 0, this time unit. Each time unit, a Thinker decreases its
   * non-negative timers' values by 1 and performs the Events whose timers have
   * reached 0. Each frame, each Thinker experiences all of its time units
   * immediately before its assigned SubThinkers experience any of theirs.</p>
   * 
   * <p>A Thinker has frameActions() that it takes exactly once each frame, after
   * all Thinkers have experienced all of their time units for that frame. It also
   * has an EventGroup of <i>frame Events</i> that it performs once each frame
   * immediately after it takes its frameActions(). Both taking frameActions() and
   * performing frame Events count as time-dependent actions, and thus a Thinker
   * will only do them when assigned to an active GameState.</p>
   * 
   * <p>SubThinkers may be assigned to one Thinker each. Because a Thinker's
   * internal list of SubThinkers cannot be modified while it is being iterated
   * over, the actual addition or removal of a SubThinker to or from a Thinker is
   * delayed until any and all iterations over its SubThinkers, such as the
   * periods during which its SubThinkers perform their timer Events, have been
   * completed. Multiple delayed instructions may be successfully given to
   * Thinkers regarding the same SubThinker without having to wait until all
   * iterations have finished.</p>
   * @param <T> The type of CellGame that uses this Thinker's GameStates
   * @param <U> The type of GameState that uses this Thinker
   * @param <V> The type of SubThinker that can be assigned to this Thinker
   * @author Alex Heyman
   */
  public abstract class Thinker<T extends CellGame, U extends GameState<T,U,V>, V extends SubThinker<T,U,V>> {
      
      private final Class<T> gameClass;
      private final Class<U> stateClass;
      private final Class<V> subThinkerClass;
      private long timeFactor = -1;
      private long timeToRun = 0;
      private final Map<Event<T,U>,Integer> timers = new HashMap<>();
      private final EventGroup<T,U> frameEvents = new EventGroup<>();
      private final Set<V> subThinkers = new HashSet<>();
      private int subThinkerIterators = 0;
      private final Queue<SubThinkerChange<T,U,V>> subThinkerChanges = new LinkedList<>();
      private boolean updatingSubThinkers = false;
      
      final Event<T,U> frame = (game, state) -> {
          frameActions(game, state);
          if (frameEvents.size() > 0) {
              frameEvents.perform(state);
          }
      };
      
      /**
       * Constructs a Thinker.
       * @param gameClass The Class object representing the type of CellGame that
       * uses this Thinker's GameStates
       * @param stateClass The Class object representing the type of GameState
       * that uses this Thinker
       * @param subThinkerClass The Class object representing the type of
       * SubThinker that can be assigned to this Thinker
       */
      public Thinker(Class<T> gameClass, Class<U> stateClass, Class<V> subThinkerClass) {
          this.gameClass = gameClass;
          this.stateClass = stateClass;
          this.subThinkerClass = subThinkerClass;
      }
      
      /**
       * Returns the Class object representing the type of CellGame that uses this
       * Thinker's GameStates.
       * @return The Class object representing the type of CellGame that uses this
       * Thinker's GameStates
       */
      public final Class<T> getGameClass() {
          return gameClass;
      }
      
      /**
       * Returns the Class object representing the type of GameState that uses
       * this Thinker.
       * @return The Class object representing the type of GameState that uses
       * this Thinker
       */
      public final Class<U> getStateClass() {
          return stateClass;
      }
      
      /**
       * Returns the Class object representing the type of SubThinker that can be
       * assigned to this Thinker.
       * @return The Class object representing the type of SubThinker that can be
       * assigned to this Thinker
       */
      public final Class<V> getSubThinkerClass() {
          return subThinkerClass;
      }
      
      /**
       * Returns the CellGame of the GameState to which this Thinker is assigned,
       * or null if it is not assigned to a GameState.
       * @return This Thinker's GameState's CellGame
       */
      public abstract T getGame();
      
      /**
       * Returns the GameState to which this Thinker is assigned, or null if it is
       * not assigned to one.
       * @return The GameState to which this Thinker is assigned
       */
      public abstract U getGameState();
      
      /**
       * Returns this Thinker's time factor.
       * @return This Thinker's time factor
       */
      public final long getTimeFactor() {
          return timeFactor;
      }
      
      /**
       * Returns this Thinker's effective time factor; that is, the average number
       * of time units it experiences every frame. If it is not assigned to a
       * GameState, this will be 0.
       * @return This Thinker's effective time factor
       */
      public abstract long getEffectiveTimeFactor();
      
      /**
       * Sets this Thinker's time factor to the specified value.
       * @param timeFactor The new time factor
       */
      public final void setTimeFactor(long timeFactor) {
          this.timeFactor = timeFactor;
      }
      
      /**
       * Returns the current value of this Thinker's timer for the specified
       * Event.
       * @param event The Event whose timer value should be returned
       * @return The current value of the timer for the specified Event
       */
      public final int getTimerValue(Event<T,U> event) {
          return timers.getOrDefault(event, -1);
      }
      
      /**
       * Sets the value of this Thinker's timer for the specified Event to the
       * specified value.
       * @param event The Event whose timer value should be set
       * @param value The new value of the specified Event's timer
       */
      public final void setTimerValue(Event<T,U> event, int value) {
          if (value < 0) {
              timers.remove(event);
          } else {
              timers.put(event, value);
          }
      }
      
      final void update(T game, U state, long time) {
          if (timeFactor >= 0) {
              time = timeFactor;
          }
          timeToRun += time;
          while (timeToRun >= Frac.UNIT) {
              if (!timers.isEmpty()) {
                  List<Event<T,U>> eventsToPerform = new ArrayList<>();
                  Iterator<Map.Entry<Event<T,U>,Integer>> iterator = timers.entrySet().iterator();
                  while (iterator.hasNext()) {
                      Map.Entry<Event<T,U>,Integer> entry = iterator.next();
                      int value = entry.getValue();
                      if (value == 0) {
                          iterator.remove();
                      } else {
                          if (value == 1) {
                              eventsToPerform.add(entry.getKey());
                          }
                          entry.setValue(value - 1);
                      }
                  }
                  for (Event<T,U> event : eventsToPerform) {
                      event.actions(game, state);
                  }
              }
              timeToRun -= Frac.UNIT;
          }
          if (getNumSubThinkers() > 0) {
              Iterator<V> iterator = subThinkerIterator();
  