示例#1
0
        /// <summary>
        /// If we are doing a bidirectional novelty search, flip the creature around and put it in the center of the world.
        /// </summary>
        private void beginSecondTrial()
        {
            numUpdates++;

            // Remove the creature from the old region lists
            // Update the region lists
            foreach (List <int> region in regions)
            {
                region.RemoveAt(indexOfCurrentCreature);
            }

            // If the creature has only completed one trial, we need to put it back in the creatureCenter of the world and flip it around.
            currentCreature.reset(initialHeading - (float)(Math.PI / 2.0));
            firstTrial = false;

            // Add the creature back into the appropriate region lists
            RotationPacket rp = currentCreature.getRotationPacket();

            regions[rp.NWCoord.Y / regionHeight, rp.NWCoord.X / regionWidth].Add(indexOfCurrentCreature);
            if ((rp.NWCoord.X % regionWidth > rp.SECoord.X % regionWidth) && (rp.NWCoord.Y % regionHeight > rp.SECoord.Y % regionHeight))
            {
                regions[rp.SECoord.Y / regionHeight, rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
            if (rp.NWCoord.X % regionWidth > rp.SECoord.X % regionWidth)
            {
                regions[(rp.NWCoord.Y / regionHeight), rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
            if (rp.NWCoord.Y % regionHeight > rp.SECoord.Y % regionHeight)
            {
                regions[rp.SECoord.Y / regionHeight, rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
        }
    public void SendRotation(Quaternion rotation, uint objectId)
    {
        RotationPacket packet = new RotationPacket();

        packet.payload = rotation;

        PacketManager.Instance.SendPacket(packet, objectId, false);
    }
示例#3
0
 /// <summary>
 /// Performs updates to the game engine based on the agent's intended actions.
 /// </summary>
 /// <param name="time">GameTime component from the main game engine.</param>
 public override void Update(GameTime gameTime)
 {
     if (!Simulator.paused)
     {
         packetBeforeMoving = getRotationPacket();
         UpdateMovement();
         packetAfterMoving = UpdatePosition(gameTime);
         checkregions();
         Sensor.Update(this, packetAfterMoving);
     }
 }
示例#4
0
        /// <summary>
        /// Calculate the max possible texture size (bounding box size will change based on angle of rotation).
        /// </summary>
        protected void getMaxBoundingBoxSize()
        {
            float minX = Position.X;
            float minY = Position.Y;

            // Rotate the texture at every possible angle to find the max necessary dimensions
            for (float theta = (float)-Math.PI; theta < Math.PI; theta += (1.0f / 360.0f))
            {
                rp = getRotationPacketAtAngle(theta);
                if (rp.NWCoord.X < minX)
                    minX = rp.NWCoord.X;
                if (rp.NWCoord.Y < minY)
                    minY = rp.NWCoord.Y;
            }

            // Calculate the distance from the creature's center to its border (used for calculating sensor placement and dimensions)
            creatureCenter = new Vector2(Position.X + (Texture.Width / 2), Position.Y + (Texture.Height / 2));
            distCenterToBorder = (float)Math.Max(Math.Ceiling(creatureCenter.X - minX), Math.Ceiling(creatureCenter.Y - minY)) + 1.0f;
        }
示例#5
0
        /// <summary>
        /// This method is called when one individual finishes its run in the world (either because it planted itself
        /// or because it timed out). It should ONLY be called when the creature is being controlled by a neural network (novelty search or evolution).
        /// </summary>
        ///
        private void ResetToFirstTrial()
        {
            // Reset numUpdates
            numUpdates = 0;

            // Remove the creature from the old region lists
            // Update the region lists
            foreach (List <int> region in regions)
            {
                region.RemoveAt(indexOfCurrentCreature);
            }

            // If the creature has already completed both trials, we need to _actually_ reset the simulator.
            #region Planter XML writing
            if (GenomeIndexOfCurrentCreature != -1)
            {
                // First, check to see if the individual was a valid planter
                if (freezeAfterPlanting)
                {
                    // Success on both trials
                    if (plantedInColoredSpace1 && plantedInColoredSpace2)
                    {
                        numBidirectionalPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_BidirectionalPlanterGenome" + numBidirectionalPlanters.ToString() + ".xml");
                    }

                    // Success on the first trial
                    else if (plantedInColoredSpace1)
                    {
                        numFirstTrialPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_FirstTrialPlanterGenome" + numFirstTrialPlanters.ToString() + ".xml");
                    }

                    // Sucess on the second trial
                    else if (plantedInColoredSpace2)
                    {
                        numSecondTrialPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_SecondTrialPlanterGenome" + numSecondTrialPlanters.ToString() + ".xml");
                    }
                }

                else
                {
                    // Success on both trials, no misplanting
                    if (plantedInColoredSpace1 && plantedInColoredSpace2 && !plantedInWhiteSpace1 && !plantedInWhiteSpace2)
                    {
                        numBidirectionalPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_BidirectionalPlanterGenome" + numBidirectionalPlanters.ToString() + ".xml");
                    }

                    // Planted only in white
                    // Success on the first trial, no misplanting
                    else if (!plantedInColoredSpace1 && plantedInWhiteSpace1)
                    {
                        numFirstTrialPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_FirstTrialPlanterGenome_White" + numFirstTrialPlanters.ToString() + ".xml");
                    }

                    // Success on the first trial, no misplanting
                    else if (plantedInColoredSpace1 && !plantedInWhiteSpace1)
                    {
                        numFirstTrialPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_FirstTrialPlanterGenome" + numFirstTrialPlanters.ToString() + ".xml");
                    }

                    // Sucess on the second trial, no misplanting
                    else if (plantedInColoredSpace2 && !plantedInWhiteSpace2)
                    {
                        numSecondTrialPlanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_SecondTrialPlanterGenome" + numSecondTrialPlanters.ToString() + ".xml");
                    }

                    // Success on both trials, but with misplanting
                    if ((plantedInColoredSpace1 && plantedInWhiteSpace1) || (plantedInColoredSpace2 && plantedInWhiteSpace2))
                    {
                        numBidirectionalMisplanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_BidirectionalPlanterGenome_Misplanted" + numBidirectionalMisplanters.ToString() + ".xml");
                    }

                    // Success on the first trial, but with misplanting
                    else if (plantedInColoredSpace1 && plantedInWhiteSpace1)
                    {
                        numFirstTrialMisplanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_FirstTrialPlanterGenome_Misplanted" + numFirstTrialMisplanters.ToString() + ".xml");
                    }

                    // Sucess on the second trial, but with misplanting
                    else if (plantedInColoredSpace2 && plantedInWhiteSpace2)
                    {
                        numSecondTrialMisplanters++;
                        XmlDocument    results     = new XmlDocument();
                        XmlDeclaration declaration = results.CreateXmlDeclaration("1.0", null, null);
                        results.AppendChild(declaration);
                        XmlGenomeWriterStatic.Write(results, (NeatGenome)ea.Population.GenomeList[GenomeIndexOfCurrentCreature]);
                        results.Save(plantersFolder + "NoveltySearch_SecondTrialPlanterGenome_Misplanted" + numSecondTrialMisplanters.ToString() + ".xml");
                    }
                }
            }
            #endregion

            // Remove the individual from the global image list
            Components.Remove(currentCreature);

            // Reset the success flags
            plantedInColoredSpace1 = false;
            plantedInWhiteSpace1   = false;
            plantedInColoredSpace2 = false;
            plantedInWhiteSpace2   = false;

            // Also reset the trial flag
            firstTrial = true;

            // Get the next creature for this generation, decode its CPPN, and replace the creature's controller
            GenomeIndexOfCurrentCreature++;

            // Update the folders for storing the archive and planters if necessary
            if (GenomeIndexOfCurrentCreature % numCreaturesPerFolder == 0)
            {
                int newFolderNumber = GenomeIndexOfCurrentCreature / numCreaturesPerFolder;
                noveltyLogsFolder = Directory.GetCurrentDirectory() + "\\archive\\" + newFolderNumber + "\\";
                if (!Directory.Exists(noveltyLogsFolder))
                {
                    Directory.CreateDirectory(noveltyLogsFolder);
                }
                plantersFolder = Directory.GetCurrentDirectory() + "\\planters\\" + newFolderNumber + "\\";
                if (!Directory.Exists(plantersFolder))
                {
                    Directory.CreateDirectory(plantersFolder);
                }
            }

            // Initialize the genome's behavior characterization structure if this genome has not previously been evaluated
            if (ea.Population.GenomeList[GenomeIndexOfCurrentCreature].Behavior == null)
            {
                ea.Population.GenomeList[GenomeIndexOfCurrentCreature].Behavior = new BehaviorType();
                ea.Population.GenomeList[GenomeIndexOfCurrentCreature].Behavior.behaviorList = new List <double>();
            }
            INetwork newController = controllerSubstrate.generateGenome(ea.Population.GenomeList[GenomeIndexOfCurrentCreature].Decode(ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"))).Decode(ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"));
            if (bidirectionalTrials)
            {
                currentCreature = new NNControlledCreature(morphology, initialBoardWidth / 2, initialBoardHeight / 2, initialHeading + (float)(Math.PI / 2.0), newController, this, drawSensorField, trackPlanting, defaultNumSensors, freezeAfterPlanting);
            }
            else
            {
                currentCreature = new NNControlledCreature(morphology, initialBoardWidth / 2, initialBoardHeight / 2, initialHeading, newController, this, drawSensorField, trackPlanting, defaultNumSensors, freezeAfterPlanting);
            }

            // Add the creature back into the appropriate region lists
            RotationPacket rp = currentCreature.getRotationPacket();
            regions[rp.NWCoord.Y / regionHeight, rp.NWCoord.X / regionWidth].Add(indexOfCurrentCreature);
            if ((rp.NWCoord.X % regionWidth > rp.SECoord.X % regionWidth) && (rp.NWCoord.Y % regionHeight > rp.SECoord.Y % regionHeight))
            {
                regions[rp.SECoord.Y / regionHeight, rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
            if (rp.NWCoord.X % regionWidth > rp.SECoord.X % regionWidth)
            {
                regions[(rp.NWCoord.Y / regionHeight), rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
            if (rp.NWCoord.Y % regionHeight > rp.SECoord.Y % regionHeight)
            {
                regions[rp.SECoord.Y / regionHeight, rp.SECoord.X / regionWidth].Add(indexOfCurrentCreature);
            }
        }
示例#6
0
        /// <summary>
        /// During each call to Sense(), this function is called to update the list of images that intersect the sensor field.
        /// p1 is the NW sensor field corner, and p2 is the SE sensor field corner.
        /// </summary>
        private List <Image> updateIntersectingImages(Image creature, RotationPacket creaturePacket)
        {
            // Figure out which regions the sensor field could intersect
            List <int> indicesOfPossibleNeighbors = new List <int>();

            indicesOfPossibleNeighbors.AddRange(Simulator.regions[creaturePacket.NWCoord.Y / Simulator.regionHeight, creaturePacket.NWCoord.X / Simulator.regionWidth]);
            indicesOfPossibleNeighbors.AddRange(Simulator.regions[creaturePacket.NWCoord.Y / Simulator.regionHeight, creaturePacket.SECoord.X / Simulator.regionWidth]);
            indicesOfPossibleNeighbors.AddRange(Simulator.regions[creaturePacket.SECoord.Y / Simulator.regionHeight, creaturePacket.NWCoord.X / Simulator.regionWidth]);
            indicesOfPossibleNeighbors.AddRange(Simulator.regions[creaturePacket.SECoord.Y / Simulator.regionHeight, creaturePacket.SECoord.X / Simulator.regionWidth]);

            // Grab the images corresponding to the indices for the possible neighbors
            float imageDepth;
            Image candidateImage;
            SortedDictionary <float, Image> neighboringRegions = new SortedDictionary <float, Image>();

            foreach (int index in indicesOfPossibleNeighbors)
            {
                candidateImage = (Image)creature.Game.Components[index];
                imageDepth     = candidateImage.Depth;
                if (!neighboringRegions.ContainsKey(imageDepth) && candidateImage != creature && imageDepth > creature.Depth)
                {
                    neighboringRegions.Add(imageDepth, candidateImage);
                }
            }


            // Go through those regions and find the images that intersect the sensor field
            // (Also, we only want images that are underneath the sensor field)
            int x1, x2, y1, y2;
            SortedDictionary <float, Image> intersectingImages = new SortedDictionary <float, Image>();

            foreach (RotateableImage image in neighboringRegions.Values.OfType <RotateableImage>())
            {
                RotationPacket imagePacket        = image.getRotationPacket();
                int            halfChangeInWidth  = (imagePacket.NewWidth - image.Texture.Width) / 2;
                int            halfChangeInHeight = (imagePacket.NewHeight - image.Texture.Height) / 2;

                // (x1, y1) is the NE corner of the intersection space
                x1 = Math.Max(creaturePacket.NWCoord.X, imagePacket.NWCoord.X);
                y1 = Math.Max(creaturePacket.NWCoord.Y, imagePacket.NWCoord.Y);

                // (x2, y2) is the SW corner of the intersection space
                x2 = Math.Min(creaturePacket.SECoord.X, imagePacket.SECoord.X);
                y2 = Math.Min(creaturePacket.SECoord.Y, imagePacket.SECoord.X);

                // If there is a nonzero intersection space and the image under consideration isn't already in the image list,
                // add it to the image list.
                if (x1 < x2 && y1 < y2)
                {
                    intersectingImages.Add(image.Depth, image);
                }
            }

            // Take care of the non-mobile images (basically just region backgroudnds)
            foreach (Image image in neighboringRegions.Values.OfType <StaticImage>())
            {
                // (x1, y1) is the NE corner of the intersection space
                x1 = Math.Max(creaturePacket.NWCoord.X, Convert.ToInt32(Math.Floor(image.Position.X)));
                y1 = Math.Max(creaturePacket.NWCoord.Y, Convert.ToInt32(Math.Floor(image.Position.Y)));

                // (x2, y2) is the SW corner of the intersection space
                x2 = Math.Min(creaturePacket.SECoord.X, Convert.ToInt32(Math.Floor(image.Position.X)) + image.Texture.Width);
                y2 = Math.Min(creaturePacket.SECoord.Y, Convert.ToInt32(Math.Floor(image.Position.Y)) + image.Texture.Height);

                // If there is a nonzero intersection space and the image under consideration isn't already in the image list,
                // add it to the image list.
                if (x1 < x2 && y1 < y2)
                {
                    intersectingImages.Add(image.Depth, image);
                }
            }

            // Convert the dictionary to a list and return it
            return(intersectingImages.Values.ToList());
        }
示例#7
0
        /// <summary>
        /// Returns the color contents of the area defined by the sensor field. This output will feed into the neural controller inputs.
        /// The neural controller has 3 input layers, which are arranged on the same horizontal level. The current version of this function
        /// assumes the sensor field is a square so that the sensor data can meaningfully be stored in a 2D array. A better version of this
        /// function will be made later so that sensor fields with different shapes are supported.
        /// </summary>
        /// <param name="creaturePosition">The absolute position of the creature in the world, measured from the upper left corner.</param>
        public void Update(Creature creature, RotationPacket creaturePacket)
        {
            // (These two variables don't factor into the actual sensing, but they are necessary if we want to visualize the sensor contents.)
            Color[] sensorContentsPixels = new Color[Simulator.FieldTexture.Width * Simulator.FieldTexture.Height];
            for (int row = 0; row < Simulator.FieldTexture.Height; row++)
            {
                for (int col = 0; col < Simulator.FieldTexture.Width; col++)
                {
                    sensorContentsPixels[col + (row * Simulator.FieldTexture.Width)] = Color.Transparent;
                }
            }

            // Reset the sensors
            resetArrays();

            // Find the new bounding box coordinates using the new creatureCenter
            List <Image> intersectingImages;

            if (Simulator.blindCreatures)
            {
                intersectingImages = new List <Image>();
                intersectingImages.Add(Simulator.initialBackground);
            }
            else if (Simulator.everyoneCanPlant)
            {
                intersectingImages = new List <Image>();
                intersectingImages.Add(Simulator.backgroundImage);
            }
            else
            {
                intersectingImages = updateIntersectingImages(creature, creaturePacket);
            }

            // Grab the rotation packets for each of the images in intersectingImages
            List <RotationPacket> rotationPackets = new List <RotationPacket>();

            for (int i = 0; i < intersectingImages.Count; i++)
            {
                rotationPackets.Add(intersectingImages[i].getRotationPacketWithoutSensors(true));
            }


            // Find the global coordinates of the creature's position and the sensor field's NW coordinate,
            // along with the local coordinates of the creature's center
            Point   creaturePosition = VectorHelpers.asXNAPoint(creature.Position);
            Point   sensorNWCoord    = new Point(creaturePosition.X + creature.SensorFieldAnchorPoint.X - (SegmentLength * ResolutionX) / 2, creaturePosition.Y + creature.SensorFieldAnchorPoint.Y - (SegmentLength * ResolutionY) / 2);
            Vector2 creatureCenter   = new Vector2(creature.Texture.Width / 2, creature.Texture.Height / 2);

            // Iterate through the sensor field texel positions and query for non-transparent pixels underneath the field
            Color worldTexel;
            int   indexIntoArray;

            for (int x = 0; x < SegmentLength; x++)
            {
                for (int y = 0; y < SegmentLength; y++)
                {
                    // Get the global position that corresponds to the internal (x,y) coordinates
                    Point globalSensorCoord = MathHelpers.rotateAroundPoint(sensorNWCoord.X + SensorArray[x, y].X, sensorNWCoord.Y + SensorArray[x, y].Y, Convert.ToInt32(creature.Position.X + creatureCenter.X), Convert.ToInt32(creature.Position.Y + creatureCenter.Y), creature.XNAHeading);

                    // Loop through each image, starting with the one that's closest to (yet still underneath) the sensor field
                    for (int i = 0; i < intersectingImages.Count; i++)
                    {
                        // Check to make sure the image actually has a pixel located at the (global) x,y we're checking
                        Point imageNW = rotationPackets[i].NWCoord;
                        Point imageSE = rotationPackets[i].SECoord;
                        if (globalSensorCoord.X >= imageNW.X && globalSensorCoord.X < imageSE.X && globalSensorCoord.Y >= imageNW.Y && globalSensorCoord.Y < imageSE.Y)
                        {
                            indexIntoArray = (globalSensorCoord.X - imageNW.X + ((globalSensorCoord.Y - imageNW.Y) * rotationPackets[i].NewWidth));
                            worldTexel     = rotationPackets[i].RotatedPixels[indexIntoArray];
                            if (worldTexel.A != 0)
                            {
                                // If we get here, the sensor field is working as it should!
                                sensedSomething = true;

                                // Store the sensed RGB values in an ANN-friendly format
                                R[x, y] = MathHelpers.Scale(worldTexel.R, 0, 255, -1, 1);
                                G[x, y] = MathHelpers.Scale(worldTexel.G, 0, 255, -1, 1);
                                B[x, y] = MathHelpers.Scale(worldTexel.B, 0, 255, -1, 1);

                                // If we're visualizing the sensor field contents, we need to update the texture-to-be-drawn also
                                if (Simulator.drawSensorField && (!Simulator.depthTest || creature.ID == Simulator.manuallyControlledCreatureID))
                                {
                                    sensorContentsPixels[x + ((y * ResolutionX) * SegmentLength)] = worldTexel;
                                }

                                // Then stop looping through the images and move on to the next texel location
                                break;
                            }
                        }
                    }
                }
            }

            // If we want to visualize the sensor field, we have to do it before we dispose of the temporary texture
            if (Simulator.drawSensorField)
            {
                Simulator.sensorContentsTexture.SetData(sensorContentsPixels);
            }

            // Raise an exception if the sensors are broken
            if (!sensedSomething)
            {
                throw new Exception("Problem: Sensor.Sense() looped through the pixels in rotatedSensorField without finding any pixels with a nonzero alpha value.");
            }

            // Reset the exception flag
            sensedSomething = false;
        }