264 lines
10 KiB
Plaintext
264 lines
10 KiB
Plaintext
@* --- НАЧАЛО КОДА ДЛЯ 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 --- *@ |