public void Mutate() { // When no genes, add gene mutation if (Connections.Count == 0) { AddConnection(); } double chance = MyRand.UniformRnd(0, 1); // 80% chance to modify weight or bias if (chance < 0.8) { ModifyConnection(); } chance = MyRand.UniformRnd(0, 1); // 8% chance to add new connection if (chance < 0.08) { AddConnection(); } chance = MyRand.UniformRnd(0, 1); // 2% chance to add new node if (chance < 0.02) { AddNode(); } // No mutations today }
/// <summary> /// Random uniform weight, and enabled /// </summary> /// <param name="node">The input node</param> public Connection(Node node) { INode = node; Weight = MyRand.UniformRnd(-1, 1); Bias = MyRand.UniformRnd(-1, 1); Enabled = true; ONode = null; // Output nodes are not necessary defined immediately InnovID = 0; // It will be overwritten }
/// <summary> /// Adds a new player to the niche by crossover or cloning, could return null! /// </summary> public Player GetBaby() { // Need at least one player in this species if (Members.Count < 1) { return(null); } Player newPlayer = null; double chance = MyRand.UniformRnd(0, 1); // TODO opt. In this case it is unnecessary to decide which species should this belong // with 25% chance just clone a player || When we only have one member if (chance < 0.25 || Members.Count == 1) { int rndPlayer = MyRand.Next(0, Members.Count); newPlayer = Members[rndPlayer].DeepCopy(); newPlayer.SetFitness(0); newPlayer.LifeSpawn = 0; } // Crossover 75% chance else { // We cant do crossover if there are less than 2 players if (Members.Count < 2) { return(null); } Player parentA = null; Player parentB = null; do { int rndPlayerNumb = MyRand.Next(0, Members.Count); parentA = Members[rndPlayerNumb]; rndPlayerNumb = MyRand.Next(0, Members.Count); parentB = Members[rndPlayerNumb]; } while(parentA.ID == parentB.ID); if (parentA.Fitness > parentB.Fitness) { newPlayer = parentA.Crossover(parentB); } else { newPlayer = parentB.Crossover(parentA); } } return(newPlayer); }
// Crossover this and NetworkB where this is the better parent public Network Crossover(Network networkB) { // Create a child network, which is very similar to this network Network child = new Network(InputNodes, OutputNodes, OutputLayer, NodeCnt); // At first we should Add the nodes, but how to choose which nodes to add? // Chose the better parent which is this foreach (var nodeA in Nodes) { Node childN = nodeA.DeepCopy(nodeA.ID); // we will add the connections later childN.Connections.Clear(); child.Nodes.Add(childN); } //Go through the genes, and decide how to use them foreach (var conA in Connections) { bool enableGene = true; Connection gene = null; //Check if both parents have this gene Connection conB = networkB.FindConnection(conA.InnovID); if (conB != null) { //Both have this gene //Check if it is disabled in any of the parent and with 75% chance if ((!conA.Enabled || !conB.Enabled) && (MyRand.UniformRnd(0, 1) < Cfg.DisableUnnecessaryGene) ) { // These gene doesnt look necessary enableGene = false; } //Decide who will give the gene if (MyRand.UniformRnd(0, 1) < 0.50) { // Parent A Node iNode = child.getNodeByID(conA.INode.ID); Node oNode = child.getNodeByID(conA.ONode.ID); gene = conA.DeepCopy(iNode, oNode); iNode.Connections.Add(gene); } else { // Parent B Node iNode = child.getNodeByID(conB.INode.ID); Node oNode = child.getNodeByID(conB.ONode.ID); gene = conB.DeepCopy(iNode, oNode); iNode.Connections.Add(gene); } } else { //Only parentA has this gene, disjoint or excess gene Node iNode = child.getNodeByID(conA.INode.ID); Node oNode = child.getNodeByID(conA.ONode.ID); gene = conA.DeepCopy(iNode, oNode); iNode.Connections.Add(gene); } gene.Enabled = enableGene; child.Connections.Add(gene); } return(child); }
// Modify an existing connection, can also be turned Off or On public Result ModifyConnection() { // Check if we have connections or not if (Connections.Count == 0) { //Cannot Add new node return(Result.fail); } // Check if every connection is disabled, like in LoL bool allDisabled = true; foreach (var c in Connections) { if (c.Enabled) { allDisabled = false; break; } } if (allDisabled) { return(Result.fail); } // Select a connection which is not disabled Connection conn = null; do { int rndConNumb = MyRand.Next(0, Connections.Count); conn = Connections[rndConNumb]; } while(!conn.Enabled); // Slightly modify this connection's weight or bias if (MyRand.UniformRnd(0, 1) > 0.3) { // Weight change conn.Weight = MyRand.NormalDist(conn.Weight, 0.1); // Not sure if limiting the weight is a good idea or not if (conn.Weight > 1.0) { conn.Weight = 1.0; } if (conn.Weight < -1.0) { conn.Weight = -1.0; } } else { // Bias change conn.Bias = MyRand.NormalDist(conn.Bias, 0.1); // Not sure if limiting the bias is a good idea or not if (conn.Bias > 5.0) { conn.Bias = 5.0; } if (conn.Bias < -5.0) { conn.Bias = -5.0; } } return(Result.success); }