blackjack/Components/Pages/BlackjackGame.razor

264 lines
10 KiB
Plaintext
Raw Normal View History

@* --- НАЧАЛО КОДА ДЛЯ BlackjackGame.razor --- *@
@page "/blackjack"
@using БлэкДжек.Components @* <--- ВОТ ЭТУ СТРОКУ НУЖНО ПРОВЕРИТЬ/ЗАМЕНИТЬ *@
@implements IDisposable
<h3>Blackjack</h3>
@* Область для сообщений игры *@
@if (!string.IsNullOrEmpty(GameMessage))
{
<div class="alert @(IsGameOver && PlayerScore <= 21 && (DealerScore > 21 || PlayerScore > DealerScore) ? "alert-success" : "alert-info")" role="alert">
@GameMessage
</div>
}
@* Основной блок игры, отображается после нажатия "Начать" *@
@if (IsGameStarted)
{
<div>
<h4>Дилер (@(IsPlayerTurn ? "?" : DealerScore.ToString()))</h4>
<div class="hand">
@foreach (var card in DealerHand)
{
@* Условие для скрытия первой карты дилера во время хода игрока *@
<div class="card @GetCardColor(card)">
@((DealerHand.IndexOf(card) == 0 && IsPlayerTurn) ? "???" : card.Display)
</div>
}
</div>
</div>
<hr />
<div>
<h4>Игрок (@PlayerScore)</h4>
<div class="hand">
@foreach (var card in PlayerHand)
{
<div class="card @GetCardColor(card)">
@card.Display
</div>
}
</div>
</div>
<hr />
@* Кнопки действий *@
<div class="actions">
<button class="btn btn-primary" @onclick="PlayerHit" disabled="@(!IsPlayerTurn || IsGameOver)">Взять карту (Hit)</button>
<button class="btn btn-secondary" @onclick="PlayerStand" disabled="@(!IsPlayerTurn || IsGameOver)">Стоп (Stand)</button>
<button class="btn btn-warning" @onclick="StartGame">Новая игра</button>
</div>
}
else
{
@* Кнопка для старта игры, видна только до начала *@
<button class="btn btn-success btn-lg" @onclick="StartGame">Начать игру</button>
}
@* Блок с C# кодом *@
@code {
// --- Поля состояния игры ---
private Deck GameDeck;
private List<Card> PlayerHand = new List<Card>(); // Инициализируем, чтобы избежать null reference до старта
private List<Card> DealerHand = new List<Card>(); // Инициализируем
// --- Вычисляемые свойства для счета ---
private int PlayerScore => CalculateScore(PlayerHand);
private int DealerScore => CalculateScore(DealerHand);
// --- Флаги состояния игры ---
private bool IsPlayerTurn;
private bool IsGameOver;
private bool IsGameStarted; // Показывает, была ли нажата кнопка "Начать игру"
private string GameMessage = string.Empty; // Инициализируем пустой строкой
// --- Инициализация компонента ---
protected override void OnInitialized()
{
// Игра не начинается автоматически при загрузке страницы
IsGameStarted = false;
}
// --- Метод начала новой игры ---
private void StartGame()
{
GameDeck = new Deck();
GameDeck.Shuffle();
PlayerHand = new List<Card>();
DealerHand = new List<Card>();
IsGameOver = false;
IsPlayerTurn = true;
GameMessage = "Ваш ход. Взять карту или стоп?";
IsGameStarted = true; // Показываем игровое поле
// Раздаем по 2 карты
PlayerHand.Add(GameDeck.DealCard());
DealerHand.Add(GameDeck.DealCard()); // Первая карта дилера
PlayerHand.Add(GameDeck.DealCard());
DealerHand.Add(GameDeck.DealCard()); // Вторая карта дилера
// Проверка на блэкджек у игрока или дилера сразу после раздачи
if (PlayerScore == 21 && DealerHand.Count == 2) // У игрока блэкджек
{
if (DealerScore == 21) // У дилера тоже блэкджек
{
RevealDealerCardAndEndGame("Ничья! У обоих Блэкджек!");
}
else // Только у игрока блэкджек
{
RevealDealerCardAndEndGame("Блэкджек! Вы выиграли!");
}
}
else if (DealerScore == 21 && DealerHand.Count == 2) // Только у дилера блэкджек (проверяем после игрока)
{
RevealDealerCardAndEndGame("Блэкджек у дилера! Вы проиграли.");
}
// Если ни у кого нет блэкджека, игра продолжается с сообщением "Ваш ход..."
StateHasChanged(); // Обновляем UI, чтобы показать начальное состояние
}
// --- Действие игрока: Взять карту (Hit) ---
private void PlayerHit()
{
if (!IsPlayerTurn || IsGameOver) return; // Нельзя брать карту не в свой ход или если игра окончена
PlayerHand.Add(GameDeck.DealCard());
if (PlayerScore > 21)
{
EndGame("Перебор! Вы проиграли.");
}
else if (PlayerScore == 21)
{
// Если игрок набрал ровно 21, его ход автоматически завершается
PlayerStand();
}
// Если меньше 21, игрок может брать еще
StateHasChanged(); // Обновляем UI после взятия карты
}
// --- Действие игрока: Стоп (Stand) ---
private void PlayerStand()
{
if (!IsPlayerTurn || IsGameOver) return; // Нельзя остановиться не в свой ход или если игра окончена
IsPlayerTurn = false; // Передаем ход дилеру
GameMessage = "Дилер ходит...";
StateHasChanged(); // Обновим сообщение и откроем карту дилера
// Можно добавить небольшую задержку перед ходом дилера для наглядности
// await Task.Delay(500); // Если раскомментировать, метод должен быть async Task
DealerTurn(); // Начинаем ход дилера
}
// --- Логика хода Дилера ---
// Простая синхронная версия. Для пауз нужен async/await и Task.Delay
private void DealerTurn()
{
// Дилер берет карты, пока его счет меньше 17
while (DealerScore < 17)
{
// В реальном приложении можно добавить паузу здесь
// await Task.Delay(800);
DealerHand.Add(GameDeck.DealCard());
// StateHasChanged(); // Обновлять UI после каждой карты дилера, если есть пауза
}
// После того, как дилер закончил брать карты, определяем победителя
DetermineWinner();
StateHasChanged(); // Показать финальный результат
}
// --- Подсчет очков для руки ---
private int CalculateScore(List<Card> hand)
{
if (hand == null || hand.Count == 0) return 0;
int score = 0;
int aceCount = 0;
foreach (var card in hand)
{
score += card.Value;
if (card.Rank == "A")
{
aceCount++;
}
}
// Корректировка значения Тузов (с 11 на 1 при переборе)
while (score > 21 && aceCount > 0)
{
score -= 10; // Считаем Туз как 1 вместо 11
aceCount--;
}
return score;
}
// --- Определение победителя ---
private void DetermineWinner()
{
// Убедимся, что карта дилера видна (IsPlayerTurn уже false)
if (PlayerScore > 21)
{
// Это условие уже должно было быть обработано в PlayerHit, но на всякий случай
EndGame("Перебор! Вы проиграли.");
}
else if (DealerScore > 21)
{
EndGame("У дилера перебор! Вы выиграли!");
}
else if (PlayerScore > DealerScore)
{
EndGame("Вы выиграли!");
}
else if (DealerScore > PlayerScore)
{
EndGame("Дилер выиграл!");
}
else // Очки равны
{
EndGame("Ничья (Push)!");
}
}
// --- Метод для завершения игры и установки сообщения ---
private void RevealDealerCardAndEndGame(string message)
{
IsPlayerTurn = false; // Убедимся, что карта дилера видна
EndGame(message);
}
private void EndGame(string message)
{
IsGameOver = true;
IsPlayerTurn = false; // Больше никто не ходит
GameMessage = message;
// StateHasChanged(); // Обычно вызывается в методе, который вызвал EndGame
}
// --- Вспомогательный метод для определения цвета карты ---
private string GetCardColor(Card card)
{
return (card.Suit == "♥" || card.Suit == "♦") ? "card-red" : "card-black";
}
// --- Реализация IDisposable (пока пустая, но может пригодиться) ---
public void Dispose()
{
// Здесь можно остановить таймеры или отписаться от событий, если они будут добавлены
}
}
@* --- КОНЕЦ КОДА ДЛЯ BlackjackGame.razor --- *@