Represents a host-only shuffled stack of card face indices (a "shoe"). It builds a list of face indices from a DeckDefinition or accepts a preset order, supports shuffling on construction, and deals cards via Draw(), returning Card instances while tracking remaining count.
namespace CardGames;
/// <summary>
/// A runtime, host-only shuffled stack of cards (a "shoe"). The order is the authoritative
/// secret - it never leaves the host. Clients only ever learn a card once it's dealt and revealed.
/// </summary>
public sealed class Shoe
{
private readonly List<int> _cards = new();
private int _next;
public int Remaining => _cards.Count - _next;
public Shoe( DeckDefinition definition, int decks = 1 )
{
for ( int d = 0; d < decks; d++ )
for ( int i = 0; i < definition.Faces.Count; i++ )
_cards.Add( i );
Shuffle();
}
/// <summary>
/// A shoe that deals an exact, pre-set order of face indices (top first) - no shuffle. Used to set up
/// a known deal for debugging or tests (see <see cref="CardGame.RiggedDeal"/>).
/// </summary>
public Shoe( IReadOnlyList<int> order )
{
_cards.AddRange( order );
}
public Card Draw()
{
if ( Remaining <= 0 ) throw new InvalidOperationException( "Shoe is empty." );
return new Card( _cards[_next++] );
}
private void Shuffle()
{
var rng = new Random();
for ( int i = _cards.Count - 1; i > 0; i-- )
{
int j = rng.Next( i + 1 );
(_cards[i], _cards[j]) = (_cards[j], _cards[i]);
}
}
}