public int numBrains; // Schrum: Total number

        public AgentBrain(bool homogenous, int numAgents, SubstrateDescription substrateDescription, INetwork genome,
            bool normalizeANNWeights, bool adaptableANN, bool modulatoryANN, bool multi, int brains, bool evolveSubstrate, bool preferenceNeurons, bool forcedSituationalPolicyGeometry)
        {
            this.evolveSubstrate = evolveSubstrate;
            this.normalizeANNWeights = normalizeANNWeights;
            this.adaptableANN = adaptableANN;
            this.modulatoryANN = modulatoryANN;
            this.genome = genome;
            this.substrateDescription = substrateDescription;
            this.numRobots = numAgents;
            this.homogenous = homogenous;
            this.multipleBrains = multi;
            this.forcedSituationalPolicyGeometry = forcedSituationalPolicyGeometry;
            // Schrum: When preference neurons are used, the number of modules in the network is the
            // more reliable source of information. Especially if Module Mutation will allow more modules
            // to be created, each creating a new brain.
            this.numBrains = genome != null && preferenceNeurons ? genome.NumOutputModules : brains;
            this.preferenceNeurons = preferenceNeurons;

            //inputCounter = 0;
            teamInput = new float[numAgents * substrateDescription.InputCount];
            activated = new bool[numAgents];

            createBrains();

            robotListeners = new List<Robot>();
        }
        /// <summary>
        /// Constructs a new AgentBrain object from the specified parameters. This brain is designed to be used as a multiagent hivemind, but can also be used to control a single agent by setting numAgents equal to 1. 
        /// </summary>
        /// <param name="homogeneous">Is the team homogeneous? Agents in a homogeneous team all have identical copies of the same brain, while those in a heterogeneous team do not, instead each contributing to one central, distributed hive brain.</param>
        /// <param name="numAgents">Set to 1 for an individual agent, or >1 for a multiagent team.</param>
        /// <param name="substrateDescription">HyperNEAT substrate</param>
        /// <param name="genome">If using NEAT, this should be the already-decoded neural network. Otherwise, if using HyperNEAT, this should be the CPPN that encodes the neural network.</param>
        /// <param name="normalizeANNWeights"></param>
        /// <param name="adaptableANN"></param>
        /// <param name="modulatoryANN"></param>
        /// <param name="multi">Multiple brains with situational policies?</param>
        /// <param name="evolveSubstrate">Set to true to enable ES-HyperNEAT.</param>
        /// <param name="useNeatBrain">If false, the system will use HyperNEAT as the EA.</param>
        /// <param name="useCTRNNs">Set to true to use continuous time recurrent neural networks.</param>
        public AgentBrain(bool homogeneous, int numAgents, SubstrateDescription substrateDescription, INetwork genome,
            bool normalizeANNWeights, bool adaptableANN, bool modulatoryANN, bool multi, bool evolveSubstrate, bool useNeatBrain, bool useCTRNNs = false)
        {
            // Set instance variables
            EvolveSubstrate = evolveSubstrate;
            NormalizeANNWeights = normalizeANNWeights;
            AdaptableANN = adaptableANN;
            ModulatoryANN = modulatoryANN;
            Genome = genome;
            SubstrateDescription = substrateDescription;
            NumRobots = numAgents;
            Homogeneous = homogeneous;
            MultipleBrains = multi;
            NeatBrain = useNeatBrain;
            UseCTRNNs = useCTRNNs;

            // Initialiaze team arrays
            TeamInput = new float[numAgents * substrateDescription.InputCount];
            TeamInputOld = new float[numAgents * substrateDescription.InputCount];
            TeamOutput = new float[numAgents * substrateDescription.OutputCount];
            TeamOutputOld = new float[numAgents * substrateDescription.OutputCount];
            TeamHidden = new float[numAgents * 5];
            TeamHiddenOld = new float[numAgents * 5];
			RobotInput = new float[substrateDescription.InputCount];
			RobotInputOld = new float[substrateDescription.InputCount];
            Activated = new bool[numAgents];

            // Initialize the agents' brains
            createBrains();
            
            // Register listeners for the robots' neural network outputs
            RobotListeners = new List<Robot>();

            if (OutputComms)
            {
                // If the robots' input and output streams have already been initialized, reset them
                if (OutputsInitialized)
                {
                    for (int j = 0; j < numAgents; j++)
                    {
                        OutStreams[j].Close();
                        InStreams[j].Close();
                        OutStreams[j] = null;
                        InStreams[j] = null;
                    }
                }

                // Initialize the robots' input and output streams
                OutStreams = new List<StreamWriter>(numAgents);
                InStreams = new List<StreamWriter>(numAgents);
                for (int j = 0; j < numAgents; j++)
                {
                    OutStreams.Add(new StreamWriter("agentO" + j + ".txt"));
                    InStreams.Add(new StreamWriter("agentI" + j + ".txt"));
                }
                OutputsInitialized = true;
            }
        }
        public AgentBrain(bool homogenous, int numAgents, SubstrateDescription substrateDescription, INetwork genome,
            bool normalizeANNWeights, bool adaptableANN, bool modulatoryANN, bool multi, bool evolveSubstrate, bool dirComm)
        {
            this.evolveSubstrate = evolveSubstrate;
            this.normalizeANNWeights = normalizeANNWeights;
            this.adaptableANN = adaptableANN;
            this.modulatoryANN = modulatoryANN;
            this.genome = genome;
            this.substrateDescription = substrateDescription;
            this.numRobots = numAgents;
            this.homogenous = homogenous;
            this.multipleBrains = multi;
            this.dirComm = dirComm;

            //inputCounter = 0;
            teamInput = new float[numAgents * substrateDescription.InputCount];
            activated = new bool[numAgents];

            createBrains();

            robotListeners = new List<Robot>();
        }
        protected void setupVariables()
        {
            robots = new List<Robot>();
            substrateDescription = new SubstrateDescription(substrateDescriptionFilename);

            agentBrain = new AgentBrain(homogeneousTeam, numberRobots, substrateDescription, genome != null ? genome.Decode(null) : null, normalizeWeights, adaptableANN, modulatoryANN, multibrain, evolveSubstrate, dirComm);

            //if(homogeneousTeam)
            //Console.WriteLine("inc:"+agentBrain.getBrain(0).InputNeuronCount);

            loadEnvironments(this);

            //agentsCollide=environment.agentsCollide;
            //agentsVisible=environment.agentsVisible;

            //Substrate sensor density
            initializeRobots(agentBrain, environment, headingNoise, sensorNoise, effectorNoise, null);

            setFitnessFunction(fitnessFunctionName);
            setBehavioralCharacterization(behaviorCharacterizationName);

            if (gridCollision)
                collisionManager = new GridCollision();
            else
                collisionManager = new StandardCollision();
            collisionManager.Initialize(environment, this, this.robots);
            timeSteps = 0;
            elapsed = 0;

            if (initialized)
                foreach (Prey p in environment.preys)
                {
                    p.reset();
                }
            preyCaught = 0;
        }
        /// <summary>
        /// Performs the actual initialization logic. 
        /// </summary>
        protected void setupVariables()
        {
            substrateDescription = new SubstrateDescription(substrateDescriptionFilename);
            agentBrain = new AgentBrain(homogeneousTeam, numberRobots, substrateDescription, genome != null ? genome.Decode(null) : null, normalizeWeights, adaptableANN, modulatoryANN, multibrain, evolveSubstrate, neatBrain, useCTRNNS);

            loadEnvironments(this);

            initializeRobots(agentBrain, environment, headingNoise, sensorNoise, effectorNoise, null);

            setFitnessFunction(fitnessFunctionName);
            setBehavioralCharacterization(behaviorCharacterizationName);

            collisionManager = new StandardCollision();

            collisionManager.initialize(environment, this, this.robots);
            timeSteps = 0;
            elapsedTime = 0;
        }