/// <summary> /// Generates the specified number of maze genomes with the specified complexity (i.e. number of interior partitions). /// </summary> /// <param name="numMazeGenomes">The number of maze genomes to generate.</param> /// <param name="numPartitions">The number of initial partitions (the starting complexity of the genome).</param> /// <param name="mazeGenomeFactory">Reference to the maze genome factory.</param> /// <returns></returns> public static List <MazeGenome> GenerateMazeGenomes(int numMazeGenomes, int numPartitions, MazeGenomeFactory mazeGenomeFactory) { var mazeGenomes = new List <MazeGenome>(numMazeGenomes); var rand = RandomDefaults.CreateRandomSource(); for (var curMazeCnt = 0; curMazeCnt < numMazeGenomes; curMazeCnt++) { // Reset innovation IDs mazeGenomeFactory.InnovationIdGenerator.Reset(); // Create a new genome and pass in the requisite factory var mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0); // Create the specified number of interior partitions (i.e. maze genes) for (var cnt = 0; cnt < numPartitions; cnt++) { // Create new maze gene and add to genome mazeGenome.WallGeneList.Add(new WallGene(mazeGenomeFactory.InnovationIdGenerator.NextId, rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5)); } mazeGenomes.Add(mazeGenome); } return(mazeGenomes); }
/// <summary> /// Serializes a maze genome into a string. /// </summary> /// <param name="mazeGenome">The maze genome object to serialize.</param> /// <returns>The serialized maze genome string.</returns> public static string GetGenomeXml(MazeGenome mazeGenome) { // Create a new string writer into which to write the genome XML StringWriter genomeStringWriter = new StringWriter(); // Serialize the genome to XML, but write it into a string writer instead of outputting to a file if (mazeGenome != null) { using (XmlTextWriter genomeTextWriter = new XmlTextWriter(genomeStringWriter)) { WriteComplete(genomeTextWriter, mazeGenome); } } // Convert to a string representation and return return genomeStringWriter.ToString(); }
/// <summary> /// Converts the maze genome into a maze structure and prints it to a bitmap file. /// </summary> /// <param name="mazeGenome">The maze genome to convert and print.</param> /// <param name="mazeImageName">The name of the maze output file.</param> private static void PrintMazeToFile(MazeGenome mazeGenome, string mazeImageName) { // Read in the maze decode parameters int mazeScaleFactor = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeScaleFactor]); string mazeBitmapOutputDirectory = _executionConfiguration[ExecutionParameter.BitmapOutputBaseDirectory]; // Instantiate the maze genome decoder MazeDecoder mazeDecoder = new MazeDecoder(mazeScaleFactor); // Decode the maze to get a maze structure MazeStructure mazeStructure = mazeDecoder.Decode(mazeGenome); // Create pen and initialize bitmap canvas Pen blackPen = new Pen(Color.Black, 0.0001f); Bitmap mazeBitmap = new Bitmap(mazeStructure.ScaledMazeWidth + 1, mazeStructure.ScaledMazeHeight + 1); using (Graphics graphics = Graphics.FromImage(mazeBitmap)) { // Fill with white Rectangle imageSize = new Rectangle(0, 0, mazeStructure.ScaledMazeWidth + 1, mazeStructure.ScaledMazeHeight + 1); graphics.FillRectangle(Brushes.White, imageSize); // Draw start and end points graphics.FillEllipse(Brushes.Green, mazeStructure.StartLocation.X, mazeStructure.StartLocation.Y, 5, 5); graphics.FillEllipse(Brushes.Red, mazeStructure.TargetLocation.X, mazeStructure.TargetLocation.Y, 5, 5); // Draw all of the walls foreach (MazeStructureWall wall in mazeStructure.Walls) { // Convert line start/end points to Point objects from drawing namespace Point startPoint = new Point(wall.StartMazeStructurePoint.X, wall.StartMazeStructurePoint.Y); Point endPoint = new Point(wall.EndMazeStructurePoint.X, wall.EndMazeStructurePoint.Y); // Draw wall graphics.DrawLine(blackPen, startPoint, endPoint); } } // Save the bitmap image mazeBitmap.Save(Path.Combine(mazeBitmapOutputDirectory, mazeImageName)); }
public void MutatedGenomeDecodeTest() { int scaleMultiplier = 16; // Mock up maze genome (just use null genome factory) MazeGenome mazeGenome = new MazeGenome(new MazeGenomeFactory(), 1, 1); MazeDecoder mazeDecoder = new MazeDecoder(20, 20, scaleMultiplier); MazeStructure mazeGrid = mazeDecoder.Decode(mazeGenome); DisplayMaze(mazeGrid.MazeArray); mazeGrid.ConvertGridArrayToWalls(mazeGrid.MazeArray); uint birthGeneration = 1; do { // Generate an offspring (perform mutation) mazeGenome.CreateOffspring(++birthGeneration); if (birthGeneration%100 == 0) { mazeGrid = mazeDecoder.Decode(mazeGenome); PrintBitmapMaze(mazeGrid.Walls, 20*scaleMultiplier, 20*scaleMultiplier, (int) birthGeneration); } } while (birthGeneration < 1000000); // Create the maze decoder mazeDecoder = new MazeDecoder(20, 20, scaleMultiplier); mazeGrid = mazeDecoder.Decode(mazeGenome); DisplayMaze(mazeGrid.MazeArray); mazeGrid.ConvertGridArrayToWalls(mazeGrid.MazeArray); //PrintBitmapMaze(mazeGrid.Walls, 20 * scaleMultiplier, 20 * scaleMultiplier); }
public void HardCodedGenomeDecodeTest() { // Mock up maze genome (just use null genome factory) MazeGenome mazeGenome = new MazeGenome((MazeGenomeFactory) null, 1, 1); // Add some genes mazeGenome.GeneList.Add(new MazeGene(1, 0.6, 0.3, false)); mazeGenome.GeneList.Add(new MazeGene(2, 0.7, 0.4, false)); mazeGenome.GeneList.Add(new MazeGene(3, 0.3, 0.8, true)); mazeGenome.GeneList.Add(new MazeGene(4, 0.9, 0.2, false)); mazeGenome.GeneList.Add(new MazeGene(5, 0.5, 0.3, false)); mazeGenome.GeneList.Add(new MazeGene(6, 0.2, 0.5, false)); mazeGenome.GeneList.Add(new MazeGene(7, 0.4, 0.1, true)); mazeGenome.GeneList.Add(new MazeGene(8, 0.7, 0.8, true)); mazeGenome.GeneList.Add(new MazeGene(9, 0.3, 0.2, false)); // Create the maze decoder MazeDecoder mazeDecoder = new MazeDecoder(20, 20); MazeStructure mazeGrid = mazeDecoder.Decode(mazeGenome); //DisplayMaze(mazeGrid.MazeArray); }
/// <summary> /// Handles the process of rendering a bitmap file of an existing maze genome. /// </summary> private static void HandleMazeImageReproduction() { MazeGenome mazeGenome = null; // Get the maze genome file path and image output path string mazeGenomeFile = _executionConfiguration[ExecutionParameter.MazeGenomeFile]; string imageOutputPath = _executionConfiguration[ExecutionParameter.BitmapOutputBaseDirectory]; // Create a new (mostly dummy) maze genome factory MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory(); // Read in the genome using (XmlReader xr = XmlReader.Create(mazeGenomeFile)) { mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xr, mazeGenomeFactory); } // Get the maze genome ID uint mazeGenomeId = mazeGenome.Id; // Render the maze phenotype (i.e. the graphical structure0 and print to a bitmap file PrintMazeToFile(mazeGenome, Path.Combine(imageOutputPath, string.Format("EvolvedMaze_ID_{0}.bmp", mazeGenomeId))); }
/// <summary> /// Handles the process of generating maze genomes and rendering bitmap files of their structure. /// </summary> private static void HandleMazeGeneration() { IRandomSource rand = RandomDefaults.CreateRandomSource(); // Get the evolved maze height and width int mazeHeight = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeHeight]); int mazeWidth = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeWidth]); int mazeQuadrantHeight = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeQuadrantHeight]); int mazeQuadrantWidth = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeQuadrantWidth]); // Get the number of interior walls and maze genome output directory int numWaypoints = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWaypoints]); int numInteriorWalls = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWalls]); string mazeGenomeOutputDirectory = _executionConfiguration[ExecutionParameter.MazeGenomeOutputBaseDirectory]; // Get the number of sample mazes to generate (or just 1 maze if not specified) int numMazes = _executionConfiguration.ContainsKey(ExecutionParameter.NumMazes) ? Int32.Parse(_executionConfiguration[ExecutionParameter.NumMazes]) : 1; // Get whether images are being generated for the sample mazes bool generateMazeImages = _executionConfiguration.ContainsKey(ExecutionParameter.OutputMazeBitmap) && Boolean.Parse(_executionConfiguration[ExecutionParameter.OutputMazeBitmap]); // Get whether maze genomes are being serialized to the same file (defaults to false) bool isSingleOutputFile = _executionConfiguration.ContainsKey(ExecutionParameter.SingleGenomeOutputFile) && Boolean.Parse(_executionConfiguration[ExecutionParameter.SingleGenomeOutputFile]); // Create a new maze genome factory MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory(mazeHeight, mazeWidth, mazeQuadrantHeight, mazeQuadrantWidth); // Instantiate list to hold generated maze genomes // (only really used when we're writing everything out to one file) List <MazeGenome> mazeGenomeList = new List <MazeGenome>(numMazes); for (int curMazeCnt = 0; curMazeCnt < numMazes; curMazeCnt++) { MazeGenome mazeGenome; // Lay out the base file name string fileBaseName = string.Format("GeneratedMazeGenome_{0}_Height_{1}_Width_{2}_Waypoints_{3}_Walls_{4}", mazeHeight, mazeWidth, numWaypoints, numInteriorWalls, curMazeCnt); // With a single output file, the genomes are likely being used for separate experiments, so we // reset the innovation IDs and assign the maze a constant identifier if (isSingleOutputFile == false) { // Reset innovation IDs mazeGenomeFactory.InnovationIdGenerator.Reset(); // Create a new genome and pass in the requisite factory mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0); } // Otherwise, we leave the innovation ID generator alone and create a new maze genome with // an identifier that's incremented by one else { mazeGenome = new MazeGenome(mazeGenomeFactory, (uint)curMazeCnt, 0); } // Add the specified number of waypoints (less one because center waypoint is created on maze initialization) for (int cnt = 0; cnt < numWaypoints - 1; cnt++) { Point2DInt waypoint; // Randomly select an orientation IntersectionOrientation newPointOrientation = mazeGenomeFactory.Rng.NextBool() ? IntersectionOrientation.Horizontal : IntersectionOrientation.Vertical; // Iterate until we get a waypoint that's valid do { waypoint = new Point2DInt(mazeGenomeFactory.Rng.Next(mazeGenome.MazeBoundaryWidth - 1), mazeGenomeFactory.Rng.Next(mazeGenome.MazeBoundaryHeight - 1)); } while ( MazeUtils.IsValidWaypointLocation(mazeGenome, waypoint, UInt32.MaxValue, newPointOrientation) == false); mazeGenome.PathGeneList.Add(new PathGene(mazeGenomeFactory.InnovationIdGenerator.NextId, waypoint, newPointOrientation)); } // Create the specified number of interior walls (i.e. maze genes) for (int cnt = 0; cnt < numInteriorWalls; cnt++) { // Create new maze gene and add to genome mazeGenome.WallGeneList.Add(new WallGene(mazeGenomeFactory.InnovationIdGenerator.NextId, rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5)); } // Only serialize genomes to separate files if single output file option is turned off if (isSingleOutputFile == false) { // Serialize the genome to XML using ( XmlWriter xmlWriter = XmlWriter.Create( Path.Combine(mazeGenomeOutputDirectory, string.Format("{0}.xml", fileBaseName)), new XmlWriterSettings { Indent = true })) { // Get genome XML MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenome); } } // Otherwise, just add genome to list to be serialized to single file in bulk else { mazeGenomeList.Add(mazeGenome); } // Print the maze to a bitmap file if that option has been specified if (generateMazeImages) { PrintMazeToFile(mazeGenome, string.Format("{0}_Structure.bmp", fileBaseName)); } } // If serialize to single output file is turned off, go ahead and write everything out to the file if (isSingleOutputFile) { // Serialize all genomes to XML using ( XmlWriter xmlWriter = XmlWriter.Create(Path.Combine(mazeGenomeOutputDirectory, string.Format("GeneratedMaze_{0}_Genomes_{1}_Height_{2}_Width_{3}_Waypoints_{4}_Walls.xml", numMazes, mazeHeight, mazeWidth, numWaypoints, numInteriorWalls)))) { MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenomeList); } } }
/// <summary> /// Converts the maze genome into a maze structure and prints it to a bitmap file. /// </summary> /// <param name="mazeGenome">The maze genome to convert and print.</param> /// <param name="mazeImageName">The name of the maze output file.</param> private static void PrintMazeToFile(MazeGenome mazeGenome, string mazeImageName) { // Read in the maze decode parameters int mazeHeight = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeHeight]); int mazeWidth = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeWidth]); int mazeScaleFactor = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeScaleFactor]); string mazeBitmapOutputDirectory = _executionConfiguration[ExecutionParameter.BitmapOutputBaseDirectory]; // Instantiate the maze genome decoder MazeDecoder mazeDecoder = new MazeDecoder(mazeHeight, mazeWidth, mazeScaleFactor); // Decode the maze to get a maze structure MazeStructure mazeStructure = mazeDecoder.Decode(mazeGenome); // Create pen and initialize bitmap canvas Pen blackPen = new Pen(Color.Black, 0.0001f); Bitmap mazeBitmap = new Bitmap(mazeStructure.ScaledMazeWidth + 1, mazeStructure.ScaledMazeHeight + 1); using (Graphics graphics = Graphics.FromImage(mazeBitmap)) { // Fill with white Rectangle imageSize = new Rectangle(0, 0, mazeStructure.ScaledMazeWidth + 1, mazeStructure.ScaledMazeHeight + 1); graphics.FillRectangle(Brushes.White, imageSize); // Draw start and end points graphics.FillEllipse(Brushes.Green, mazeStructure.StartLocation.X, mazeStructure.StartLocation.Y, 5, 5); graphics.FillEllipse(Brushes.Red, mazeStructure.TargetLocation.X, mazeStructure.TargetLocation.Y, 5, 5); // Draw all of the walls foreach (MazeStructureWall wall in mazeStructure.Walls) { // Convert line start/end points to Point objects from drawing namespace Point startPoint = new Point(wall.StartMazeStructurePoint.X, wall.StartMazeStructurePoint.Y); Point endPoint = new Point(wall.EndMazeStructurePoint.X, wall.EndMazeStructurePoint.Y); // Draw wall graphics.DrawLine(blackPen, startPoint, endPoint); } } // Save the bitmap image mazeBitmap.Save(Path.Combine(mazeBitmapOutputDirectory, mazeImageName)); }
/// <summary> /// Handles the process of generating maze genomes and rendering bitmap files of their structure. /// </summary> private static void HandleMazeGeneration() { Random rand = new Random(); // Get the number of interior walls and maze genome output directory int numInteriorWalls = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWalls]); string mazeGenomeOutputDirectory = _executionConfiguration[ExecutionParameter.MazeGenomeOutputBaseDirectory]; // Get the number of sample mazes to generate (or just 1 maze if not specified) int numMazes = _executionConfiguration.ContainsKey(ExecutionParameter.NumMazes) ? Int32.Parse(_executionConfiguration[ExecutionParameter.NumMazes]) : 1; // Get whether images are being generated for the sample mazes bool generateMazeImages = _executionConfiguration.ContainsKey(ExecutionParameter.OutputMazeBitmap) && Boolean.Parse(_executionConfiguration[ExecutionParameter.OutputMazeBitmap]); // Get whether maze genomes are being serialized to the same file (defaults to false) bool isSingleOutputFile = _executionConfiguration.ContainsKey(ExecutionParameter.SingleGenomeOutputFile) && Boolean.Parse(_executionConfiguration[ExecutionParameter.SingleGenomeOutputFile]); // Create a new maze genome factory MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory(); // Instantiate list to hold generated maze genomes // (only really used when we're writing everything out to one file) List<MazeGenome> mazeGenomeList = new List<MazeGenome>(numMazes); for (int curMazeCnt = 0; curMazeCnt < numMazes; curMazeCnt++) { MazeGenome mazeGenome = null; // Lay out the base file name string fileBaseName = string.Format("GeneratedMazeGenome_{0}_Walls_{1}", numInteriorWalls, curMazeCnt); // With a single output file, the genomes are likely being used for separate experiments, so we // reset the innovation IDs and assign the maze a constant identifier if (isSingleOutputFile == false) { // Reset innovation IDs mazeGenomeFactory.InnovationIdGenerator.Reset(); // Create a new genome and pass in the requisite factory mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0); } // Otherwise, we leave the innovation ID generator along and create a new maze genome with // an identifier that's incremented by one else { mazeGenome = new MazeGenome(mazeGenomeFactory, (uint) curMazeCnt, 0); } // Create the specified number of interior walls (i.e. maze genes) for (int cnt = 0; cnt < numInteriorWalls; cnt++) { // Create new maze gene and add to genome mazeGenome?.GeneList.Add(new MazeGene(mazeGenomeFactory.InnovationIdGenerator.NextId, rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5)); } // Only serialize genomes to separate files if single output file option is turned off if (isSingleOutputFile == false) { // Serialize the genome to XML using ( XmlWriter xmlWriter = XmlWriter.Create( Path.Combine(mazeGenomeOutputDirectory, string.Format("{0}.xml", fileBaseName)), new XmlWriterSettings {Indent = true})) { // Get genome XML MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenome); } } // Otherwise, just add genome to list to be serialized to single file in bulk else { mazeGenomeList.Add(mazeGenome); } // Print the maze to a bitmap file if that option has been specified if (generateMazeImages) { PrintMazeToFile(mazeGenome, string.Format("{0}_Structure.bmp", fileBaseName)); } } // If serialize to single output file is turned off, go ahead and write everything out to the file if (isSingleOutputFile) { // Serialize all genomes to XML using ( XmlWriter xmlWriter = XmlWriter.Create(Path.Combine(mazeGenomeOutputDirectory, string.Format("GeneratedMaze_{0}_Genomes_{1}_Walls.xml", numMazes, numInteriorWalls)))) { MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenomeList); } } }
/// <summary> /// Generates the specified number of maze genomes with the specified complexity (i.e. number of interior partitions). /// </summary> /// <param name="numMazeGenomes">The number of maze genomes to generate.</param> /// <param name="numPartitions">The number of initial partitions (the starting complexity of the genome).</param> /// <param name="mazeGenomeFactory">Reference to the maze genome factory.</param> /// <returns></returns> public static List<MazeGenome> GenerateMazeGenomes(int numMazeGenomes, int numPartitions, MazeGenomeFactory mazeGenomeFactory) { List<MazeGenome> mazeGenomes = new List<MazeGenome>(numMazeGenomes); Random rand = new Random(); for (int curMazeCnt = 0; curMazeCnt < numMazeGenomes; curMazeCnt++) { // Reset innovation IDs mazeGenomeFactory.InnovationIdGenerator.Reset(); // Create a new genome and pass in the requisite factory MazeGenome mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0); // Create the specified number of interior partitions (i.e. maze genes) for (int cnt = 0; cnt < numPartitions; cnt++) { // Create new maze gene and add to genome mazeGenome.GeneList.Add(new MazeGene(mazeGenomeFactory.InnovationIdGenerator.NextId, rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5)); } mazeGenomes.Add(mazeGenome); } return mazeGenomes; }
/// <summary> /// Writes a single genome to XML. /// </summary> /// <param name="xw">Reference to the XmlWriter.</param> /// <param name="genome">The genome to write.</param> public static void WriteComplete(XmlWriter xw, MazeGenome genome) { WriteComplete(xw, new List<MazeGenome>(1) {genome}); }
/// <summary> /// Writes all of the components of a single maze genome to XML. /// </summary> /// <param name="xw">Reference to the XmlWriter.</param> /// <param name="genome">The genome to write.</param> public static void Write(XmlWriter xw, MazeGenome genome) { // Write maze element and accompanying attributes xw.WriteStartElement(__ElemMaze); xw.WriteAttributeString(__AttrId, genome.Id.ToString(NumberFormatInfo.InvariantInfo)); xw.WriteAttributeString(__AttrBirthGeneration, genome.BirthGeneration.ToString(NumberFormatInfo.InvariantInfo)); // Emit walls xw.WriteStartElement(__ElemWalls); foreach (MazeGene mazeGene in genome.GeneList) { xw.WriteStartElement(__ElemWall); xw.WriteAttributeString(__AttrId, mazeGene.InnovationId.ToString(NumberFormatInfo.InvariantInfo)); xw.WriteAttributeString(__AttrRelativeWallLocation, mazeGene.WallLocation.ToString(NumberFormatInfo.InvariantInfo)); xw.WriteAttributeString(__AttrRelativePassageLocation, mazeGene.PassageLocation.ToString(NumberFormatInfo.InvariantInfo)); xw.WriteAttributeString(__AttrOrientationSeed, mazeGene.OrientationSeed.ToString()); // </Wall> xw.WriteEndElement(); } // </Walls> xw.WriteEndElement(); // </Maze> xw.WriteEndElement(); }