142 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace NanoBrain {
[Serializable]
public class ClusterArray : Nucleus {
public ClusterPrefab prefab;
public Cluster[] clusters;
public Dictionary<int, Cluster> thingClusters = new();
public ClusterArray(ClusterPrefab prefab, Cluster parent, int size, Nucleus receiver = null) {
this.prefab = prefab;
this.name = prefab.name;
this.clusters = new Cluster[size];
for (int ix = 0; ix < size; ix++) {
Cluster cluster = new(prefab, parent);
cluster.defaultOutput.AddReceiver(receiver);
cluster.clusterArray = this;
this.clusters[ix] = cluster;
}
}
public ClusterArray(ClusterPrefab prefab, ClusterPrefab parent, int size, Nucleus receiver = null) {
this.prefab = prefab;
this.name = prefab.name;
this.clusters = new Cluster[size];
for (int ix = 0; ix < size; ix++) {
Cluster cluster = new(prefab, parent);
cluster.defaultOutput.AddReceiver(receiver);
cluster.clusterArray = this;
this.clusters[ix] = cluster;
}
}
public override Nucleus ShallowCloneTo(Cluster parent) {
ClusterArray clone = new(this.prefab, parent, this.clusters.Length) {
clusterPrefab = this.clusterPrefab,
};
return clone;
}
public override Nucleus Clone(ClusterPrefab parent) {
ClusterArray clone = new(this.prefab, parent, this.clusters.Length) {
};
return clone;
}
public void Add(ClusterPrefab prefab) {
if (this.clusters.Length == 0) {
Debug.LogError("Empty perceptoid array, cannot add");
return;
}
int newLength = this.clusters.Length + 1;
Cluster[] newClusters = new Cluster[newLength];
string baseName = this.name;
int colonPos = baseName.IndexOf(":");
if (colonPos > 0)
baseName = baseName[..colonPos];
for (int i = 0; i < this.clusters.Length; i++)
newClusters[i] = this.clusters[i];
Cluster sourceCluster = this.clusters[0];
Cluster newCluster = sourceCluster.Clone(prefab) as Cluster;
newCluster.name = $"{baseName}: {newLength - 1}";
newCluster.clusterArray = this;
newClusters[newLength - 1] = newCluster;
this.clusters = newClusters;
}
public void Remove() {
int newLength = this.clusters.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
return;
}
Cluster[] newClusters = new Cluster[newLength];
for (int i = 0; i < newLength; i++)
newClusters[i] = this.clusters[i];
// Delete the last perception
//Cluster.Delete(nucleus);
this.clusters = newClusters;
}
public override void UpdateStateIsolated() {
// Clusters don't do anything,
// The nuclei in them do the work
// and should be called directly, not from the cluster
}
public virtual Cluster GetThingCluster() {
Cluster selectedCluster = SelectCluster();
return selectedCluster;
}
public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
return cluster;
Cluster selectedCluster = SelectCluster();
thingClusters[thingId] = selectedCluster;
return selectedCluster;
}
private Cluster SelectCluster() {
// Find a sleeping cluster
foreach (Cluster cluster in clusters) {
if (cluster.defaultOutput.isSleeping) {
RemoveThingCluster(cluster);
return cluster;
}
}
// Otherwise find the stalest cluster?
Cluster stalestCluster = clusters[0];
for (int ix = 1; ix < clusters.Length; ix++) {
if (clusters[ix].defaultOutput.stale > stalestCluster.defaultOutput.stale)
stalestCluster = clusters[ix];
}
RemoveThingCluster(stalestCluster);
return stalestCluster;
}
private void RemoveThingCluster(Cluster cluster) {
List<int> keysToRemove = new();
foreach (KeyValuePair<int, Cluster> kvp in thingClusters) {
if (kvp.Value == cluster)
keysToRemove.Add(kvp.Key);
}
foreach (int thingId in keysToRemove)
thingClusters.Remove(thingId);
}
}
}