Dictionary <Move, Tuple <int, int> > atGoalWaitsToTimeAndAgentNum   = new Dictionary <Move, Tuple <int, int> >(); // No need for a list of agent nums because goals can't collide :)

        public void AddPlan(SinglePlan plan)
        {
            int planSize = plan.GetSize();

            for (int i = 0; i < planSize; i++)
            {
                Move      temp = plan.GetLocationAt(i);
                TimedMove step;
                if (temp.GetType() == typeof(TimedMove))
                {
                    step = (TimedMove)temp;
                }
                else
                {
                    step = new TimedMove(temp, i); // TODO: Avoid creating new objects when possible. Make the method return correctly timed moves.
                }
                if (this.timedMovesToAgentNumList.ContainsKey(step) == false)
                {
                    this.timedMovesToAgentNumList[step] = new List <int>(1); // THIS IS ON THE HOT PATH! ~11% of time is passed on this line!
                }
                this.timedMovesToAgentNumList[step].Add(plan.agentNum);
            }

            Move lastMove = plan.GetLocationAt(planSize - 1);
            Move goal     = new Move(lastMove.x, lastMove.y, Move.Direction.Wait);

            this.atGoalWaitsToTimeAndAgentNum.Add(goal, new Tuple <int, int>(planSize, plan.agentNum));
        }