示例#1
0
文件: Tests2.cs 项目: mrBoie/NeatPlay
        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];
    }
示例#3
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);
            }
        }
示例#4
0
        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();
    }
示例#7
0
        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);
        }
示例#8
0
    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));
    }
示例#9
0
    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);
    }
示例#10
0
    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);
    }
示例#11
0
    //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);
    }
示例#12
0
    /// <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);
        //}
    }
示例#13
0
        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);
        }
示例#14
0
        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();
        }