Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <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));
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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);
                }
            }
        }
Ejemplo n.º 10
0
        /// <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;
        }
Ejemplo n.º 11
0
 /// <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});
 }
Ejemplo n.º 12
0
        /// <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();
        }