blackjack/Components/Pages/BlackjackGame.razor

264 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@* --- НАЧАЛО КОДА ДЛЯ 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 --- *@