117 lines
4.1 KiB
C#
117 lines
4.1 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
|
public class ClusterPrefab : ScriptableObject {
|
|
// The ScriptableObject asset from which the runtime object has been created
|
|
|
|
[SerializeReference]
|
|
public List<Nucleus> nuclei = new();
|
|
|
|
|
|
public virtual Nucleus output => this.nuclei[0] as Nucleus;
|
|
|
|
public List<Nucleus> _inputs = null;
|
|
public virtual List<Nucleus> inputs {
|
|
get {
|
|
if (this._inputs == null) {
|
|
this._inputs = new();
|
|
foreach (Nucleus receptor in this.nuclei) {
|
|
if (receptor is Nucleus nucleus) {
|
|
// inputs have no incoming synapses yet.
|
|
if (nucleus.synapses.Count == 0)
|
|
this._inputs.Add(nucleus);
|
|
}
|
|
}
|
|
}
|
|
return this._inputs;
|
|
}
|
|
}
|
|
private List<Nucleus> _outputs = null;
|
|
public List<Nucleus> outputs {
|
|
get {
|
|
if (this._outputs == null)
|
|
RefreshOutputs();
|
|
return this._outputs;
|
|
}
|
|
}
|
|
public void RefreshOutputs() {
|
|
this._outputs = new();
|
|
foreach (Nucleus nucleus in this.nuclei) {
|
|
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
|
this._outputs.Add(nucleus);
|
|
}
|
|
}
|
|
|
|
public Nucleus GetNucleus(string nucleusName) {
|
|
foreach (Nucleus nucleus in this.nuclei) {
|
|
if (nucleus.name == nucleusName)
|
|
return nucleus;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Call this function to ensure that there is at least one nucleus
|
|
// This is an invariant and should be ensured before the nucleus is used
|
|
// because output requires it.
|
|
public void EnsureInitialization() {
|
|
nuclei ??= new List<Nucleus>();
|
|
if (nuclei.Count == 0)
|
|
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
|
}
|
|
|
|
public void GarbageCollection() {
|
|
HashSet<Nucleus> visitedNuclei = new();
|
|
foreach (Nucleus output in this.outputs)
|
|
MarkNuclei(visitedNuclei, output);
|
|
//MarkNuclei(visitedNuclei, this.output);
|
|
//Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
|
this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
|
|
}
|
|
|
|
public void MarkNuclei(HashSet<Nucleus> visitedNuclei, Nucleus nucleus) {
|
|
if (nucleus is null)
|
|
return;
|
|
|
|
if (nucleus.parent != null && nucleus.parent.prefab != this)
|
|
visitedNuclei.Add(nucleus.parent);
|
|
else
|
|
visitedNuclei.Add(nucleus);
|
|
if (nucleus.synapses != null) {
|
|
HashSet<Synapse> visitedSynapses = new();
|
|
foreach (Synapse synapse in nucleus.synapses) {
|
|
if (synapse != null && synapse.nucleus != null) {
|
|
visitedSynapses.Add(synapse);
|
|
if (synapse.nucleus is Nucleus synapse_nucleus)
|
|
MarkNuclei(visitedNuclei, synapse_nucleus);
|
|
}
|
|
}
|
|
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
|
}
|
|
if (nucleus is Neuron neuron && neuron.receivers != null) {
|
|
HashSet<Nucleus> visitedReceivers = new();
|
|
foreach (Nucleus receiver in neuron.receivers) {
|
|
if (receiver != null && receiver != null) {
|
|
visitedReceivers.Add(receiver);
|
|
visitedNuclei.Add(receiver);
|
|
}
|
|
}
|
|
neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
|
}
|
|
}
|
|
|
|
public virtual void UpdateNuclei() {
|
|
foreach (Nucleus nucleus in this.nuclei)
|
|
nucleus.UpdateNuclei();
|
|
}
|
|
|
|
public int GetNucleusIndex(Nucleus receiver) {
|
|
int ix = 0;
|
|
foreach (Nucleus nucleus in this.nuclei) {
|
|
if (receiver == nucleus)
|
|
return ix;
|
|
ix++;
|
|
}
|
|
return -1;
|
|
}
|
|
} |