public void MyTestMethod() { var random = new RandomImplementation(23); INeatConfiguration configuration = new DefaultNeatConfiguration(500); var nodeInovator = new InnovationGenerator(1); var ConnectionInovator = new InnovationGenerator(1); var genomeProvider = new GenomeProvider(nodeInovator, ConnectionInovator, random); var crossFunction = new NeatCrossFunction(random, configuration); var weightMutation = new ApplyWeightMutation(random, configuration); var addNodeMutation = new AddNodeMutation(nodeInovator, ConnectionInovator, random); var addConnectionMutation = new AddConnectionMutation(ConnectionInovator, random, configuration); var evaluator = new WeightOfAHundred(configuration, genomeProvider, nodeInovator, ConnectionInovator, addConnectionMutation, addNodeMutation, weightMutation, crossFunction, random); for (int i = 0; i < 1000; i++) { evaluator.EvaluateGeneration(); Console.WriteLine($"Best Fitness: {evaluator.FittestGenome.Fitness}"); } Assert.That(evaluator.FittestGenome.Fitness > 90); }
// Start is called before the first frame update void Awake() { players = new List <GameObject>(); playerControls = new List <PlayerControl>(); startTimes = new List <float>(); generation = 1; currentGenomeId = 1; genomes = new Dictionary <string, Genome>(); cameraFollow = GetComponent <CameraFollow>(); innovationGenerator = new InnovationGenerator(); GameObject playerPrefab = (GameObject)Resources.Load("Player"); playerSpawner = GameObject.Find("Player Spawner"); genomeDropdown.onValueChanged.AddListener(delegate { DropdownValueChanged(genomeDropdown); }); for (int i = 0; i < numPerGeneration; i++) { players.Add(GameObject.Instantiate(playerPrefab)); players[i].transform.position = playerSpawner.transform.position; playerControls.Add(players[i].GetComponent <PlayerControl>()); Genome newGenome = new Genome(currentGenomeId++, 4, 3, true, innovationGenerator); playerControls[i].AssociateGenome(newGenome); genomes.Add("Genome " + newGenome.Id, newGenome); UpdateDropdowns("Genome " + newGenome.Id); startTimes.Add(Time.realtimeSinceStartup); } bestPlayer = players[0]; }
public Runner(string gamePath, int gameInstances, string luaScriptPath = "") { InnovationGenerator = new InnovationGenerator(); GenomeInnovationGenerator = new InnovationGenerator(); GameExecutablePath = gamePath; GameCount = gameInstances; LuaState = new Lua(); LuaState.LoadCLRPackage(); LuaState["runner"] = this; if (luaScriptPath != string.Empty && File.Exists(luaScriptPath)) { LuaState.DoFile(luaScriptPath); } }
public void test() { var random = new RandomImplementation(23); INeatConfiguration configuration = new DefaultNeatConfiguration(500); var nodeInovator = new InnovationGenerator(1); var connectionInovator = new InnovationGenerator(1); var problemDomain = new ProblemDomain( inputs: new double[, ] { { 0, 0, 1 }, { 0, 1, 1 }, { 1, 0, 1 }, { 1, 1, 1 } }, outputs: new double[, ] { { 0 }, { 1 }, { 1 }, { 0 } }); var genome = CreateOriginalGenome(nodeInovator, connectionInovator, problemDomain); var genomeProvider = new XORNNProvider(nodeInovator, connectionInovator, random, genome); var crossFunction = new NeatCrossFunction(random, configuration); var weightMutation = new ApplyWeightMutation(random, configuration); var addNodeMutation = new AddNodeMutation(nodeInovator, connectionInovator, random); var addConnectionMutation = new AddConnectionMutation(connectionInovator, random, configuration); var evaluator = new XORNNEvaluator(configuration, genomeProvider, nodeInovator, connectionInovator, addConnectionMutation, addNodeMutation, weightMutation, crossFunction, random, problemDomain); for (int i = 0; i < 1000; i++) { evaluator.EvaluateGeneration(); Console.WriteLine($"Best Fitness: {evaluator.FittestGenome.Fitness}"); } Assert.That(evaluator.FittestGenome.Fitness > 90); }
// Start is called before the first frame update void Start() { innovationGenerator = new InnovationGenerator(); genomes = new Dictionary <string, Genome>(); currentGenomeId = 0; firstGenomeDropdown.onValueChanged.AddListener(delegate { DropdownValueChanged(firstGenomeDropdown); }); //Genome parent = new Genome(0, 4, 3, true, innovationGenerator); //for (int i = 0; i < 50; i++) //{ // parent.AddConnection(1.0f, 0.1f, 1.0f, innovationGenerator, 20, 20); // Debug.Log(innovationGenerator.CurrentInnovation); //} //PrintGenome("ParentMutated", parent); //GraphDisplay graphDisplay = new GraphDisplay(parent); }
/// <summary> /// Constructs a genome given a number of inputs and outputs and whether or not there is a bias node. /// </summary> /// <param name="id">The unique id of the genome.</param> /// <param name="numInputs">The number of inputs in the genome.</param> /// <param name="numOutputs">The number of outputs in the genome.</param> /// <param name="hasBiasNode">Whether or not the genome will have a bias node.</param> /// <param name="innovationGenerator">The innovation generator that creates unique innovation numbers and node ids.</param> public Genome(int id, int numInputs, int numOutputs, bool hasBiasNode, InnovationGenerator innovationGenerator) { // Initialize the hash tables Nodes = new List <NodeGene>(); Connections = new List <ConnectionGene>(); // Initialize id Id = id; // Initialize starting nodes id int startingNodesId = 0; // Generate and add input nodes NumInputs = numInputs; for (int i = 0; i < numInputs; i++) { Nodes.Add(new NodeGene(NodeGene.TYPE.INPUT, startingNodesId++)); } // Create the bias node if it exists if (hasBiasNode) { Nodes.Add(new NodeGene(NodeGene.TYPE.BIAS, startingNodesId++)); } // Generate and add output nodes NumOutputs = numOutputs; for (int i = 0; i < numOutputs; i++) { Nodes.Add(new NodeGene(NodeGene.TYPE.OUTPUT, startingNodesId++)); } // Add starting nodes innovations if they have not been created previously if (innovationGenerator.CheckInnovation(-1, -1, Innovation.TYPE.NEW_NODE) < 0) { innovationGenerator.CreateStartingNodeInnovations(startingNodesId); } // Update the locations of the output nodes UpdateOutputLocations(); }
private static Genome CreateOriginalGenome(InnovationGenerator nodeInovator, InnovationGenerator connectionInovator, ProblemDomain problemDomain) { var grandGenome = new Genome(); grandGenome.Nodes = new Dictionary <int, Node>(); for (int i = 0; i < problemDomain.Inputs.GetLength(1); i++) { var node = new Node { Id = nodeInovator.GetNextInnovation(), NodeType = SoNEAT.Models.NodeType.Sensor }; grandGenome.Nodes.Add(node.Id, node); } for (int i = 0; i < problemDomain.Outputs.GetLength(1); i++) { var node = new Node { Id = nodeInovator.GetNextInnovation(), NodeType = SoNEAT.Models.NodeType.Output }; grandGenome.Nodes.Add(node.Id, node); } grandGenome.Connections = new Dictionary <int, SoNEAT.Models.Connection>(); foreach (var inNode in grandGenome.Nodes.Values.Where(n => n.NodeType == SoNEAT.Models.NodeType.Sensor)) { foreach (var outNode in grandGenome.Nodes.Values.Where(n => n.NodeType == SoNEAT.Models.NodeType.Output)) { var connection = new Connection() { Id = connectionInovator.GetNextInnovation(), InNodeId = inNode.Id, OutNodeId = outNode.Id, IsEnabled = true, Weight = 1.0 }; grandGenome.Connections.Add(connection.Id, connection); } } return(grandGenome); }
public void AddNodeMutation(Random r) //insert a node between two connected nodes { int conKey = connectionKeys[r.Next(connectionKeys.Count)]; //get a random connection ConnectionGene con = connectionList[conKey]; int node1 = con.GetInNode(); int node2 = con.GetOutNode(); con.Disable(); //disable connection NodeGene newNode = new NodeGene(nodeList.Count + 1, NodeGene.TYPE.HIDDEN); //create a new node nodeList.Add(newNode); //add new node to node list int innovation1 = InnovationGenerator.GetInnovation(); int innovation2 = InnovationGenerator.GetInnovation(); connectionKeys.Add(innovation1); connectionList.Add(innovation1, new ConnectionGene(node1, newNode.GetID(), 1f, true, innovation1)); //add new connections to connection list connectionKeys.Add(innovation2); connectionList.Add(innovation2, new ConnectionGene(newNode.GetID(), node2, con.GetWeight(), true, innovation2)); }
public void AddConnectionMutation(Random r) //Adds a connection between two random nodes { int node1 = r.Next(nodeList.Count); int node2 = r.Next(nodeList.Count); NodeGene.TYPE type1 = nodeList[node1].GetNodeType(); NodeGene.TYPE type2 = nodeList[node2].GetNodeType(); if (type1 == type2 && type1 != NodeGene.TYPE.HIDDEN) //invalid pair { AddConnectionMutation(r); //try again with a random a pair return; } foreach (ConnectionGene con in connectionList.Values) { if (node1 == con.GetInNode() && node2 == con.GetOutNode() || node2 == con.GetInNode() && node1 == con.GetOutNode()) //if connection already exists { return; } } if (type1 == NodeGene.TYPE.OUTPUT || type1 == NodeGene.TYPE.HIDDEN && type2 == NodeGene.TYPE.INPUT) //Switch nodes if they are reversed { int tmp = node1; NodeGene.TYPE tmpType = type1; node1 = node2; type1 = type2; node2 = tmp; type2 = tmpType; } float weight = (float)((r.NextDouble() * 2) - 1); int innovation = InnovationGenerator.GetInnovation(); connectionList.Add(innovation, new ConnectionGene(node1 + 1, node2 + 1, weight, true, innovation)); connectionKeys.Add(innovation); }
public Genome(int inputNodes, int outputNodes, Random r) //Makes a basic genome with only input and output nodes { connectionKeys = new List <int>(); nodeList = new List <NodeGene>(); connectionList = new Dictionary <int, ConnectionGene>(); int innovation = 1; for (int i = 1; i <= inputNodes; i++) { nodeList.Add(new NodeGene(i, NodeGene.TYPE.INPUT)); } for (int i = inputNodes + 1; i <= inputNodes + outputNodes; i++) { nodeList.Add(new NodeGene(i, NodeGene.TYPE.OUTPUT)); for (int j = 1; j <= inputNodes; j++) { float weight = (float)((r.NextDouble() * 2) - 1); connectionList.Add(innovation, new ConnectionGene(j, i, weight, true, innovation)); connectionKeys.Add(innovation); innovation++; } } InnovationGenerator.SetInnovation(connectionKeys.Count); }
//TODO: Investigate whether recurrent connections should be able to get new nodes /// <summary> /// Adds a node in a random connection if possible, disables that connection, and creates two new connections. /// </summary> /// <param name="mutationRate">The chance that this mutation occurs.</param> /// <param name="innovationGenerator">The generator that tracks innovation numbers.</param> /// <param name="numTrysToFindOldConnection">The number of attempts that will be made to find an old connection for the new node.</param> public void AddNode(float mutationRate, InnovationGenerator innovationGenerator, int numTrysToFindOldConnection) { // Return if there are no connections to add nodes to if (Connections.Count == 0) { return; } // Return depending on the mutation rate if (Random.Range(0.0f, 1.0f) > mutationRate) { return; } // Set to true if a valid connection is found for the new node bool connectionFound = false; // The innovation of the connection we are replacing ConnectionGene oldConnection = null; // If the genome has fewer than 5 hidden nodes, we select a connection // with a bias towards older nodes, otherwise we select without bias int sizeThreshold = NumInputs + NumOutputs + 5; if (Nodes.Count < sizeThreshold) { while (numTrysToFindOldConnection-- > 0) { // Select a random connection with bias towards earlier connections oldConnection = Connections[Random.Range(0, Connections.Count - 1 - (int)Mathf.Sqrt(Connections.Count))]; // Make sure this connection is enabled, not recurrent, and not originating // from a bias node if (oldConnection.Enabled && !oldConnection.Recurrent && oldConnection.InNode.Type != NodeGene.TYPE.BIAS) { connectionFound = true; numTrysToFindOldConnection = 0; } } // Return if no old connection was found if (!connectionFound) { return; } } else { while (!connectionFound) { // This genome is big enough to select a connection uniformly randomly oldConnection = Connections[Random.Range(0, Connections.Count)]; // Make sure this connection is enabled, not recurrent, and not originating // from a bias node if (oldConnection.Enabled && !oldConnection.Recurrent && oldConnection.InNode.Type != NodeGene.TYPE.BIAS) { connectionFound = true; } } } // Disable the old connection oldConnection.Enabled = false; // Get the in and out nodes for this connection NodeGene inNode = oldConnection.InNode; NodeGene outNode = oldConnection.OutNode; // Check if this innovation has occured for another genome in the population int id = innovationGenerator.CheckInnovation(inNode.Id, outNode.Id, Innovation.TYPE.NEW_NODE); // Since the connection can be re-enabled later, it is possible that multiple nodes will be created for the same // connection, in which case we must assign it a new id if (id >= 0 && AlreadyHasNodeId(id)) { id = -1; } // We know that this innovation is new if id = -1 if (id < 0) { // --------- New Node ---------- // Create new node and add to list of nodes NodeGene newNode = new NodeGene(NodeGene.TYPE.HIDDEN, innovationGenerator.CurrentNodeId); Nodes.Add(newNode); // Create new node innovation innovationGenerator.CreateNewInnovation(inNode.Id, outNode.Id, Innovation.TYPE.NEW_NODE); // --------- First connection ---------- // Create new connection and add to list of connections Connections.Add(new ConnectionGene(inNode, newNode, 1.0f, innovationGenerator.CurrentInnovation, false)); // Create new connection innovation innovationGenerator.CreateNewInnovation(inNode.Id, newNode.Id, Innovation.TYPE.NEW_CONNECTION); // --------- Second connection ---------- // Create new connection and add to list of connections Connections.Add(new ConnectionGene(newNode, outNode, oldConnection.Weight, innovationGenerator.CurrentInnovation, false)); // Create new connection innovation innovationGenerator.CreateNewInnovation(newNode.Id, outNode.Id, Innovation.TYPE.NEW_CONNECTION); // --------- Update locations ---------- // Add newNode to inNode's connections inNode.AddConnectedNode(newNode); // Add outNode to newNode's connections newNode.AddConnectedNode(outNode); // Update location of newNode newNode.Location = inNode.Location + 1; // Update location of outNode int newNodeLocation = newNode.Location + 1; if (outNode.Location < newNodeLocation) { outNode.Location = newNodeLocation; outNode.UpdateLocations(); } UpdateOutputLocations(); } else { // Get the innovations for the already existing connections int innovation1 = innovationGenerator.CheckInnovation(inNode.Id, id, Innovation.TYPE.NEW_CONNECTION); int innovation2 = innovationGenerator.CheckInnovation(id, outNode.Id, Innovation.TYPE.NEW_CONNECTION); // TODO: This happened, need to figure out why and fix, probably nodes not being assigned correct values (again) // This should not happen, as the connections should exist, but if not diplay an error and return if (innovation1 < 0 || innovation2 < 0) { Debug.LogError("Error in Genome.AddNode()!"); return; } // Create node and add to node list NodeGene newNode = new NodeGene(NodeGene.TYPE.HIDDEN, id); Nodes.Add(newNode); // Create connections and add them to connection list Connections.Add(new ConnectionGene(inNode, newNode, 1.0f, innovation1, false)); Connections.Add(new ConnectionGene(newNode, outNode, oldConnection.Weight, innovation2, false)); // --------- Update locations ---------- // Add newNode to inNode's connections inNode.AddConnectedNode(newNode); // Add outNode to newNode's connections newNode.AddConnectedNode(outNode); // Update location of newNode newNode.Location = inNode.Location + 1; // Update location of outNode int newNodeLocation = newNode.Location + 1; if (outNode.Location < newNodeLocation) { outNode.Location = newNodeLocation; outNode.UpdateLocations(); } UpdateOutputLocations(); } // *** // Old implementation // *** //// If there are no connections return //if (Connections.Count == 0) return; //// Get a random connection gene by grabbing a random key from the hashtable //int[] keys = new int[Connections.Count]; //Connections.Keys.CopyTo(keys, 0); //ConnectionGene gene = (ConnectionGene)Connections[keys[Random.Range(0, keys.Length)]]; //// Disable that connection //gene.Enabled = false; //// Create a new node and connect it to the inNode and outNode of the connection gene //NodeGene newNode = new NodeGene(NodeGene.TYPE.HIDDEN, innovationGenerator.GetNodeInnovation(gene.InNode.Id, gene.OutNode.Id)); //ConnectionGene inToNew = new ConnectionGene(gene.InNode, newNode, 1f, innovationGenerator.GetConnectionInnovation(gene.InNode.Id, newNode.Id)); //ConnectionGene newToOut = new ConnectionGene(newNode, gene.OutNode, gene.Weight, innovationGenerator.GetConnectionInnovation(newNode.Id, gene.OutNode.Id)); //Debug.Log(gene.InNode.Id + " " + gene.OutNode.Id + " " + newNode.Id); //// Add the new node and connection genes to lists //Nodes.Add(newNode.Id, newNode); //Connections.Add(inToNew.Innovation, inToNew); //Connections.Add(newToOut.Innovation, newToOut); }
/// <summary> /// Adds a new random connection to the genome if possible. /// </summary> /// <param name="mutationRate">The chance that this mutation occurs.</param> /// <param name="chanceOfLooped">The chance that the connection will be from a node to itself.</param> /// <param name="weightLimit">The weight will be a random float between positive and negative weightLimit.</param> /// <param name="innovationGenerator">The generator that tracks innovation numbers.</param> /// <param name="numTrysToFindConnection">The number of attempts made to find a connection to create.</param> /// <param name="numTrysToFindLoop">The number of attempts made to find a possible connection from a node to itself.</param> public void AddConnection(float mutationRate, float chanceOfLooped, float weightLimit, InnovationGenerator innovationGenerator, int numTrysToFindLoop, int numTrysToFindConnection) { // Return depending on the mutation rate if (Random.Range(0.0f, 1.0f) > mutationRate) { return; } // Initialize nodes we will use to create the connection NodeGene inNode = null; NodeGene outNode = null; // Whether or not the connection is recurrent bool recurrent = false; // Check to see if connection should be made from a node to itself //int[] nodeKeys = new int[Nodes.Count]; //Nodes.Keys.CopyTo(nodeKeys, 0); if (Random.Range(0.0f, 1.0f) < chanceOfLooped) { // Check numTrysToFindLoop times to find node that is not bias // or input and does not have recurrent connection while (numTrysToFindLoop-- > 0) { NodeGene node = Nodes[Random.Range(0, Nodes.Count)]; if (node.Type != NodeGene.TYPE.INPUT && node.Type != NodeGene.TYPE.BIAS && !node.Recurrent) { node.Recurrent = true; inNode = outNode = node; recurrent = true; numTrysToFindLoop = 0; } } } else { // Check numTrysToFindConnection times to find two nodes with // no existing connection between them while (numTrysToFindConnection-- > 0) { // Get two nodes randomly int inNodeIndex = Random.Range(0, Nodes.Count); inNode = Nodes[inNodeIndex]; // Ensure that outNode is not the same node as inNode outNode = Nodes[(inNodeIndex + Random.Range(1, Nodes.Count)) % Nodes.Count]; // The second node cannot be an input or bias if (outNode.Type == NodeGene.TYPE.INPUT || outNode.Type == NodeGene.TYPE.BIAS) { inNode = null; outNode = null; continue; } // If this connection does not already exist, we have found our new connection if (!IsDuplicateConnection(inNode, outNode)) { numTrysToFindConnection = 0; } else { inNode = null; outNode = null; } } } // If we did not find two nodes that can have a connection, return if (inNode == null || outNode == null) { return; } // Check if this innovation already exists int id = innovationGenerator.CheckInnovation(inNode.Id, outNode.Id, Innovation.TYPE.NEW_CONNECTION); // Check the location of the nodes to check if the connection is recurrent if (outNode.Location <= inNode.Location) { recurrent = true; } // Get random weight float weight = Random.Range(-weightLimit, weightLimit); // Create a new innovation if it does not exist and get its id if (id < 0) { id = innovationGenerator.CurrentInnovation; innovationGenerator.CreateNewInnovation(inNode.Id, outNode.Id, Innovation.TYPE.NEW_CONNECTION); } // Add this connection to the existing connections ConnectionGene newConnection = new ConnectionGene(inNode, outNode, weight, id, recurrent); Connections.Add(newConnection); // If this new connection is not recurrent, we may need to update node locations if (!newConnection.Recurrent) { // Add outNode to inNode's connections inNode.AddConnectedNode(outNode); // Update node locations int newNodeLocation = inNode.Location + 1; if (outNode.Location < newNodeLocation) { outNode.Location = newNodeLocation; outNode.UpdateLocations(); } UpdateOutputLocations(); } //// Print for testing //string connectedNodesAsString = "All nodes:\n"; //foreach (NodeGene node in Nodes.Values) //{ // connectedNodesAsString += node.ToString() + ":\n"; // foreach (NodeGene connectedNode in node.ConnectedNodes.Values) // { // connectedNodesAsString += connectedNode.Id + " " + connectedNode.Location + "\n"; // } //} //Debug.Log(connectedNodesAsString); // *** // Old implementation // *** // Pick two nodes randomly from existing nodes //int[] keys = new int[Nodes.Count]; //Nodes.Keys.CopyTo(keys, 0); //int node1Key = keys[Random.Range(0, keys.Length)]; //inNode = (NodeGene) Nodes[node1Key]; //outNode = (NodeGene) Nodes[(node1Key + Random.Range(1, keys.Length)) % keys.Length]; // ensures that this is not the same node as inNode // Check if outNode is in a layer before inNode //bool reversed = false; //if (inNode.Type == NodeGene.TYPE.HIDDEN && outNode.Type == NodeGene.TYPE.INPUT) //{ // reversed = true; //} //else if (inNode.Type == NodeGene.TYPE.OUTPUT && outNode.Type == NodeGene.TYPE.HIDDEN) //{ // reversed = true; //} //else if (inNode.Type == NodeGene.TYPE.OUTPUT && (outNode.Type == NodeGene.TYPE.INPUT || outNode.Type == NodeGene.TYPE.BIAS)) //{ // reversed = true; //} // Make sure the connection does not already exist //bool connectionExists = false; //foreach (ConnectionGene gene in Connections.Values) //{ // if (gene.InNode.Equals(inNode) && gene.OutNode.Equals(outNode)) // { // connectionExists = true; // break; // } // else if (gene.InNode.Equals(outNode) && gene.OutNode.Equals(inNode)) // { // connectionExists = true; // break; // } //} // Make sure the connection is not between two nodes in the input layer or two in output layer //bool connectionImpossible = false; //if ((inNode.Type == NodeGene.TYPE.INPUT || inNode.Type == NodeGene.TYPE.BIAS) && (outNode.Type == NodeGene.TYPE.INPUT || outNode.Type == NodeGene.TYPE.BIAS)) //{ // connectionImpossible = true; //} //else if (inNode.Type == NodeGene.TYPE.OUTPUT && outNode.Type == NodeGene.TYPE.OUTPUT) //{ // connectionImpossible = true; //} // If the connection already exists or is not possible, try again, otherwise add this new connection //if (connectionExists || connectionImpossible) //{ // AddConnection(innovationGenerator); //} //else //{ // ConnectionGene newConnection; // if (reversed) { // newConnection = new ConnectionGene(outNode, inNode, weight, true, innovationGenerator.GetConnectionInnovation(outNode.Id, inNode.Id)); // } // else // { // newConnection = new ConnectionGene(inNode, outNode, weight, true, innovationGenerator.GetConnectionInnovation(inNode.Id, outNode.Id)); // } // Connections.Add(newConnection.Innovation, newConnection); //} }
public Generation MakeFirstGeneration(InnovationGenerator generator, InnovationGenerator genomeGenerator, int initialPopulationSize, int selectionAlgorithm, int reproductionsPerGenome, int nBest) { // check if there is a Lua implementation of this LuaFunction func = LuaState["MakeFirstGeneration"] as LuaFunction; if (func != null) { try { return((Generation)func.Call(generator, initialPopulationSize)?.First()); } catch (Exception e) { logger.Error(e, "Error running lua code for first generation."); } } Generation generation = new Generation(0, selectionAlgorithm, reproductionsPerGenome, nBest); Genome genome = new Genome(0); int inputs = Data.Constants.NetworkInputs; int outputs = Data.Constants.NetworkOutputs; List <int> inputIds = new List <int>(inputs); // input nodes for (int i = 0; i < inputs; i++) { int currentId = generator.Innovate(); inputIds.Add(currentId); genome.AddNode(new Node(currentId, NodeType.Input, int.MinValue)); } // output nodes for (int i = 0; i < outputs; i++) { int currentId = generator.Innovate(); genome.AddNode(new Node(currentId, NodeType.Output, int.MaxValue)); foreach (int hiddenId in inputIds) { genome.AddConnection(new Connection(hiddenId, currentId, Double() * 4f - 2f, true, generator.Innovate())); } } Species original = new Species(genome); generation.Species.Add(original); for (int i = 0; i < initialPopulationSize; i++) { Genome g = genome.Copy(); g.Mutate(generator); g.Id = genomeGenerator.Innovate(); original.AddGenome(g); } return(generation); }
public void DoRun(GameModes mode, Generation firstGeneration, int selectionAlgorithm, int reproductionsPerGenome, int nBest) { string hexagonDirectory = Path.GetDirectoryName(GameExecutablePath); string hexagonFile = Path.GetFileName(GameExecutablePath); // start game instances logger.Trace("Starting {0} Super Hexagon instances... ", GameCount); string gamePath = Path.Combine(hexagonDirectory, hexagonFile); string gameWd = hexagonDirectory; StartGameInstances(gamePath, gameWd, GameCount); // create directory for run files logger.Trace("Creating run directory... "); DateTime now = DateTime.Now; string runDirectoryName = "run-" + now.Year + "-" + now.Month + "-" + now.Day + "-" + now.Hour + "-" + now.Minute + "-" + now.Second; string runDirectoryPath = Path.Combine(Directory.GetCurrentDirectory(), runDirectoryName); Directory.CreateDirectory(runDirectoryPath); // do the run InnovationGenerator generator = InnovationGenerator; InnovationGenerator genomeGenerator = GenomeInnovationGenerator; Generation generation = firstGeneration; while (!ShouldStop) { logger.Trace("Generation " + generation.Number + " starting (" + generation.Species.Sum(s => s.Members.Count) + ")..."); // add the individuals to the list of untested individuals int generationCount = 0; foreach (Species s in generation.Species) { foreach (Genome member in s.Members) { Individual individual = new Individual(member, generation.Number); //individual.Prepare(); individual.Index = generationCount; UntestedIndividuals.Enqueue(individual); OnUntestedIndividual(individual); generationCount++; } } // test all individuals in generation while (!UntestedIndividuals.IsEmpty) { // in case there are no available game managers, wait for a signal on // managerAvailableEvent if (AvailableGameManagers.IsEmpty) { managerAvailableEvent.WaitOne(); continue; // restart the loop (in order to check again if there are game managers available) } // there are still untested individuals in the generation and there // is a manager available, so start a thread with a runner on this manager AvailableGameManagers.TryDequeue(out GameManager manager); if (manager == null) { continue; // not sure what happened, try again } UntestedIndividuals.TryDequeue(out Individual individual); if (individual == null) { // put the manager back in queue and try the loop again AvailableGameManagers.Enqueue(manager); continue; } manager.Game.SRand((uint)individual.Generation); manager.Game.GameSpeed = GameSpeed; AIRunner runner = new AIRunner(manager, individual, mode); ThreadStart start = new ThreadStart(() => { runner.DoSafeRun(); // do the game run // add the individual to the list of tested individuals TestedIndividuals.Enqueue(runner.Individual); OnIndividualTested(runner.Individual); individualTestedEvent.Set(); // signal that an individual was tested AvailableGameManagers.Enqueue(manager); // then add the manager back to the queue managerAvailableEvent.Set(); // then signal that managers are available }); Thread thread = new Thread(start); thread.Start(); // start the thread } // now we know all individuals are either testing or tested // let's wait until all individuals have been tested while (TestedIndividuals.Count != generationCount) { individualTestedEvent.WaitOne(); } string genFileName = "gen-" + generation.Number + ".json"; var genFile = File.Create(Path.Combine(runDirectoryPath, genFileName)); var buf = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(generation)); genFile.Write(buf, 0, buf.Length); genFile.Close(); logger.Trace("Generation file saved: " + genFileName); // make next generation OnGenerationFinished(generation); LuaFunction func = LuaState["MakeNextGeneration"] as LuaFunction; bool error = false; if (func != null) { try { generation = (Generation)func.Call(generation, generator, genomeGenerator).First(); } catch (Exception e) { error = true; logger.Error(e, "Error running lua code for next generation."); } } if (func == null || error) { generation = generation.Next(generator, genomeGenerator, selectionAlgorithm, reproductionsPerGenome, nBest); } OnNextGeneration(generation); // ajustes da mutação // clean up this generation's data TestedIndividuals = new ConcurrentQueue <Individual>(); } OnLoopFinish(); // terminate all game processes KillGameInstances(); }