Skip to content

Commit 2bcd594

Browse files
committed
Fixed several issues with the implementation
1 parent c1900d3 commit 2bcd594

File tree

5 files changed

+77
-65
lines changed

5 files changed

+77
-65
lines changed

src/auto-evo/RunResults.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ public void ApplyResults(GameWorld world, bool skipMutations)
440440

441441
if (!skipMutations && entry.Value.MutatedProperties != null)
442442
{
443+
if (entry.Key is MicrobeSpecies microbe)
444+
microbe.Organelles.Approve();
445+
443446
entry.Key.ApplyMutation(entry.Value.MutatedProperties);
444447
}
445448

src/auto-evo/mutation_strategy/MoveOrganelleBack.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ public MoveOrganelleBack(Func<OrganelleDefinition, bool> criteria)
2828
var workMemory2 = new List<Hex>();
2929
var workMemory3 = new HashSet<Hex>();
3030

31-
foreach (OrganelleTemplate organelle in baseSpecies.Organelles.Where(x => allOrganelles.Contains(x.Definition)))
31+
int organelleCount = baseSpecies.Organelles.Count;
32+
for (int i = 0; i < organelleCount; i++)
3233
{
33-
MicrobeSpecies newSpecies = (MicrobeSpecies)baseSpecies.Clone();
34+
var organelle = baseSpecies.Organelles[i];
35+
36+
if (!allOrganelles.Contains(organelle.Definition))
37+
continue;
3438

39+
MicrobeSpecies newSpecies = (MicrobeSpecies)baseSpecies.Clone();
3540
newSpecies.Organelles.Remove(organelle);
3641

3742
if (CommonMutationFunctions.AddOrganelle(organelle.Definition, CommonMutationFunctions.Direction.Rear,
3843
newSpecies, workMemory1, workMemory2, workMemory3, random))
3944
{
40-
// Add mutation attempt only if was able to place the organelle
41-
// TODO: maybe this should add the attempt anyway as this may act as a separate remove organelle step
42-
// for things that cannot be moved?
4345
mutated.Add(Tuple.Create(newSpecies, mp - Constants.ORGANELLE_MOVE_COST));
4446
}
4547
}

src/auto-evo/steps/ModifyExistingSpecies.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public bool RunStep(RunResults results)
169169
bool isEqual = m.ParentSpecies == m.MutatedSpecies;
170170

171171
if (isEqual)
172-
m.MutatedSpecies.Organelles.Approve(false);
172+
m.MutatedSpecies.Organelles.Reject();
173173

174174
return isEqual;
175175
});
@@ -180,7 +180,7 @@ public bool RunStep(RunResults results)
180180
while (mutationsToTry.Count > TotalMutationsToTry)
181181
{
182182
var toRemove = mutationsToTry[^1];
183-
toRemove.MutatedSpecies.Organelles.Approve(false);
183+
toRemove.MutatedSpecies.Organelles.Reject();
184184

185185
mutationsToTry.RemoveAt(mutationsToTry.Count - 1);
186186
}
@@ -241,10 +241,12 @@ public bool RunStep(RunResults results)
241241
new KeyValuePair<Patch, long>(patch, newPopulation), mutation.AddType,
242242
mutation.ParentSpecies);
243243

244-
mutation.MutatedSpecies.Organelles.Approve(true);
244+
mutation.MutatedSpecies.Organelles.Approve();
245+
}
246+
else
247+
{
248+
mutation.MutatedSpecies.Organelles.Reject();
245249
}
246-
247-
mutation.MutatedSpecies.Organelles.Approve(false);
248250
}
249251

250252
return true;

src/general/HexLayout.cs

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public HexLayout()
4242

4343
public HexLayout(List<T> hexes)
4444
{
45-
existingHexes = new HexLayoutView(hexes, true, false);
45+
existingHexes = new HexLayoutView(hexes, true, true);
4646
}
4747

4848
/// <summary>
@@ -325,18 +325,16 @@ public bool Contains(T item)
325325
return existingHexes.Contains(item);
326326
}
327327

328-
public void Approve(bool isApproved = true)
328+
public void Approve()
329329
{
330-
if (isApproved)
331-
{
332-
existingHexes.Commit(false);
333-
}
334-
else
335-
{
336-
// This species will probably be discarded by auto-evo in this situation, so this returns the allocated
337-
// memory to the pool.
338-
existingHexes.Drop();
339-
}
330+
existingHexes.Commit(false);
331+
}
332+
333+
public void Reject()
334+
{
335+
// This species will probably be discarded by auto-evo in this situation, so this returns the allocated
336+
// memory to the pool.
337+
existingHexes.Drop();
340338
}
341339

342340
// TODO: remove this bit of boxing here. https://nede.dev/blog/preventing-unnecessary-allocation-in-net-collections
@@ -488,12 +486,11 @@ protected struct HexLayoutView : IReadOnlyList<T>
488486
private const int MEMORY_ALLOC_SIZE = 16;
489487

490488
private T?[]? diffHexes;
491-
private int diffIndex;
489+
private int diffIndex = 0;
492490

493491
public HexLayoutView(List<T> parent, bool shared, bool initDiffHexes = false)
494492
{
495493
MainHexes = parent;
496-
497494
Shared = shared;
498495

499496
if (initDiffHexes)
@@ -516,8 +513,7 @@ public T this[int index]
516513
{
517514
var item = diffHexes[pendingIndex];
518515

519-
return item is null ? throw new ArgumentOutOfRangeException(nameof(index), "Out of range.") :
520-
diffHexes[pendingIndex]!;
516+
return item ?? throw new ArgumentOutOfRangeException(nameof(index), "Out of range.");
521517
}
522518
}
523519

@@ -550,19 +546,15 @@ public void Add(T item)
550546
if (diffHexes == null)
551547
{
552548
// No diff hexes, so we add directly to the layout.
553-
if (Shared)
554-
{
555-
// This is a shared hex layout. Since we're diverging from it, we need to allocate a brand-new list.
556549

557-
MainHexes = [];
558-
Shared = false;
559-
}
550+
// This is a shared hex layout. Since we're diverging from it, we need to allocate a brand-new list.
551+
IsolateIfShared();
560552

561553
MainHexes.Add(item);
562554
return;
563555
}
564556

565-
if (diffIndex == diffHexes.Length - 1)
557+
if (diffIndex == diffHexes.Length)
566558
{
567559
ArrayPool<T?>.Shared.Resize(ref diffHexes, diffHexes.Length + MEMORY_ALLOC_SIZE);
568560
}
@@ -572,53 +564,40 @@ public void Add(T item)
572564

573565
public void Remove(T item)
574566
{
575-
if (diffHexes == null)
567+
if (diffHexes != null)
576568
{
577-
if (Shared)
569+
for (int i = 0; i < diffIndex; ++i)
578570
{
579-
MainHexes = [];
580-
Shared = false;
581-
}
571+
if (!ReferenceEquals(item, diffHexes[i]))
572+
continue;
582573

583-
MainHexes.Remove(item);
584-
return;
574+
diffHexes[i] = diffHexes[--diffIndex];
575+
diffHexes[diffIndex] = null;
576+
return;
577+
}
585578
}
586579

587-
for (int i = 0; i < diffIndex; ++i)
588-
{
589-
var toTest = diffHexes[i];
580+
IsolateIfShared();
590581

591-
if (!ReferenceEquals(item, toTest))
592-
continue;
593-
594-
diffHexes[i] = diffHexes[--diffIndex];
595-
diffHexes[diffIndex] = null;
596-
597-
break;
598-
}
582+
MainHexes.Remove(item);
599583
}
600584

601585
/// <summary>
602586
/// This method clears the diff layout and loads the modifications into the permanent layout.
603587
/// </summary>
604588
/// <remarks>
605-
/// <para>
606-
/// This is the method that allocates memory. Only when this is called and the diff is not empty the
607-
/// organelles get deep cloned.
608-
/// </para>
609-
/// </remarks>>
610-
/// <returns>true if this layout was in diff mode.</returns>>
589+
/// <para>
590+
/// This is the method that allocates memory. Only when this is called and the diff is not empty the
591+
/// organelles get deep cloned.
592+
/// </para>
593+
/// </remarks>
594+
/// <returns>true if this layout was in diff mode.</returns>
611595
public bool Commit(bool reallocate)
612596
{
613597
if (diffHexes is null || diffIndex == 0)
614598
return false;
615599

616-
if (Shared)
617-
{
618-
// Mark this not as shared now and allocate a new list.
619-
MainHexes = new List<T>(MainHexes);
620-
Shared = false;
621-
}
600+
IsolateIfShared();
622601

623602
for (int i = 0; i < diffIndex; ++i)
624603
{
@@ -644,12 +623,32 @@ public bool Commit(bool reallocate)
644623
return true;
645624
}
646625

626+
public void IsolateIfShared()
627+
{
628+
if (!Shared)
629+
return;
630+
631+
var count = MainHexes.Count;
632+
var newList = new List<T>(count);
633+
634+
for (int i = 0; i < count; i++)
635+
{
636+
newList.Add((T)((ICloneable)MainHexes[i]).Clone());
637+
}
638+
639+
MainHexes = newList;
640+
Shared = false;
641+
}
642+
647643
public void Drop()
648644
{
649645
if (diffHexes is null)
650646
return;
651647

652648
ArrayPool<T?>.Shared.Return(diffHexes, true);
649+
650+
diffHexes = null;
651+
diffIndex = 0;
653652
}
654653

655654
public IEnumerator<T> GetEnumerator()
@@ -662,7 +661,7 @@ public IEnumerator<T> GetEnumerator()
662661
if (diffHexes == null)
663662
yield break;
664663

665-
for (int i = 0; i < diffHexes.Length; ++i)
664+
for (int i = 0; i < diffIndex; ++i)
666665
{
667666
var item = diffHexes[i];
668667

src/microbe_stage/OrganelleLayout.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/// </summary>
1111
/// <typeparam name="T">The type of organelle contained in this layout</typeparam>
1212
public class OrganelleLayout<T> : HexLayout<T>, IArchivable, IReadOnlyOrganelleLayout<T>
13-
where T : class, IPositionedOrganelle, ICloneable
13+
where T : class, IPositionedOrganelle
1414
{
1515
public OrganelleLayout(Action<T> onAdded, Action<T>? onRemoved = null) : base(onAdded, onRemoved)
1616
{
@@ -156,6 +156,12 @@ public bool RepositionToOrigin()
156156
if (centerOfMass.Q == 0 && centerOfMass.R == 0)
157157
return false;
158158

159+
// The following repositioning is unsafe to share, so let's isolate.
160+
// TODO:
161+
// Maybe, instead of this, use an offset Hex in the iterator and adjust the positions on-fly instead of
162+
// allocating?
163+
existingHexes.IsolateIfShared();
164+
159165
foreach (var organelle in Organelles)
160166
{
161167
// This calculation aligns the center of mass with the origin by moving every organelle of the microbe.

0 commit comments

Comments
 (0)