Добавить в корзинуПозвонить
Найти в Дзене
Программы от меня

Напишем игру Blackjack на C#: пошаговое руководство для начинающих

Хотите освоить C# и создать свою собственную карточную игру? Сегодня мы реализуем классический Blackjack (блэкджек, или «очко») в консоли. Проект поможет разобраться с объектно-ориентированным подходом, коллекциями, случайными числами и логикой игры. Давайте начнём! Игрок соревнуется с дилером. Цель — набрать сумму очков, близкую к 21, но не больше. Карты от 2 до 10 дают соответствующее число очков, валет, дама, король — 10 очков, туз — 1 или 11 (выбирается автоматически в пользу игрока без перебора). Игрок может брать новые карты (Hit) или остановиться (Stand). Дилер обязан брать, пока у него меньше 17 очков. Побеждает тот, у кого сумма ближе к 21, либо кто не перебрал. Создадим консольное приложение. Нам понадобятся три класса: Весь код пишем в одном файле Program.cs для простоты. public class Card
{
public string Suit { get; }
public string Rank { get; }
public int Value { get; }
public Card(string suit, string rank, int value)
{
Suit = suit;
Оглавление

Хотите освоить C# и создать свою собственную карточную игру? Сегодня мы реализуем классический Blackjack (блэкджек, или «очко») в консоли. Проект поможет разобраться с объектно-ориентированным подходом, коллекциями, случайными числами и логикой игры. Давайте начнём!

Правила игры (кратко)

Игрок соревнуется с дилером. Цель — набрать сумму очков, близкую к 21, но не больше. Карты от 2 до 10 дают соответствующее число очков, валет, дама, король — 10 очков, туз — 1 или 11 (выбирается автоматически в пользу игрока без перебора). Игрок может брать новые карты (Hit) или остановиться (Stand). Дилер обязан брать, пока у него меньше 17 очков. Побеждает тот, у кого сумма ближе к 21, либо кто не перебрал.

Структура проекта

Создадим консольное приложение. Нам понадобятся три класса:

  • Card — одна карта (масть, значение, очки)
  • Deck — колода (список карт, перемешивание, выдача)
  • Game — логика игры (игрок, дилер, ввод, вывод)

Весь код пишем в одном файле Program.cs для простоты.

Класс Card

public class Card
{
public string Suit { get; }
public string Rank { get; }
public int Value { get; }

public Card(string suit, string rank, int value)
{
Suit = suit;
Rank = rank;
Value = value;
}

public override string ToString() => $"{Rank}{Suit}";
}

Масти можно обозначать символами: ♠ ♥ ♣ ♦. Значения: 2-10, J, Q, K, A. Очки для туза временно зададим 11, но при подсчёте будем корректировать.

Класс Deck

Колода из 52 карт. Создадим метод Initialize() с перебором мастей и рангов.

public class Deck
{
private List<Card> _cards;
private readonly Random _random = new();

public Deck()
{
_cards = new List<Card>();
Initialize();
Shuffle();
}

private void Initialize()
{
string[] suits = { "♠", "♥", "♣", "♦" };
string[] ranks = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };
int[] values = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11 };

for (int i = 0; i < suits.Length; i++)
{
for (int j = 0; j < ranks.Length; j++)
{
_cards.Add(new Card(suits[i], ranks[j], values[j]));
}
}
}

public void Shuffle()
{
for (int i = _cards.Count - 1; i > 0; i--)
{
int j = _random.Next(i + 1);
(_cards[i], _cards[j]) = (_cards[j], _cards[i]);
}
}

public Card DrawCard()
{
if (_cards.Count == 0)
{
Initialize();
Shuffle();
}
Card card = _cards[0];
_cards.RemoveAt(0);
return card;
}
}

Класс Game и логика подсчёта очков

Подсчёт очков: суммируем значения, но если сумма > 21 и есть туз (который дал 11), то заменяем 11 на 1 (уменьшаем сумму на 10).

public class Game
{
private Deck _deck;
private List<Card> _playerHand;
private List<Card> _dealerHand;

public Game()
{
_deck = new Deck();
_playerHand = new List<Card>();
_dealerHand = new List<Card>();
}

private int CalculateHandValue(List<Card> hand)
{
int sum = hand.Sum(c => c.Value);
int aceCount = hand.Count(c => c.Rank == "A");
while (sum > 21 && aceCount > 0)
{
sum -= 10;
aceCount--;
}
return sum;
}

public void Start()
{
// Начальная раздача
_playerHand.Add(_deck.DrawCard());
_dealerHand.Add(_deck.DrawCard());
_playerHand.Add(_deck.DrawCard());
_dealerHand.Add(_deck.DrawCard());

// Ход игрока
bool playerTurn = true;
while (playerTurn)
{
Console.Clear();
DisplayGame(false);
int playerScore = CalculateHandValue(_playerHand);
if (playerScore > 21)
{
Console.WriteLine("Перебор! Вы проиграли.");
playerTurn = false;
break;
}

Console.Write("Взять карту (h) или остановиться (s)? ");
string choice = Console.ReadLine()?.ToLower();
if (choice == "h")
{
_playerHand.Add(_deck.DrawCard());
}
else if (choice == "s")
{
playerTurn = false;
}
}

// Если игрок не перебрал, ход дилера
if (CalculateHandValue(_playerHand) <= 21)
{
DealerTurn();
DetermineWinner();
}

Console.WriteLine("Игра окончена. Нажмите любую клавишу...");
Console.ReadKey();
}

private void DealerTurn()
{
while (CalculateHandValue(_dealerHand) < 17)
{
_dealerHand.Add(_deck.DrawCard());
}
}

private void DetermineWinner()
{
Console.Clear();
DisplayGame(true);
int playerScore = CalculateHandValue(_playerHand);
int dealerScore = CalculateHandValue(_dealerHand);

if (dealerScore > 21)
Console.WriteLine("Дилер перебрал! Вы выиграли!");
else if (playerScore > dealerScore)
Console.WriteLine("Вы выиграли!");
else if (dealerScore > playerScore)
Console.WriteLine("Дилер выиграл!");
else
Console.WriteLine("Ничья!");
}

private void DisplayGame(bool revealDealer)
{
Console.WriteLine("=== Blackjack ===\n");
Console.Write("Дилер: ");
if (revealDealer)
{
foreach (var card in _dealerHand)
Console.Write(card + " ");
Console.WriteLine($" (очки: {CalculateHandValue(_dealerHand)})");
}
else
{
Console.Write($"{_dealerHand[0]} ??");
Console.WriteLine($" (очки: {CalculateHandValue(new List<Card> { _dealerHand[0] })})");
}

Console.Write("\nВаши карты: ");
foreach (var card in _playerHand)
Console.Write(card + " ");
Console.WriteLine($" (очки: {CalculateHandValue(_playerHand)})");
Console.WriteLine();
}
}

Точка входа

В Main просто создаём игру и запускаем цикл для повторных партий.

csharp

class Program
{
static void Main()
{
Console.Title = "Blackjack";
Console.OutputEncoding = System.Text.Encoding.UTF8;

bool playAgain = true;
while (playAgain)
{
var game = new Game();
game.Start();

Console.Write("Сыграем ещё? (y/n): ");
string answer = Console.ReadLine()?.ToLower();
if (answer != "y")
playAgain = false;
}
Console.WriteLine("Спасибо за игру!");
}
}

Улучшения, которые можно добавить

  • Ставки и фишки – добавить переменную баланса игрока, ставку перед раздачей, удвоение ставки (double).
  • Разделение пар (split) – если две карты одинакового ранга.
  • Страховка при открытом тузе у дилера.
  • Подсчёт карт – для продвинутых игроков.

Заключение

У нас получилась полноценная консольная игра Blackjack на C#. Вы познакомились с классами, списками, случайными числами, управлением игровым циклом и подсчётом очков с тузами. Этот код легко расширить, добавив новые возможности или графический интерфейс на WPF/Unity.

Попробуйте запустить, сыграйте пару партий и поэкспериментируйте с правилами. Если появятся вопросы – пишите в комментариях. Удачи в программировании!

Понравилась статья? Ставьте лайк и подписывайтесь на канал, чтобы не пропустить новые уроки по C# и созданию игр.