Ejemplo n.º 1
0
    /// <summary>
    /// Create default Genome with 2 layers (input and output layers).
    /// </summary>
    public Genome(int inNodesCount, int outNodesCount)
    {
        // Create Nodes:
        for (int i = 0; i < inNodesCount; i++)
        {
            nodesList.Add(new Node(i + 1, 1));           // Input Nodes.
        }

        for (int i = 0; i < outNodesCount; i++)
        {
            nodesList.Add(new Node(i + inNodesCount + 1, maxNodeLayer));         // Output Nodes.
        }

        biasNodeIndex = inNodesCount + outNodesCount;
        nodesList.Add(new Node(biasNodeIndex + 1, 1));   // Bias Node.
        nodesList[biasNodeIndex].Activation = 1;         // Bias always has an activation value of 1.

        // Create connections between created input and output Nodes (without the Bias Node):
        for (int i = 0; i < outNodesCount; i++)
        {
            for (int j = 0; j < inNodesCount; j++)
            {
                nodesConnectionsList.Add(new NodesConnection(true, nodesList[j], nodesList[inNodesCount + i]));
            }
        }

        // Create connections between created Bias Node and output Nodes:
        for (int i = inNodesCount; i < biasNodeIndex; i++)
        {
            NodesConnection connection = new NodesConnection(true, nodesList[biasNodeIndex], nodesList[i]);
            connection.Weight = 1;             // On beginning set weight to 1 in the Bias connections.
            nodesConnectionsList.Add(connection);
        }
    }
Ejemplo n.º 2
0
    private void DrawNodesConnections(CarBrain brain, GameObject[] nodesUI)
    {
        int nodesConnectionsNumber = brain.Genome.NodesConnectionsList.Count;

        for (int i = 0; i < nodesConnectionsNumber; i++)
        {
            NodesConnection connection   = brain.Genome.NodesConnectionsList[i];
            GameObject      connectionUI = GetGenomeDataUIElementFromPool(genomeDataNodesConnectionsQueue, genomeDataNodesConnectionPrefab,
                                                                          genomeDataPanelNodesConnections);

            RectTransform   rectTransform        = connectionUI.GetComponent <RectTransform>();
            TextMeshProUGUI connectionNumberText = connectionUI.GetComponentInChildren <TextMeshProUGUI>(true);
            connectionNumberText.text = connection.Weight.ToString("F");

            Vector2 startPoint = Vector2.zero;
            foreach (GameObject nodeUI in nodesUI)
            {
                TextMeshProUGUI nodeNumberText = nodeUI.GetComponentInChildren <TextMeshProUGUI>();
                if (nodeNumberText.text.Equals(connection.InNode.Number.ToString()))
                {
                    startPoint = nodeUI.GetComponent <RectTransform>().anchoredPosition;
                    break;
                }
            }

            Vector2 endPoint = Vector2.zero;
            foreach (GameObject nodeUI in nodesUI)
            {
                TextMeshProUGUI nodeNumberText = nodeUI.GetComponentInChildren <TextMeshProUGUI>();
                if (nodeNumberText.text.Equals(connection.OutNode.Number.ToString()))
                {
                    endPoint = nodeUI.GetComponent <RectTransform>().anchoredPosition;
                    break;
                }
            }

            // Position:
            Vector2 connectionUIPosition = (endPoint + startPoint) / 2;
            rectTransform.anchoredPosition = connectionUIPosition;

            // Rotation:
            Vector2 distance = endPoint - startPoint;
            float   z        = Mathf.Atan2(distance.y, distance.x) * Mathf.Rad2Deg;
            rectTransform.rotation = Quaternion.AngleAxis(z, Vector3.forward);

            // Width:
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, distance.magnitude);

            // Color:
            float hsvColorPercent = (connection.Weight + 1) / 2 * 0.32f;         // 0% (min) = red, 16% (mid) = yellow, 32% (max) = green.
            connectionUI.GetComponent <Image>().color = Color.HSVToRGB(hsvColorPercent, 1, 1);
        }
    }
Ejemplo n.º 3
0
    private void Mutate(CarBrain[] brains)
    {
        System.Random rand = new System.Random();

        for (int brainIndex = 0; brainIndex < brains.Length; brainIndex++)
        {
            // 80% chance for each Genome to mutate their weights in the NodesConnections:
            if (rand.Next(0, 100) < 80)
            {
                for (int connectionIndex = 0; connectionIndex < brains[brainIndex].Genome.NodesConnectionsList.Count; connectionIndex++)
                {
                    // 10% chance for entirely change the weight and 90% for a little change:
                    if (rand.Next(0, 100) < 10)
                    {
                        brains[brainIndex].Genome.NodesConnectionsList[connectionIndex].Weight = (float)rand.NextDouble() * 2 - 1;
                    }
                    else
                    {
                        NodesConnection connection = brains[brainIndex].Genome.NodesConnectionsList[connectionIndex];

                        float additionalValue = connection.Weight / 10;
                        additionalValue = (rand.Next(0, 2) == 0) ? additionalValue : -additionalValue;

                        float weight = connection.Weight;
                        weight += additionalValue;
                        if (weight > 1)
                        {
                            weight = 1;
                        }
                        else if (weight < -1)
                        {
                            weight = -1;
                        }

                        connection.Weight = weight;
                    }
                }
            }

            // 5% chance for each Genome to add a new NodesConnection:
            if (rand.Next(0, 100) < 5)
            {
                brains[brainIndex].Genome.AddNewNodesConnection();
            }

            // 2% chance for each Genome to add a new Node:
            if (rand.Next(0, 100) < 2)
            {
                brains[brainIndex].Genome.AddNewNode();
            }
        }
    }
Ejemplo n.º 4
0
    public void ResetPopulationConfirmButtonClicked()
    {
        if (!sceneIsRestarting)
        {
            StartRaceButtonClicked();
            ResetPopulationCancelButtonClicked();
            startRaceButton.interactable       = false;
            resetPopulationButton.interactable = false;
            ShowEvolutionInfo(false);
            sceneIsRestarting = true;

            NodesConnection.ResetStaticValues();
            CarsController.ResetStaticValues();
            Species.ResetStaticValues();

            SensorVisualizer.VisualizeSensors = false;
            StartCoroutine(carsController.StartDissolveEffectOnSceneRestarting());
            StartCoroutine(EndSceneEffectBeforePopulationReset());
        }
    }
Ejemplo n.º 5
0
    /// <summary>
    /// Set data as in another Genome.
    /// </summary>
    public void CloneGenome(Genome betterGenome)
    {
        nodesList.Clear();
        nodesConnectionsList.Clear();

        biasNodeIndex = betterGenome.biasNodeIndex;
        maxNodeLayer  = betterGenome.maxNodeLayer;

        foreach (Node betterNode in betterGenome.NodesList)
        {
            nodesList.Add(new Node(betterNode.Number, betterNode.Layer));
        }
        nodesList[biasNodeIndex].Activation = 1;         // Bias always has an activation value of 1.

        foreach (NodesConnection betterConnection in betterGenome.NodesConnectionsList)
        {
            Node inNode  = null;
            Node outNode = null;
            foreach (Node node in nodesList)
            {
                if (betterConnection.InNode.Number == node.Number)
                {
                    inNode = node;
                }
                else if (betterConnection.OutNode.Number == node.Number)
                {
                    outNode = node;
                }

                if (inNode != null && outNode != null)
                {
                    break;
                }
            }

            NodesConnection connection = new NodesConnection(betterConnection.Enabled, inNode, outNode);
            connection.Weight = betterConnection.Weight;
            nodesConnectionsList.Add(connection);
        }
    }
Ejemplo n.º 6
0
    /// <summary>
    /// Add Node in hidden layer, between input and output layers. Can't add Node without at least 1 existing NodesConnection.
    /// </summary>
    public void AddNewNode()
    {
        if (nodesConnectionsList.Count == 0)
        {
            return;
        }

        // Get from random NodesConnection inNode and outNode. Don't disable the Bias connection:
        int randomConnectionIndex         = Random.Range(0, nodesConnectionsList.Count);
        int numberOfRandomBiasConnections = 0;

        while (nodesConnectionsList[randomConnectionIndex].InNode == nodesList[biasNodeIndex])        // Draw again if is connected with the Bias Node.
        {
            randomConnectionIndex = Random.Range(0, nodesConnectionsList.Count);

            // After 50 draws cancel adding the new Node. We don't want to freeze the game / wait too long:
            numberOfRandomBiasConnections++;
            if (numberOfRandomBiasConnections >= 50)
            {
                return;
            }
        }

        Node inNode        = nodesConnectionsList[randomConnectionIndex].InNode;
        Node outNode       = nodesConnectionsList[randomConnectionIndex].OutNode;
        Node newHiddenNode = new Node(nodesList.Count + 1, inNode.Layer + 1);

        // If newHiddenNode's layer is equal to outNode's layer then shift all Nodes' layers greater or equal to newHiddenNode's layer:
        if (newHiddenNode.Layer == outNode.Layer)
        {
            for (int i = 0; i < nodesList.Count; i++)
            {
                Node node = nodesList[i];
                if (newHiddenNode.Layer <= node.Layer)
                {
                    node.Layer++;
                    if (maxNodeLayer < node.Layer)
                    {
                        maxNodeLayer = node.Layer;
                    }
                }
            }
        }
        nodesList.Add(newHiddenNode);

        // Disable this random NodesConnection and add new 2 NodesConnections between newHiddenNode:
        nodesConnectionsList[randomConnectionIndex].Enabled = false;
        NodesConnection connection1 = new NodesConnection(true, inNode, newHiddenNode);
        NodesConnection connection2 = new NodesConnection(true, newHiddenNode, outNode);

        // First connection weight have to be 1. Second connection weight have to be equal to the weight of the disabled connection:
        connection1.Weight = 1;
        connection2.Weight = nodesConnectionsList[randomConnectionIndex].Weight;
        nodesConnectionsList.Add(connection1);
        nodesConnectionsList.Add(connection2);

        // Connect Bias Node to the newHiddenNode with 1 weight:
        NodesConnection newBiasConnection = new NodesConnection(true, nodesList[biasNodeIndex], newHiddenNode);

        newBiasConnection.Weight = 1;
        nodesConnectionsList.Add(newBiasConnection);
    }