feat(physics): Stage 1 — CellArray ordered/deduped cell collection (retail CELLARRAY)
Ports retail CELLARRAY::add_cell (acclient_2013_pseudo_c.txt:701036): ordered list, dedup by cell_id, append at end. The order is load-bearing for the verbatim find_cell_list current-cell-first interior-wins pick (next commits) that fixes the R1 cottage membership flap. Implements ICollection<uint> (helper-facing) + IReadOnlyCollection<uint> (consumer-facing). 5 unit tests. Also lands the membership-port pseudocode (workflow step 3) + the Stage-1 plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1438d73a43
commit
b44dd147bc
4 changed files with 992 additions and 0 deletions
56
src/AcDream.Core/Physics/CellArray.cs
Normal file
56
src/AcDream.Core/Physics/CellArray.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Ordered, deduped cell-id collection — a faithful model of retail's CELLARRAY
|
||||
/// (<c>CELLARRAY::add_cell</c> @ <c>acclient_2013_pseudo_c.txt:701036</c>: linear
|
||||
/// dedup by cell_id, append at the END, insertion order preserved). The order is
|
||||
/// load-bearing for <c>CObjCell::find_cell_list</c>'s current-cell-first,
|
||||
/// interior-wins pick (pc:308742) — the current cell is added at index 0 and the
|
||||
/// pick iterates in order, so the current cell wins a boundary straddle and the
|
||||
/// membership does not ping-pong (the R1 flap fix). Replaces the unordered
|
||||
/// <see cref="HashSet{T}"/> the candidate build used to use.
|
||||
///
|
||||
/// <para>Implements <see cref="ICollection{T}"/> (so the candidate-building
|
||||
/// helpers can take it where they used to take <c>HashSet<uint></c>) and
|
||||
/// <see cref="IReadOnlyCollection{T}"/> (so it satisfies the
|
||||
/// <c>out IReadOnlyCollection<uint></c> on <c>FindCellSet</c> and the
|
||||
/// <c>CheckOtherCells</c> / diagnostics consumers). Enumeration is always
|
||||
/// insertion order.</para>
|
||||
/// </summary>
|
||||
public sealed class CellArray : ICollection<uint>, IReadOnlyCollection<uint>
|
||||
{
|
||||
private readonly List<uint> _order = new();
|
||||
private readonly HashSet<uint> _seen = new();
|
||||
|
||||
public int Count => _order.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <summary>Ordered cell ids; index 0 is the cell added first (the current cell).</summary>
|
||||
public IReadOnlyList<uint> OrderedIds => _order;
|
||||
|
||||
/// <summary>Append <paramref name="id"/> iff not already present (retail add_cell dedup).</summary>
|
||||
public void Add(uint id)
|
||||
{
|
||||
if (_seen.Add(id))
|
||||
_order.Add(id);
|
||||
}
|
||||
|
||||
public bool Contains(uint id) => _seen.Contains(id);
|
||||
|
||||
public void Clear() { _order.Clear(); _seen.Clear(); }
|
||||
|
||||
public bool Remove(uint id)
|
||||
{
|
||||
if (!_seen.Remove(id)) return false;
|
||||
_order.Remove(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CopyTo(uint[] array, int arrayIndex) => _order.CopyTo(array, arrayIndex);
|
||||
|
||||
public IEnumerator<uint> GetEnumerator() => _order.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => _order.GetEnumerator();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue