87 lines
3.4 KiB
C#
87 lines
3.4 KiB
C#
using OECS;
|
|
|
|
namespace Game.Blackjack;
|
|
|
|
/// <summary>
|
|
/// Creates the deck (52 cards + deck/hand entities) and shuffles
|
|
/// using mulberry32 with the seed from the GameState singleton.
|
|
/// Runs once at the start of each round (during Dealing phase).
|
|
/// </summary>
|
|
public class DeckSetupSystem : ISystem
|
|
{
|
|
public void Run(World world)
|
|
{
|
|
var state = world.ReadSingleton<GameState>();
|
|
if (state.Phase != GamePhase.Dealing)
|
|
return;
|
|
|
|
// Only create deck entities if they don't exist yet.
|
|
var singletonEntity = World.SingletonEntity;
|
|
bool hasDeck = false;
|
|
using (var iter = world.Select<Deck>())
|
|
{
|
|
hasDeck = iter.MoveNext() && iter.CurrentEntity != singletonEntity;
|
|
}
|
|
|
|
if (!hasDeck)
|
|
{
|
|
// Create deck entity.
|
|
var deckEntity = world.CreateEntity();
|
|
world.AddComponent(deckEntity, new Deck());
|
|
|
|
// Create all 52 cards.
|
|
foreach (Suit suit in Enum.GetValues<Suit>())
|
|
{
|
|
foreach (Rank rank in Enum.GetValues<Rank>())
|
|
{
|
|
var cardEntity = world.CreateEntity();
|
|
world.AddComponent(cardEntity, new Card { Suit = suit, Rank = rank });
|
|
world.AddComponent(cardEntity, new InDeck { Target = deckEntity });
|
|
}
|
|
}
|
|
|
|
// Create hand entities.
|
|
var playerHand = world.CreateEntity();
|
|
world.AddComponent(playerHand, new PlayerHand());
|
|
|
|
var dealerHand = world.CreateEntity();
|
|
world.AddComponent(dealerHand, new DealerHand());
|
|
}
|
|
|
|
// Shuffle the deck using mulberry32 with the current seed.
|
|
ref var mutableState = ref world.GetSingleton<GameState>();
|
|
var deckEntity2 = HitCommand.FindEntity<Deck>(world, singletonEntity);
|
|
var cards = world.GetSources<InDeck>(deckEntity2).ToArray();
|
|
Shuffle(world, deckEntity2, cards, ref mutableState.Seed);
|
|
}
|
|
|
|
private static void Shuffle(World world, Entity deckEntity, Entity[] cardEntities, ref uint seed)
|
|
{
|
|
// Fisher-Yates shuffle using mulberry32.
|
|
for (int i = cardEntities.Length - 1; i > 0; i--)
|
|
{
|
|
int j = Mulberry32.NextInt(ref seed, 0, i);
|
|
|
|
// Swap the InDeck relationship targets (cards are always in the deck,
|
|
// so there's nothing to swap except the cards themselves — but we
|
|
// shuffle the card order conceptually by removing and re-adding
|
|
// InDeck components in shuffled order). Actually, since InDeck
|
|
// is just a tag, we just re-shuffle the order in the source collection.
|
|
// The simplest approach: no need to swap component data; we just
|
|
// need to ensure the cards are iterated in shuffled order.
|
|
// We'll swap the card entities in the array.
|
|
(cardEntities[i], cardEntities[j]) = (cardEntities[j], cardEntities[i]);
|
|
}
|
|
|
|
// Now remove all InDeck and re-add in shuffled order so GetSources
|
|
// returns them in shuffled order.
|
|
for (int i = cardEntities.Length - 1; i >= 0; i--)
|
|
{
|
|
world.RemoveComponent<InDeck>(cardEntities[i]);
|
|
}
|
|
for (int i = 0; i < cardEntities.Length; i++)
|
|
{
|
|
world.AddComponent(cardEntities[i], new InDeck { Target = deckEntity });
|
|
}
|
|
}
|
|
} |