/// <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)); }