public DirectionControllerSphere(EditorOptions options, ItemOptions itemOptions, ShipPartDNA dna, IContainer energyTanks, Thruster[] thrusters, ImpulseEngine[] impulseEngines) : base(options, dna, itemOptions.DirectionController_Damage.HitpointMin, itemOptions.DirectionController_Damage.HitpointSlope, itemOptions.DirectionController_Damage.Damage) { _itemOptions = itemOptions; _energyTanks = energyTanks; _thrusters = thrusters; _impulseEngines = impulseEngines; this.Design = new DirectionControllerSphereDesign(options, true); this.Design.SetDNA(dna); double radius; DirectionControllerRing.GetMass(out _mass, out _volume, out radius, out _scaleActual, dna, itemOptions, false); this.Radius = radius; #region neurons double area = Math.Pow(radius, itemOptions.DirectionController_Sphere_NeuronGrowthExponent); int neuronCount = Convert.ToInt32(Math.Ceiling(itemOptions.DirectionController_Sphere_NeuronDensity_Half * area)); if (neuronCount == 0) { neuronCount = 1; } _neuronsLinear = NeuralUtility.CreateNeuronShell_Sphere(1, neuronCount); _neuronsRotation = NeuralUtility.CreateNeuronShell_Sphere(.4, neuronCount); _neurons = _neuronsLinear.Neurons. Concat(_neuronsRotation.Neurons). ToArray(); #endregion }
private static Neuron_SensorPosition[] CreateNeurons(ShipPartDNA dna, ItemOptions itemOptions, double neuronDensity, bool ignoreSetValue) { #region Calculate Counts // Figure out how many to make //NOTE: This radius isn't taking SCALE into account. The other neural parts do this as well, so the neural density properties can be more consistent double radius = (dna.Scale.X + dna.Scale.Y) / (2d * 2d); // XY should always be the same anyway (not looking at Z for this. Z is just to keep the sensors from getting too close to each other) double area = Math.Pow(radius, itemOptions.Sensor_NeuronGrowthExponent); int neuronCount = Convert.ToInt32(Math.Ceiling(neuronDensity * area)); if (neuronCount == 0) { neuronCount = 1; } #endregion // Place them evenly in a ring // I don't want a neuron in the center, so placing a static point there to force the neurons away from the center Vector3D[] positions = NeuralUtility.GetNeuronPositions_CircularShell_Even(dna.Neurons, neuronCount, radius); //why 2D? // Exit Function return(positions. Select(o => new Neuron_SensorPosition(o.ToPoint(), true, ignoreSetValue)). ToArray()); }
public static Neuron_SensorPosition[] CreateNeurons(ShipPartDNA dna, ItemOptions itemOptions, double neuronDensity) { // Figure out how many to make //NOTE: This radius isn't taking SCALE into account. The other neural parts do this as well, so the neural density properties can be more consistent double radius = (dna.Scale.X + dna.Scale.Y + dna.Scale.Z) / (3d * 2d); // xyz should all be the same anyway double volume = Math.Pow(radius, itemOptions.Sensor_NeuronGrowthExponent); int count = Convert.ToInt32(Math.Ceiling(neuronDensity * volume)); if (count == 0) { count = 1; } // Place them evenly in a sphere //NOTE: An interesting side effect of calling this for each generation is that the parent may not have been perfectly evenly spaced, but calling this //again will slightly refine the positions Vector3D[] positions = NeuralUtility.GetNeuronPositions_Spherical_Even(dna.Neurons, count, radius); //TODO: Remove this, it's now done in getmass // The radius exposed through the neuron container interface needs to be reduced to actual size //radius *= SensorGravityDesign.SIZEPERCENTOFSCALE; return(positions. Select(o => new Neuron_SensorPosition(o.ToPoint(), true)). ToArray()); }
internal static Neuron_SensorPosition[] CreateNeurons(ShipPartDNA dna, ItemOptions itemOptions, double neuronDensity, bool hasHoleInMiddle, bool ignoreSetValue) { var count = GetNeuronCount(dna.Scale, itemOptions.Sensor_NeuronGrowthExponent, neuronDensity); Point3D[] staticPositions = null; if (hasHoleInMiddle) { staticPositions = new Point3D[] { new Point3D(0, 0, 0) }; } // Place them evenly within a circle. // I don't want a neuron in the center, so placing a static point there to force the neurons away from the center Vector3D[] positions = NeuralUtility.GetNeuronPositions_Circular_Even(dna.Neurons, staticPositions, 1d, count.neuronCount, count.radius); return(positions. Select(o => new Neuron_SensorPosition(o.ToPoint(), true, ignoreSetValue)). ToArray()); }
private static Neuron_NegPos[] CreateNeurons(ShipPartDNA dna, ItemOptions itemOptions, Point3D[] brainChemicalPositions) { // Figure out how many to make GetNeuronVolume(out double radius, out double volume, dna, itemOptions); int count = Convert.ToInt32(Math.Round(itemOptions.Brain_NeuronDensity * volume)); if (count == 0) { count = 1; } // Figure out the positions Vector3D[] positions = NeuralUtility.GetNeuronPositions_Spherical_Cluster(dna.Neurons, brainChemicalPositions, 3d, count, radius, itemOptions.Brain_NeuronMinClusterDistPercent); return(positions. Select(o => new Neuron_NegPos(o.ToPoint())). ToArray()); }
private static (Neuron_SensorPosition rot_dirspeed, Neuron_SensorPosition rot_radius, Neuron_SensorPosition[] linear) CreateNeurons(ShipPartDNA dna, ItemOptionsArco itemOptions) { #region ring - linear // Figure out how many to make //NOTE: This radius isn't taking SCALE into account. The other neural parts do this as well, so the neural density properties can be more consistent double radius = (dna.Scale.X + dna.Scale.Y) / (2d * 2d); // XY should always be the same anyway (not looking at Z for this. Z is just to keep the sensors from getting too close to each other) double area = Math.Pow(radius, itemOptions.MotionController2_NeuronGrowthExponent); int neuronCount = (area * itemOptions.MotionController2_NeuronDensity).ToInt_Ceiling(); neuronCount += 2; // manually add two for the rotation neruons if (neuronCount < 7) { neuronCount = 7; } var neuronPositions = SplitNeuronPositions(dna.Neurons); // Place them evenly around the perimiter of a circle. Vector3D[] linearPositions = NeuralUtility.GetNeuronPositions_CircularShell_Even(neuronPositions?.linear, neuronCount, radius); Neuron_SensorPosition[] linearNeurons = linearPositions. Select(o => new Neuron_SensorPosition(o.ToPoint(), true, false)). ToArray(); #endregion #region interior - rotation Neuron_SensorPosition rotateDirSpeed = new Neuron_SensorPosition(new Point3D(-.25, 0, 0), false, false); Neuron_SensorPosition rotateRadius = new Neuron_SensorPosition(new Point3D(.25, 0, 0), true, false); #endregion return ( rotateDirSpeed, rotateRadius, linearNeurons ); }
private static NeuronLayer[] CreateNeurons_Layers(SensorVisionDNA dna, ItemOptionsArco itemOptions) { if (dna.Filters == null || dna.Filters.Length == 0) { throw new ApplicationException("This method requires filters to be populated"); } var count = GetNeuronCount(dna.Scale, itemOptions.Sensor_NeuronGrowthExponent, itemOptions.VisionSensor_NeuronDensity); //TODO: SensorVisionFilterType.Bot will need two layers var neuronZs = GetNeuron_Zs(dna.Filters.Length, count.radius); Point3D[] staticPositions = new Point3D[] { new Point3D(0, 0, 0) }; Point3D[] singlePlate = null; if (dna.Neurons != null && dna.Neurons.Length > 0) { var byLayer = NeuralUtility.DivideNeuronLayersIntoSheets(dna.Neurons, neuronZs.z, count.neuronCount); // Just use one of the layer's positions to re evenly distribute (first layer with the correct number of neurons - or closest number). // Could try to find the nearest between each layer and use the average of each set, but that's a lot of expense with very little payoff singlePlate = GetBestNeuronSheet(byLayer, count.neuronCount); } // Make sure there is a correct number of neurons and apply an even distribution singlePlate = NeuralUtility.GetNeuronPositions_Circular_Even(singlePlate, staticPositions, 1d, count.neuronCount, count.radius). Select(o => o.ToPoint()). ToArray(); // Use the location of neurons in this single layer for all layers. By making sure that each neuron represents the same point in each // layer (and the index of that neuron is the same in each layer), position logic in each tick can be optimized return(Enumerable.Range(0, dna.Filters.Length). Select(o => new NeuronLayer() { FilterType = dna.Filters[o], Z = neuronZs.z[o], Neurons = singlePlate. Select(p => new Neuron_SensorPosition(new Point3D(p.X, p.Y, neuronZs.z[o]), true, true)). ToArray(), }). ToArray()); }
public virtual ShipDNA GetNewDNA() { // Create dna for each part using that part's current stats List <ShipPartDNA> dnaParts = new List <ShipPartDNA>(); foreach (PartBase part in _parts.AllPartsArray) { ShipPartDNA dna = part.GetNewDNA(); if (_neuronLinks != null && part is INeuronContainer) { NeuralUtility.PopulateDNALinks(dna, (INeuronContainer)part, _neuronLinks); } dnaParts.Add(dna); } // Build the ship dna return(ShipDNA.Create(_dna, dnaParts)); }
private static Neuron_SensorPosition[] CreateNeurons(ShipPartDNA dna, ItemOptions itemOptions, double neuronDensity, bool ignoreSetValue) { #region calculate counts // Figure out how many to make //NOTE: This radius isn't taking SCALE into account. The other neural parts do this as well, so the neural density properties can be more consistent double radius = Math1D.Avg(dna.Scale.X, dna.Scale.Y, dna.Scale.Z) / 2d; // dividing by 2, because radius is wanted, not diameter double area = Math.Pow(radius, itemOptions.Sensor_NeuronGrowthExponent); int neuronCount = (neuronDensity * area).ToInt_Ceiling(); neuronCount = Math.Max(neuronCount, 10); #endregion // Place them evenly on the surface of a sphere Vector3D[] positions = NeuralUtility.GetNeuronPositions_SphericalShell_Even(dna.Neurons, neuronCount, radius); return(positions. Select(o => new Neuron_SensorPosition(o.ToPoint(), true, ignoreSetValue)). ToArray()); }
private static Neuron_Fade[] CreateBrainChemicals(ShipPartDNA dna, ItemOptions itemOptions) { const double K_UP = 50d; const double K_DOWN = 750d; const double VALUECUTOFF = .75d; // Figure out how many to make double radius, volume; GetNeuronVolume(out radius, out volume, dna, itemOptions); int count = Convert.ToInt32(Math.Round(itemOptions.Brain_ChemicalDensity * volume)); if (count == 0) { return(new Neuron_Fade[0]); } // The brain chemicals are stored in dna.AltNeurons Point3D[] brainChemPositions = null; if (dna.AltNeurons != null && dna.AltNeurons.Length > 0) { if (dna.AltNeurons.Length != 1) { throw new ApplicationException("dna.AltNeurons.Length should be exactly 1 (" + dna.AltNeurons.Length.ToString() + ")"); } brainChemPositions = dna.AltNeurons[0]; } // Figure out the positions //NOTE: Only let them go to half radius. Cluster% then needs to be doubled (doubling it again so that the brain chemicals don't get //too close together) Vector3D[] positions = NeuralUtility.GetNeuronPositions_Spherical_Cluster(brainChemPositions, count, radius * .5d, itemOptions.Brain_NeuronMinClusterDistPercent * 4d); // Exit Function return(positions.Select(o => new Neuron_Fade(o.ToPoint(), K_UP, K_DOWN, VALUECUTOFF)).ToArray()); }
/// <summary> /// This overload is for bots that don't derive from ship, but do contain parts. This will show the parts, and wont' show /// any ship specific visuals /// </summary> public ShipViewerWindow(PartBase[] parts, NeuralUtility.ContainerOutput[] neuronLinks) { InitializeComponent(); _bot = null; _parts = parts; _neuronLinks = neuronLinks; var aabb = PartBase.GetAABB(_parts); Constructor_Finish(aabb); }