148 lines
4.2 KiB
C#
148 lines
4.2 KiB
C#
using OECS;
|
||
|
||
namespace Blackjack;
|
||
|
||
/// <summary>
|
||
/// Renders the current game state to the console.
|
||
/// </summary>
|
||
public class RenderSystem : ISystem
|
||
{
|
||
public void Run(World world)
|
||
{
|
||
var state = world.ReadSingleton<GameState>();
|
||
|
||
Console.WriteLine();
|
||
Console.WriteLine(" Blackjack");
|
||
Console.WriteLine(" ═════════");
|
||
Console.WriteLine();
|
||
Console.WriteLine($" Chips: {state.Chips} | Round: {state.RoundNumber}");
|
||
Console.WriteLine();
|
||
|
||
// Show dealer's hand.
|
||
var dealerTotal = HandUtil.CalculateHand(world, DealerHandTag.Instance);
|
||
Console.Write(" Dealer: ");
|
||
if (state.Phase == GamePhase.PlayerTurn)
|
||
{
|
||
// Hide first card (hole card) during player's turn.
|
||
Console.Write("?? ");
|
||
PrintHand(world, DealerHandTag.Instance, skipFirst: true);
|
||
}
|
||
else
|
||
{
|
||
PrintHand(world, DealerHandTag.Instance);
|
||
Console.Write($" ({dealerTotal})");
|
||
}
|
||
Console.WriteLine();
|
||
|
||
// Show player's hand.
|
||
var playerTotal = HandUtil.CalculateHand(world, PlayerHandTag.Instance);
|
||
Console.Write(" Player: ");
|
||
PrintHand(world, PlayerHandTag.Instance);
|
||
Console.Write($" ({playerTotal})");
|
||
Console.WriteLine();
|
||
Console.WriteLine();
|
||
|
||
// Status line.
|
||
switch (state.Phase)
|
||
{
|
||
case GamePhase.Betting:
|
||
Console.Write($" Enter bet (1–{state.Chips}): ");
|
||
break;
|
||
case GamePhase.PlayerTurn:
|
||
Console.Write(" [H]it or [S]tand: ");
|
||
break;
|
||
case GamePhase.RoundOver:
|
||
Console.WriteLine($" {ResultText(state.Result)}");
|
||
Console.WriteLine();
|
||
Console.Write(" Press Enter for next round...");
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
private static void PrintHand(World world, DealerHand hand, bool skipFirst = false)
|
||
{
|
||
PrintHandImpl(world, hand, skipFirst);
|
||
}
|
||
|
||
private static void PrintHand(World world, PlayerHand hand)
|
||
{
|
||
PrintHandImpl(world, hand, skipFirst: false);
|
||
}
|
||
|
||
private static void PrintHandImpl<T>(World world, T handTag, bool skipFirst)
|
||
where T : struct
|
||
{
|
||
Entity handEntity = Entity.Null;
|
||
using (var iter = world.Select<T>())
|
||
{
|
||
while (iter.MoveNext())
|
||
{
|
||
if (iter.CurrentEntity != World.SingletonEntity)
|
||
{
|
||
handEntity = iter.CurrentEntity;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (handEntity == Entity.Null)
|
||
return;
|
||
|
||
var cards = world.GetSources<Holds>(handEntity);
|
||
var ordered = cards.OrderByDescending(c =>
|
||
{
|
||
var card = world.ReadComponent<Card>(c);
|
||
return (int)card.Rank;
|
||
}).ToList();
|
||
|
||
bool first = true;
|
||
foreach (var cardEntity in ordered)
|
||
{
|
||
if (skipFirst && first)
|
||
{
|
||
first = false;
|
||
continue;
|
||
}
|
||
first = false;
|
||
var card = world.ReadComponent<Card>(cardEntity);
|
||
Console.Write(CardToString(card));
|
||
Console.Write(" ");
|
||
}
|
||
}
|
||
|
||
private static string CardToString(Card card)
|
||
{
|
||
var suit = card.Suit switch
|
||
{
|
||
Suit.Hearts => "♥",
|
||
Suit.Diamonds => "♦",
|
||
Suit.Clubs => "♣",
|
||
Suit.Spades => "♠",
|
||
_ => "?"
|
||
};
|
||
|
||
var rank = card.Rank switch
|
||
{
|
||
Rank.Ace => "A",
|
||
Rank.Jack => "J",
|
||
Rank.Queen => "Q",
|
||
Rank.King => "K",
|
||
_ => ((int)card.Rank).ToString()
|
||
};
|
||
|
||
return $"{rank}{suit}";
|
||
}
|
||
|
||
private static string ResultText(RoundResult result) => result switch
|
||
{
|
||
RoundResult.PlayerBust => "You bust! Dealer wins.",
|
||
RoundResult.DealerBust => "Dealer busts! You win!",
|
||
RoundResult.PlayerWin => "You win!",
|
||
RoundResult.DealerWin => "Dealer wins.",
|
||
RoundResult.Push => "Push — it's a tie!",
|
||
RoundResult.Blackjack => "Blackjack!",
|
||
_ => ""
|
||
};
|
||
} |