NanoBrain-unitypackage/NucleusArray.cs

157 lines
5.7 KiB
C#

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[System.Serializable]
public class NucleusArray {
[SerializeReference]
private Nucleus[] _nuclei;
public Nucleus[] nuclei {
get {
return _nuclei;
}
set {
_nuclei = value;
}
}
public NucleusArray(Nucleus nucleus) {
this._nuclei = new Nucleus[1];
this._nuclei[0] = nucleus;
}
public NucleusArray(ClusterPrefab cluster) {
this._nuclei = new Nucleus[0];
}
public NucleusArray(int size, string name) {
this._nuclei = new Nucleus[size];
}
public void AddNucleus(ClusterPrefab prefab) {
if (this._nuclei.Length == 0) {
Debug.LogError("Empty perceptoid array, cannot add");
return;
}
int newLength = this._nuclei.Length + 1;
Nucleus[] newArray = new Nucleus[newLength];
for (int i = 0; i < this._nuclei.Length; i++)
newArray[i] = this._nuclei[i];
if (this._nuclei[0] is Nucleus nucleus) {
newArray[newLength - 1] = nucleus.Clone(prefab);
newArray[newLength - 1].name += $": {newLength - 1}";
}
this._nuclei = newArray;
}
public void RemoveNucleus() {
int newLength = this._nuclei.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
return;
}
Nucleus[] newPerceptei = new Nucleus[newLength];
for (int i = 0; i < newLength; i++)
newPerceptei[i] = this._nuclei[i];
// Delete the last perception
if (this._nuclei[newLength] is Nucleus nucleus)
Neuron.Delete(nucleus); //this._nuclei[newLength]);
this._nuclei = newPerceptei;
}
public Dictionary<int, Nucleus> thingReceivers = new();
private Nucleus FindReceiver(int thingId, float3 inputValue) {
// No existing nucleus for this thing
float inputMagnitude = length(inputValue);
Neuron selectedReceiver = null;
float selectedMagnitude = 0;
foreach (Nucleus nucleusReceiver in this._nuclei) {
if (nucleusReceiver is not Neuron receiver)
continue;
if (thingReceivers.ContainsValue(receiver) == false) {
// We found an unusued receiver
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (receiver.isSleeping) {
// A sleeping receiver is not active and can therefore always be used
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (selectedReceiver == null) {
// If we haven't found a receiver yet, just start by taking the first
selectedReceiver = receiver;
selectedMagnitude = length(selectedReceiver.outputValue);
}
// Look for the receiver with the lowest magnitude
else {
float magnitude = length(receiver.outputValue);
if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) {
selectedReceiver = receiver;
selectedMagnitude = length(selectedReceiver.outputValue);
}
}
}
if (selectedReceiver != null) {
// Replace the receiver
// Find the thingId current associated with the receiver
int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key;
if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove))
thingReceivers.Remove(keyToRemove);
// And add the new association
thingReceivers.Add(thingId, selectedReceiver);
}
return selectedReceiver;
}
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
CleanupReceivers();
if (this._nuclei[0] is Neuron neuron)
inputValue = neuron.Activator(inputValue);
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
// No existing nucleus for this thing
selectedReceiver = FindReceiver(thingId, inputValue);
}
if (selectedReceiver == null)
return;
if (thingName != null) {
string baseName = selectedReceiver.name;
int colonPos = selectedReceiver.name.IndexOf(":");
if (colonPos > 0)
baseName = selectedReceiver.name[..colonPos];
selectedReceiver.name = baseName + ": " + thingName;
}
if (selectedReceiver is Neuron selectedNucleus)
selectedNucleus.ProcessStimulusDirect(inputValue);
}
private void CleanupReceivers() {
// Remove a thing-receiver connection when the nucleus is inactive
List<int> receiversToRemove = new();
foreach (KeyValuePair<int, Nucleus> item in thingReceivers) {
if (item.Value != null && item.Value is Neuron neuron && neuron.isSleeping)
receiversToRemove.Add(item.Key);
}
foreach (int thingId in receiversToRemove) {
Nucleus selectedReceiver = thingReceivers[thingId];
thingReceivers.Remove(thingId);
int colonPos = selectedReceiver.name.IndexOf(":");
if (colonPos > 0)
selectedReceiver.name = selectedReceiver.name[..colonPos];
}
}
}