using System; using System.Collections.Generic; using System.Linq; using Random = UnityEngine.Random; public sealed class NeuralNetwork : IComparable { public float Fitness { get; set; } private readonly int[] _layers; private readonly float[][] _neurons; private float[][][] _weights; public NeuralNetwork(int[] layers) { _layers = layers.ToArray(); _neurons = _layers.Select(layer => new float[layer]).ToArray(); InitWeights(); } public NeuralNetwork(NeuralNetwork network) { _layers = network._layers.ToArray(); _neurons = _layers.Select(layer => new float[layer]).ToArray(); InitWeights(); CopyWeights(network._weights); } private void CopyWeights(float[][][] weights) { for (int i = 0; i < _weights.Length; i++) { for (int j = 0; j < _weights[i].Length; j++) { for (int k = 0; k < _weights[i][j].Length; k++) { _weights[i][j][k] = weights[i][j][k]; } } } } private void InitWeights() { var weights = new List(); for (int i = 1; i < _layers.Length; i++) { var layerWeights = new List(); int previousNeurons = _layers[i - 1]; for (int j = 0; j < _neurons[i].Length; j++) { var neuronWeights = new float[previousNeurons]; for (int k = 0; k < previousNeurons; k++) { neuronWeights[k] = Random.Range(-0.5f, 0.5f); } layerWeights.Add(neuronWeights); } weights.Add(layerWeights.ToArray()); } _weights = weights.ToArray(); } public float[] FeedForward(float[] inputs) { for (int i = 0; i < inputs.Length; i++) { _neurons[0][i] = inputs[i]; } for (int i = 1; i < _layers.Length; i++) { for (int j = 0; j < _neurons[i].Length; j++) { var value = 0.25f; for (int k = 0; k < _neurons[i - 1].Length; k++) { value += _weights[i - 1][j][k] * _neurons[i - 1][k]; } _neurons[i][j] = MathF.Tanh(value); } } return _neurons[^1]; } public void Mutate() { for (int i = 0; i < _weights.Length; i++) { for (int j = 0; j < _weights[i].Length; j++) { for (int k = 0; k < _weights[i][j].Length; k++) { var weight = _weights[i][j][k]; var random = Random.Range(0.0f, 1000.0f); if (random <= 2.0f) weight *= -1.0f; else if (random <= 4.0f) weight = Random.Range(-0.5f, 0.5f); else if (random <= 6.0f) weight *= Random.Range(0.0f, 1.0f) + 1.0f; else if (random <= 8.0f) weight *= Random.Range(0.0f, 1.0f); _weights[i][j][k] = weight; } } } } public int CompareTo(NeuralNetwork other) { if (ReferenceEquals(this, other)) return 0; if (ReferenceEquals(null, other)) return 1; return Fitness.CompareTo(other.Fitness); } }