/// <summary> /// Gets the readable neurons from the containers of the type requested (and skips the current container) /// </summary> private static List<Tuple<ContainerInput, List<INeuron>, double>> BuildExternalLinksRandom_Continue_Eligible(BotConstruction_PartMap partMap, NeuronContainerType containerType, int currentIndex, ContainerInput[] containers, List<INeuron>[] readable) { var retVal = new List<Tuple<ContainerInput, List<INeuron>, double>>(); for (int cntr = 0; cntr < containers.Length; cntr++) { if (cntr == currentIndex) { continue; } if (containers[cntr].ContainerType != containerType) { continue; } double? weight = null; foreach (var mapped in partMap.Actual) { if ((mapped.Item1.Token == containers[currentIndex].Token && mapped.Item2.Token == containers[cntr].Token) || (mapped.Item2.Token == containers[currentIndex].Token && mapped.Item1.Token == containers[cntr].Token)) { weight = mapped.Item3; break; } } if (weight == null) { // The map doesn't hold a link between these two containers continue; } retVal.Add(Tuple.Create(containers[cntr], readable[cntr], weight.Value)); } return retVal; }
private static NeuralLink[][] BuildExternalLinksRandom(BotConstruction_PartMap partMap, ContainerInput[] containers, double maxWeight) { NeuralLink[][] retVal = new NeuralLink[containers.Length][]; // Pull out the readable nodes from each container List<INeuron>[] readable = BuildExternalLinksRandom_FindReadable(containers); // Shoot through each container, and create links that feed it for (int cntr = 0; cntr < containers.Length; cntr++) { ContainerInput container = containers[cntr]; if (container.ExternalRatios == null || container.ExternalRatios.Length == 0) { // This container shouldn't be fed by other containers (it's probably a sensor) retVal[cntr] = null; continue; } // Find writable nodes List<INeuron> writeable = new List<INeuron>(); writeable.AddRange(container.Container.Neruons_ReadWrite); writeable.AddRange(container.Container.Neruons_Writeonly); if (writeable.Count == 0) { // There are no nodes that can be written retVal[cntr] = null; continue; } List<NeuralLink> links = new List<NeuralLink>(); foreach (var ratio in container.ExternalRatios) { // Link to this container type links.AddRange(BuildExternalLinksRandom_Continue(partMap, containers, cntr, ratio, readable, writeable, maxWeight)); } // Add links to the return jagged array if (links.Count == 0) { retVal[cntr] = null; } else { retVal[cntr] = links.ToArray(); } } // Exit Function return retVal; }
private static List<NeuralLink> BuildExternalLinksRandom_Continue(BotConstruction_PartMap partMap, ContainerInput[] containers, int currentIndex, Tuple<NeuronContainerType, ExternalLinkRatioCalcType, double> ratio, List<INeuron>[] readable, List<INeuron> writeable, double maxWeight) { List<NeuralLink> retVal = new List<NeuralLink>(); // Find eligible containers var matchingInputs = BuildExternalLinksRandom_Continue_Eligible(partMap, ratio.Item1, currentIndex, containers, readable); if (matchingInputs.Count == 0) { return retVal; } // Add up all the eligible neurons int sourceNeuronCount = matchingInputs.Sum(o => o.Item2.Count); double multiplier = matchingInputs.Average(o => o.Item3); multiplier *= ratio.Item3; // Figure out how many to create (this is the total count. Each feeder container will get a percent of these based on its ratio of // neurons compared to the other feeders) int count = BuildExternalLinks_Count(ratio.Item2, sourceNeuronCount, writeable.Count, multiplier); if (count == 0) { return retVal; } // I don't want to draw so evenly from all the containers. Draw from all containers at once. This will have more clumping, and some containers // could be completely skipped. // // My reasoning for this is manipulators like thrusters don't really make sense to be fed evenly from every single sensor. Also, thruster's count is by // destination neuron, which is very small. So fewer total links will be created by doing just one pass List<Tuple<int, int>> inputLookup = new List<Tuple<int, int>>(); for (int outer = 0; outer < matchingInputs.Count; outer++) { for (int inner = 0; inner < matchingInputs[outer].Item2.Count; inner++) { //Item1 = index into matchingInputs //Item2 = index into neuron inputLookup.Add(new Tuple<int, int>(outer, inner)); } } // For now, just build completely random links //NOTE: This is ignoring the relative weights in the map passed in. Those weights were used to calculate how many total links there should be Tuple<int, int, double>[] links = GetRandomLinks(inputLookup.Count, writeable.Count, count, Enumerable.Range(0, inputLookup.Count).ToArray(), Enumerable.Range(0, writeable.Count).ToArray(), new SortedList<int, int>(), maxWeight); foreach (var link in links) { // link.Item1 is the from neuron. But all the inputs were put into a single list, so use the inputLookup to figure out which container/neuron // is being referenced var input = matchingInputs[inputLookup[link.Item1].Item1]; int neuronIndex = inputLookup[link.Item1].Item2; double[] brainChemicals = GetBrainChemicalModifiers(input.Item1, maxWeight); // the brain chemicals are always based on the from container (same in NeuralOperation.Tick) retVal.Add(new NeuralLink(input.Item1.Container, containers[currentIndex].Container, input.Item2[neuronIndex], writeable[link.Item2], link.Item3, brainChemicals)); } // Exit Function return retVal; }
/// <summary> /// This overload takes a map that tells which parts can link to which /// </summary> public static ContainerOutput[] LinkNeurons(BotConstruction_PartMap partMap, ContainerInput[] containers, double maxWeight) { //TODO: Take these as params (these are used when hooking up existing links) const int MAXINTERMEDIATELINKS = 3; const int MAXFINALLINKS = 3; NeuralLink[][] internalLinks, externalLinks; if (containers.Any(o => o.ExternalLinks != null || o.InternalLinks != null)) { internalLinks = BuildInternalLinksExisting(containers, MAXINTERMEDIATELINKS, MAXFINALLINKS); externalLinks = BuildExternalLinksExisting(containers, MAXINTERMEDIATELINKS, MAXFINALLINKS); //NOTE: The partMap isn't needed for existing links. It is just to help figure out new random links internalLinks = CapWeights(internalLinks, maxWeight); externalLinks = CapWeights(externalLinks, maxWeight); } else { internalLinks = BuildInternalLinksRandom(containers, maxWeight); externalLinks = BuildExternalLinksRandom(partMap, containers, maxWeight); } // Build the return ContainerOutput[] retVal = new ContainerOutput[containers.Length]; for (int cntr = 0; cntr < containers.Length; cntr++) { retVal[cntr] = new ContainerOutput(containers[cntr].Container, internalLinks[cntr], externalLinks[cntr]); } // Exit Function return retVal; }