DiamondContact.cs
using System;
using System.Collections.Generic;
using static Diamonds.DiamondBoard;

namespace Diamonds;

/// <summary>Lower faces touching external supports at the instant of a vertical landing.</summary>
public static class DiamondContact
{
	[Flags]
	public enum Faces { None = 0, LowerLeft = 1, LowerRight = 2, Corner = 4 }
	const float Tolerance = 0.02f;

	public static Faces Find( IEnumerable<Diamond> moving, IReadOnlyList<Diamond> stationary, ISet<int> excluded = null, bool fillCornerPockets = true )
	{
		Faces faces = Faces.None;
		foreach ( var cell in moving )
		{
			if ( MathF.Abs( cell.Y - FloorY( cell.Lane ) ) <= Tolerance )
			{
				float phase = cell.Lane % 2;
				// Even lanes nest in a valley; odd lanes balance tip-on-peak.
				if ( MathF.Min( phase, 2 - phase ) * Width * 0.5f <= Tolerance )
					faces |= Faces.LowerLeft | Faces.LowerRight;
				else if ( MathF.Abs( phase - 1 ) * Width * 0.5f <= Tolerance )
					faces |= Faces.Corner;
				else faces |= phase < 1 ? Faces.LowerRight : Faces.LowerLeft;
			}
			// Visit the two sources directly: materializing Concat().ToArray() here
			// allocates per contact and first-use JITs the generic LINQ array builder.
			for ( int i = 0; i < stationary.Count; i++ )
			{
				if ( excluded?.Contains( i ) == true ) continue;
				faces |= SupportFace( cell, stationary[i] );
			}
			int boundaryIndex = stationary.Count;
			foreach ( var support in BoundaryDiamonds( fillCornerPockets ) )
			{
				if ( excluded?.Contains( boundaryIndex++ ) == true ) continue;
				faces |= SupportFace( cell, support );
			}
		}
		return faces;
	}

	static Faces SupportFace( Diamond cell, Diamond support )
	{
		float dx = (support.Lane - cell.Lane) * Width * 0.5f;
		float dy = support.Y - cell.Y;
		// Ignore side tips, supports above us, and anything not actually touching.
		if ( dy <= Tolerance || MathF.Abs( dx ) >= Width - Tolerance ) return Faces.None;
		float gap = dy - Height * (1 - MathF.Abs( dx ) / Width);
		if ( MathF.Abs( gap ) > Tolerance ) return Faces.None;
		return MathF.Abs( dx ) <= Tolerance ? Faces.Corner : dx < 0 ? Faces.LowerLeft : Faces.LowerRight;
	}
}