Example #1
0
        /// <summary>
        /// Mutates a given genome by adding a connection.
        /// Connection is guaranteed to not be 'into' a sensor or bias.
        /// </summary>
        /// <param name="genome">The genome to be modified.</param>
        /// <param name="innovationsSeen">A list of previously seen innovations.</param>
        /// <param name="rando">A random number generator.</param>
        public static void MutateAddConnection(Genome genome, InnovationPool innovationsSeen, Random rando)
        {
            //TODO: I'm getting the node information, but I only need that to construct allNodesNotInput...

            Dictionary <int, NodeInformation> allNodes         = genome.GetAllNodeInformation(true);
            Dictionary <int, NodeInformation> allNodesNotInput = new Dictionary <int, NodeInformation>(allNodes);

            //TODO: Witnessed a bug where allNodes.Count == 0.
            //      Could be a node where there are only frozen links connecting.

            foreach (var id in allNodesNotInput.Where(kvp => kvp.Value.IsInput()).ToList())
            {
                allNodesNotInput.Remove(id.Key);
            }

            //TODO: Gotta be a better way than a tryCount...
            int tryCount   = 0;
            int nodeFromId = -1;
            int nodeToId   = -1;

            while (tryCount < 20)
            {
                nodeFromId = allNodes.Keys.ToList()[rando.Next(allNodes.Count)];
                nodeToId   = allNodesNotInput.Keys.ToList()[rando.Next(allNodesNotInput.Count)];

                if (!genome.ContainsConnection(nodeFromId, nodeToId))
                {
                    break;
                }

                tryCount++;
            }

            if (tryCount == 20)
            {
                return;
            }

            ConnectionInformation connectInfo = new ConnectionInformation(nodeFromId, nodeToId);
            InnovationInformation innovation  = new InnovationInformation(connectInfo);

            int connectId = -1;
            //TODO: Pull inital weight setting out of here.
            double weight = rando.NextDouble() * 2.0 - 1.0;

            int registeredInnovationId = innovationsSeen.FindByInnovation(innovation);

            if (registeredInnovationId == -1)
            {
                connectId = ConnectionPool.Add(connectInfo);

                innovation.NewConnectionDetails.ConnectionId = connectId;
                innovationsSeen.Add(innovation);
            }
            else
            {
                connectId = innovationsSeen.FindById(registeredInnovationId).NewConnectionDetails.ConnectionId;
            }

            genome.Genes.Add(new Gene(ConnectionPool.FindById(connectId), connectId, weight, false));
        }