Пишем свой блек-джек на Python
easy

Пишем свой блек-джек на Python

Простая игра для серьёзных исследований

Большинство профессиональных игроков в азартные игры пользуются всем арсеналом комбинаторики, статистики и теории вероятностей. Чтобы показать, как это происходит в жизни, нам нужен пример, на котором мы сможем проверить все гипотезы и убедиться в их правильности (или опровергнуть их). 

Для этого мы сегодня напишем игру на Python в блек-джек, или двадцать одно, — и на примере этой игры дальше будем показывать, как статистика работает в пользу игрока (или казино). Правила игры довольно просты:

  • Есть колода из 54 карт, масти неважны. В казино используют сразу до 8 колод, перемешивая их друг с другом.
  • Каждому игроку сдаётся в открытую по две карте, раздающему (крупье) — одна карта.
  • Карты с цифрами от 2 до 10 дают номинальное число очков (от 2 до 10), картинка — 10 очков, туз — 11 очков (или одно, если на руке больше 11 очков).
  • Цель игры — набрать как можно больше очков, но не больше 21. Если получается больше 21 — игрок автоматически проиграл.
  • Игрок смотрит свою карту и принимает решение, взять ещё или ему хватит. После каждой взятой карты игрок смотрит на сумму очков и решает, будет брать ещё или нет.
  • Когда игрок останавливается, крупье сдаёт себе карты по той же схеме.
  • Если у игрока больше очков, чем у крупье, то он выиграл. Если очков больше у крупье — выиграл он.

Как это будет выглядеть:

Пишем свой блек-джек на Python

Если вы ещё не писали программы на Python, начните с этого, дальше будет проще:

Что делаем

Для простоты наша игра будет устроена по таким правилам:

  1. Один игрок играет против раздающего.
  2. В начале игры раздающий сдаёт игроку две карты.
  3. Игрок может добрать дополнительную карту или остановиться на той комбинации, что у него уже есть.
  4. Когда игрок остановился, раздающий получает право хода и сдаёт себе две карты.
  5. Если раздающий набирает меньше 16 очков, он обязан взять ещё одну карту. Если 17 и больше — должен остановиться и подсчитать очки.
  6. Выигрывает тот, у кого больше очков, но не более 21. 

В блек-джеке используют от одной до восьми колод карт. Чем больше колод, тем ниже вероятность набрать 21 очко, то есть блек-джек. Чтобы играть было интереснее, мы будем предлагать игроку выбрать, сколько колод будет участвовать в игре.

Считать очки будем так:

  • масть не учитывается;
  • карты от 2 до 10 считаются по своему номиналу: двойка даёт 2 очка, десятка — 10;
  • валет, дама и король считаются за 10 очков;
  • туз даёт 1 очко, если на руке больше 11 очков, и 11 — если меньше.

Что понадобится

Вся игра будет реализована встроенными средствами Python без внешних библиотек.

Модуль os добавляет возможности для работы с операционной системой. Нам он понадобится, чтобы задать оформление вывода программы в консоли.

Модуль random нужен для работы со случайными значениями. С его помощью мы будем перемешивать карты.

Списки — упорядоченные коллекции элементов, в которые мы будем складывать карты. У нас будет три списка: один для общей колоды и по одному для карт игрока и раздающего. Элементы списка пронумерованы, и их можно изменять — например, добавить карту на руку игроку. Списки обозначаются квадратными скобками:

deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Цикл — это инструкция, которая повторяет выполнение блока кода несколько раз для достижения задачи. В цикле for перебираются элементы последовательности, а цикл while выполняется до тех пор, пока указанное условие остаётся истинным. Мы будем использовать обе конструкции, например с помощью for проходить по элементам списка в порядке их нумерации.

Проверка условий if, elif и else. Скрипт будет работать после проверки условий. Например, если у игрока на руке туз и валет, то у него блек-джек и он выиграл. Если комбинация карт не даёт блек-джек, то скрипт спросит, что игрок хочет делать дальше — добирать карту или передавать ход раздающему.

Управляющие последовательности ANSI — это специальные символы, с помощью которых можно настраивать внешний вид вывода в консоли: выделить текст другим цветом или жирным и выбрать фон для текста. Управляющие последовательности используются внутри строк кода, начинаются с обратной косой черты \ и составляются по таким правилам:

  • Начинаются с символа ESC, который обозначается как \x1b[, \u001b[ или \033[.
  • После этого идёт основная структура. Если параметров несколько, они указываются через точку с запятой.
  • Последовательность заканчивается буквой m. Она указывает, что параметры применяются к тексту.
  • Чтобы вернуть остальному тексту стандартное форматирование, указывают последовательность сброса параметров \033[0m.

Например, последовательность \033[1;32;40mПОБЕДЫ будет обрабатываться так, что слово «ПОБЕДЫ» отобразится жирным зелёным цветом на чёрном фоне.

Функции. Чтобы не запутаться и соблюдать правила хорошего тона в программировании, всю программу мы разделим на функции. Сначала соберём все вспомогательные функции, а потом напишем одну главную.

Импортируем модули и указываем тип терминала

Добавляем нужные модули командой import:

# импортируем модуль os
import os
# импортируем модуль random
import random

Теперь нам нужно указать тип терминала, чтобы Python лучше понимал, как работать с последовательностями ANSI. Чтобы узнать тип терминала, используем команду echo $TERM в командной строке или терминале IDE:

Пишем свой блек-джек на Python

Нужно указать только первое слово, например xterm, linux, vt100 или screen. У нас тип терминала xterm, мы укажем в коде его. Если у вас другой тип терминала, замените xterm на своё значение:

# устанавливаем переменную окружения, предварительно узнав
# свой тип консоли в терминале командой echo $TERM
os.environ['TERM'] = 'xterm'

Если не объявить эту переменную, скорее всего, всё будет работать и без неё. Но тогда в выводе каждый раз будет появляться служебное сообщение:

Пишем свой блек-джек на Python

Создаём игровую колоду

Подготовимся к игре. Спросим у пользователя количество колод и создадим для каждой колоды 4 списка с полным набором карт — по одному для каждой масти. Масть для игры неважна, но важно указать количество карт в колоде.

# просим пользователя ввести количество колод
decks = input("Введите количество колод: ")
# умножаем список карт одной масти на 4 и на количество колод decks
deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] * (int(decks) * 4)

Из карт от 11 до 14 мы потом сделаем карты-картинки — от валета до туза.

Объявим два счётчика — побед и поражений.

# устанавливаем начальные значения счётчиков побед и поражений
wins = 0
losses = 0

Раздаём начальные карты

Создадим функцию, которая сдаёт по 2 карты. Для этого сначала передаём в функцию общий список со всеми картами, которые есть в игре:

# функция выдачи двух начальных карт
def deal(deck_func):

Создаём пустой список hand — в него будем добавлять две карты с конца колоды.

   # создаём список без карт
   hand = []

Перемешиваем общую колоду:

   # дважды запускаем цикл
   # перемешиваем все карты в общей колоде
   random.shuffle(deck_func)

Запускаем цикл и дважды достаём из колоды последнюю карту методом .pop(). Тогда из списка извлекается последний элемент. В самом списке этот элемент удаляется:

   for i in range(2):
       # достаём последний элемент списка, «верхнюю карту»
       card = deck_func.pop()

Проверим карты на обозначение: 11 станет валетом, 12 — дамой, 13 — королём, из 14 получится туз. 

       # присваиваем карте понятное обозначение, если карта — картинка
       # валет
       if card == 11:
           card = "J"
       # дама
       if card == 12:
           card = "Q"
       # король
       if card == 13:
           card = "K"
       # туз
       if card == 14:
           card = "A"

Добавляем эту карту на руку игроку или раздающему и возвращаем список hand

       # добавляем карту на руку игроку
       hand.append(card)
   # возвращаем из функции список с двумя картами
   return hand

Запускаем новый раунд

После каждого раунда будем спрашивать игрока, хочет ли он сыграть ещё. Для этого напишем функцию, которая выводит текст вопроса и принимает от пользователя строку-ответ.

Если игрок пишет «да», то независимо от регистра букв запускаем основную функцию игры. У нас её пока нет, но название уже можно указать. Назовём её game():

# функция запуска нового раунда игры после окончания предыдущего
def play_again():
   # спрашиваем у пользователя, хочет ли он играть ещё
   again = input("Хотите сыграть снова? (Да/Нет) : ").lower()
   # если хочет, запускаем основную функцию игры
   if again == "да":
       game()
   # если не хочет, показываем финальное сообщение и закрываем программу
   else:
       print("\033[0;35;40mКазино всегда выигрывает!\033[0m")
       exit()

Если пользователь пишет любой другой ответ, завершаем работу программы командой exit(). Она останавливает работу всего интерпретатора. Перед выходом показываем сообщение фиолетовым цветом на чёрном фоне.

Переводим карты в очки

Нам понадобится отдельная функция для перевода списка с картами в числовые значения. Для этого добавим в функцию переменную-счётчик, который каждый раз объявляется с нулевым значением.

Посмотрим на код функции, а потом разберём его работу:

# функция подсчёта очков по картам на руке
def total(hand):
   # устанавливаем начальное нулевое значение
   points = 0
   # запускаем цикл, который проверит все карты в списке hand
   for card in hand:
       # если карта — картинка, то прибавляем 10
       if card == "J" or card == "Q" or card == "K":
           points += 10
       # туз считается в зависимости от количества очков
       elif card == "A":
           if points >= 11:
               points += 1
           else:
               points += 11
       # все остальные карты считаются по своему номиналу
       else:
           points += card
   # возвращаем количество очков
   return points

Как происходит подсчёт очков:

  • На каждую карту в списке мы запускаем по одной итерации цикла.
  • Если элемент списка — карта-картинка, приравниваем её к 10 очкам.
  • При этом помним, что ценность у туза считается с нюансами.
  • Остальные карты считаем по своему номиналу-названию.

Производим добор карт

После раздачи игрок и раздающий смотрят на свои карты и решают — остановиться или взять ещё одну карту. Для добавления ещё одной карты на руку напишем функцию, которая берёт последний элемент из списка всех карт deck и добавляет в список игроков hand. Все карты с картинками становятся своими понятными буквенными аналогами:

# функция добавления новой карты
def hit(hand):
   # берём карту с конца списка общей колоды — «снимаем карту сверху»
   card = deck.pop()
   # присваиваем карте понятное обозначение, если карта — картинка
   # валет
   if card == 11:
       card = "J"
   # дама
   if card == 12:
       card = "Q"
   # король
   if card == 13:
       card = "K"
   # туза
   if card == 14:
       card = "A"
   # добавляем карту на руку
   hand.append(card)
   # возвращаем новый список
   return hand

В конце возвращаем обновлённый список.

Выводим результаты

Функций по подсчёту очков у нас ещё нет, но для них понадобится ещё одна функция для вывода результатов раунда на экран. Поэтому сначала создадим её.

В функцию для вывода результатов мы передаём два списка: очки раздающего и игрока, — после чего выводим на экран заголовок и две строки с этими очками:

# функция вывода результатов
def print_results(dealer_hand, player_hand):
   # выводим на экран результаты раунда
   print("\n*** РЕЗУЛЬТАТЫ РАУНДА ***\n")
   # выводим список карт на руке в формате строки и считаем сумму очков для раздающего и игрока
   print("У раздающего на руке: " + str(dealer_hand) + ", в сумме: " + str(total(dealer_hand)))
   print("У вас на руке: " + str(player_hand) + ", в сумме: " + str(total(player_hand)))

Чтобы вывести одной строкой список карт и очков, списки трансформируем в строки. В этой же строке считаем уже готовой функцией total число очков и тоже переводим его в строковый формат. Теперь можно склеить все элементы вывода через знак +.

Проверяем начальные карты

Если у кого-то на руках туз и карта в 10 очков, то набран блек-джек. В этом случае сразу заканчиваем игру, увеличиваем счётчик побед или поражений и предлагаем сыграть снова.Чтобы функция могла изменять счётчики побед и поражений, их нужно добавить в область видимости функции командой global.

def blackjack(dealer_hand, player_hand):
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses

В теле функции будет три главных блока с проверками условий if и elif. Если блек-джек у игрока, то увеличиваем счётчик побед и выводим сообщение о выигрыше.

   # проверяем очки игрока на 21
   if total(player_hand) == 21:
       # если у игрока 21, выводим результаты, пишем
       # сообщение о выигрыше, увеличиваем счётчик побед
       print_results(dealer_hand, player_hand)
       print("Поздравляю! У вас блек-джек, вы выиграли!\n")
       wins += 1
       # предлагаем сыграть снова
       play_again()

Если блек-джек у раздающего, то увеличиваем счётчик поражений и выводим сообщение о проигрыше.

   # проверяем очки раздающего на 21
   elif total(dealer_hand) == 21:
       # если у раздающего 21, выводим результаты, пишем
       # сообщение о проигрыше, увеличиваем счётчик поражений
       print_results(dealer_hand, player_hand)
       print("Простите, вы проиграли. У раздающего блек-джек.\n")
       losses += 1
       # предлагаем сыграть снова
       play_again()

Если блек-джек у обоих, счётчики не меняются и программа предлагает сыграть снова.

   elif total(dealer_hand) == total(player_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("У вас и у раздающего блек-джек. В этом раунде победителя нет.\n")
       # предлагаем сыграть снова
       play_again()

Считаем очки в конце раунда

Если никому не достался блек-джек, а игрок и раздающий не набрали больше 21 очка, нужно посчитать карты. Алгоритм такой же, как в функции blackjack():

  • делаем счётчики побед и поражений видимыми с помощью команды global;
  • считаем очки при помощи функции total, которая переводит карты в очки;
  • добавляем по одному условию на каждый вариант подсчёта очков;
  • увеличиваем счётчик побед или поражений или не меняем оба счётчика, если раунд закончился ничьей.

Объявляем функцию и добавляем счётчики в область видимости:

# функция подсчёта очков
def score(dealer_hand, player_hand):
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses

Проверяем очки. Прописываем логику для ситуации, когда игрок набрал 21:

   # проверяем очки
   # если у игрока 21:
   if total(player_hand) == 21:
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Поздравляю! У вас 21, вы выиграли!\n")
       wins += 1

Раздающий набрал 21:

   # если у раздающего 21
   elif total(dealer_hand) == 21:
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о проигрыше и итоговом результате
       print("Простите, вы проиграли. У раздающего 21.\n")
       losses += 1

Никто не набрал 21, но у игрока меньше очков, чем у раздающего:

   # если у раздающего больше очков
   elif total(player_hand) < total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о проигрыше и итоговом результате
       print("У раздающего больше очков, чем у вас. Вы проиграли.\n")
       losses += 1

Раздающий набрал меньше игрока:

   # если у игрока больше очков
   elif total(player_hand) > total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Поздравляю, у вас больше очков, чем у раздающего. Вы выиграли!\n")
       wins += 1

Очков поровну:

   elif total(player_hand) == total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Раздающий набрал столько же, сколько и вы. В этом раунде победителя нет.\n")

Обратите внимание, что в этой функции мы не вызываем функцию запуска нового раунда. Она будет вызываться в основной функции после подсчёта очков.

Выводим результаты

Объявляем функцию и делаем счётчики видимыми для неё:

# основная функция игры
def game():
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses

Используем управляющие последовательности для оформления. Слово «ПОБЕДЫ» выделяем зелёным текстом жирного начертания, «ПОРАЖЕНИЯ» — красным. Значения добавляем знаком % и в конце строки в скобках объясняем, что за переменные туда передавать: 

   # выводим оформление нового раунда
   print("\n    Новая игра!\n")
   # выводим 30 коротких тире
   print("-" * 30 + "\n")
   # выводим слово ПОБЕДЫ жирным зелёным шрифтом, слово ПОРАЖЕНИЯ — жирным красным
   # после каждого слова ставим корректные счётчики
   print("    \033[1;32;40mПОБЕДЫ:  \033[1;37;40m%s   \033[1;31;40mПОРАЖЕНИЯ:  \033[1;37;40m%s\n\033[0m" % (wins, losses))
   # выводим 30 коротких тире
   print("-" * 30 + "\n")

Дописываем игровую логику

Запускаем функцию раздачи начальных карт для игрока и раздающего:

   # раздаём по две карты игроку и раздающему
   dealer_hand = deal(deck)
   player_hand = deal(deck)

Раздающий раскрывает одну карту и показывает, что у него:

   # раздающий раскрывает одну карту
   print("Раздающий показывает " + str(dealer_hand[0]))

Показываем игроку, какие карты выпали ему:

   # говорим игроку, что за карты у него на руке и сколько очков
   print("У вас на руке:" + str(player_hand) + ", в сумме количество очков равно " + str(total(player_hand)))

Проверяем игрока и раздающего на блек-джек:

   # проверяем, есть ли у кого-то 21
   blackjack(dealer_hand, player_hand)

Запускаем главную функцию с игрой:

   # запускаем бесконечный цикл
   while True:

Если игрок решил взять карту, запускаем функцию hit(). После этого показываем новый список карт и считаем очки. Если получается больше 21, выводим сообщение о проигрыше и предлагаем сыграть ещё.

       # при выборе добрать карту
       if choice == 'д':
           # запускаем функцию добавления карты
           hit(player_hand)
           # выводим новый список карт
           print(player_hand)
           # выводим на экран сумму очков
           print("Сумма ваших очков: " + str(total(player_hand)))
           # если у игрока больше 21 очка, выводим сообщение о проигрыше,
           # увеличиваем счётчик поражений, предлагаем сыграть заново
           if total(player_hand) > 21:
               print('У вас перебор')
               losses += 1
               play_again()

Если пользователь больше не хочет брать карты, ход переходит раздающему. Напомним, что по правилам раздающий должен набрать на руке не меньше 17 очков.

Запускаем функцию hit()и считаем очки после каждой новой карты. Если больше 17 — останавливаем игру и считаем очки. Если больше 21 — пишем игроку, что он победил, и увеличиваем счётчик побед на 1.

       # при выборе остановиться ход переходит раздающему
       elif choice == 'о':
           # пока у дилера меньше 17 очков, он должен добирать карты
           while total(dealer_hand) < 17:
               hit(dealer_hand)
               # после каждой новой карты выводим список карт раздающего
               print('Раздающий взял новую карту. У него на руках: ', dealer_hand)
               # если у раздающего больше 21 очка, выводим сообщение о выигрыше,
               # увеличиваем счётчик побед, предлагаем сыграть заново
               if total(dealer_hand) > 21:
                   print('У раздающего перебор, вы выиграли!')
                   wins += 1
                   play_again()

Если раздающий набрал между 17 и 21 очком, подсчитываем итоги у обоих:

           # если раздающий набрал 17 очков и у него не перебор, подсчитываем очки обоих
           else:
               score(dealer_hand, player_hand)
               play_again()

Если игрок хочет закончить игру, показываем финальное сообщение и останавливаем выполнение всей программы:

       # если игрок решил завершить игру, выводим сообщение и завершаем программу
       elif choice == "в":
           print("Казино всегда выигрывает!")
           exit()

Добавим проверку ввода. Если игрок ввёл какой-то другой символ вместо «д», «о» или «в», выводим сообщение, что нужно повторить ответ.

       # если пользователь ввёл какое-то непредусмотренное значение, просим повторить ввод
       else:
           print("Неверный ввод. Пожалуйста, введите 'д', 'о' или 'в'.")

Запускаем основную функцию:

# запускаем основную функцию игры
game()

Играем:

Пишем свой блек-джек на Python

Что дальше

Теперь у нас есть программа, на которой мы можем моделировать разные стратегии игры и проверять, как работает комбинаторика и теория вероятностей в жизни. Этим потихоньку и займёмся в следующий раз.

# импортируем модуль os
import os
# импортируем модуль random
import random
# устанавливаем переменную окружения, предварительно узнав
# свой тип консоли в терминале командой echo $TERM
os.environ['TERM'] = 'xterm'

# просим пользователя ввести количество колод
decks = input("Введите количество колод: ")
# умножаем список карт одной масти на 4 и на количество колод decks
deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] * (int(decks) * 4)

# устанавливаем начальные значения счётчиков побед и поражений
wins = 0
losses = 0

# функция выдачи двух начальных карт
def deal(deck_func):
   # создаём список без карт
   hand = []
   # дважды запускаем цикл
   # перемешиваем все карты в общей колоде
   random.shuffle(deck_func)
   for i in range(2):
       # достаём последний элемент списка, «верхнюю карту»
       card = deck_func.pop()
       # присваиваем карте понятное обозначение, если карта — картинка
       # валет
       if card == 11:
           card = "J"
       # дама
       if card == 12:
           card = "Q"
       # король
       if card == 13:
           card = "K"
       # туз
       if card == 14:
           card = "A"
       # добавляем карту на руку игроку
       hand.append(card)
   # возвращаем из функции список с двумя картами
   return hand

# функция запуска нового раунда игры после окончания предыдущего
def play_again():
   # спрашиваем у пользователя, хочет ли он играть ещё
   again = input("Хотите сыграть снова? (Да/Нет) : ").lower()
   # если хочет, запускаем основную функцию игры
   if again == "да":
       game()
   # если не хочет, показываем финальное сообщение и закрываем программу
   else:
       print("\033[0;35;40mКазино всегда выигрывает!\033[0m")
       exit()

# функция подсчёта очков по картам на руке
def total(hand):
   # устанавливаем начальное нулевое значение
   points = 0
   # запускаем цикл, который проверит все карты в списке hand
   for card in hand:
       # если карта — картинка, то прибавляем 10
       if card == "J" or card == "Q" or card == "K":
           points += 10
       # туз считается в зависимости от количества очков
       elif card == "A":
           if points >= 11:
               points += 1
           else:
               points += 11
       # все остальные карты считаются по своему номиналу
       else:
           points += card
   # возвращаем количество очков
   return points

# функция добавления новой карты
def hit(hand):
   # берём карту с конца списка общей колоды — «снимаем карту сверху»
   card = deck.pop()
   # присваиваем карте понятное обозначение, если карта — картинка
   # валет
   if card == 11:
       card = "J"
   # дама
   if card == 12:
       card = "Q"
   # король
   if card == 13:
       card = "K"
   # туз
   if card == 14:
       card = "A"
   # добавляем карту на руку
   hand.append(card)
   # возвращаем новый список
   return hand

# функция вывода результатов
def print_results(dealer_hand, player_hand):
   # выводим на экран результаты раунда
   print("\n*** РЕЗУЛЬТАТЫ РАУНДА ***\n")
   # выводим список карт на руке в формате строки и считаем сумму очков для раздающего и игрока
   print("У раздающего на руке: " + str(dealer_hand) + ", в сумме: " + str(total(dealer_hand)))
   print("У вас на руке: " + str(player_hand) + ", в сумме: " + str(total(player_hand)))

# функция проверки начальной раздачи на 21
def blackjack(dealer_hand, player_hand):
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses
   # проверяем очки игрока на 21
   if total(player_hand) == 21:
       # если у игрока 21, выводим результаты, пишем
       # сообщение о выигрыше, увеличиваем счётчик побед
       print_results(dealer_hand, player_hand)
       print("Поздравляю! У вас блек-джек, вы выиграли!\n")
       wins += 1
       # предлагаем сыграть снова
       play_again()
   # проверяем очки раздающего на 21
   elif total(dealer_hand) == 21:
       # если у раздающего 21, выводим результаты, пишем
       # сообщение о проигрыше, увеличиваем счётчик поражений
       print_results(dealer_hand, player_hand)
       print("Простите, вы проиграли. У раздающего блек-джек.\n")
       losses += 1
       # предлагаем сыграть снова
       play_again()
   elif total(dealer_hand) == total(player_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("У вас и у раздающего блек-джек. В этом раунде победителя нет.\n")
       # предлагаем сыграть снова
       play_again()

# функция подсчёта очков
def score(dealer_hand, player_hand):
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses
   # проверяем очки
   # если у игрока 21:
   if total(player_hand) == 21:
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Поздравляю! У вас 21, вы выиграли!\n")
       wins += 1
   # если у раздающего 21
   elif total(dealer_hand) == 21:
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о проигрыше и итоговом результате
       print("Простите, вы проиграли. У раздающего 21.\n")
       losses += 1
   # если у раздающего больше очков
   elif total(player_hand) < total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о проигрыше и итоговом результате
       print("У раздающего больше очков, чем у вас. Вы проиграли.\n")
       losses += 1
   # если у игрока больше очков
   elif total(player_hand) > total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Поздравляю, у вас больше очков, чем у раздающего. Вы выиграли!\n")
       wins += 1
   elif total(player_hand) == total(dealer_hand):
       # выводим результаты игрока и раздающего
       print_results(dealer_hand, player_hand)
       # выводим сообщение о победе и итоговом результате
       print("Раздающий набрал столько же, сколько и вы. В этом раунде победителя нет.\n")

# основная функция игры
def game():
   # добавляем в область видимости счётчики побед и поражений
   global wins
   global losses

   # выводим оформление нового раунда
   print("\n    Новая игра!\n")
   # выводим 30 коротких тире
   print("-" * 30 + "\n")
   # выводим слово ПОБЕДЫ жирным зелёным шрифтом, слово ПОРАЖЕНИЯ — жирным красным
   # и после каждого слова ставим корректные счётчики
   print("    \033[1;32;40mПОБЕДЫ:  \033[1;37;40m%s   \033[1;31;40mПОРАЖЕНИЯ:  \033[1;37;40m%s\n\033[0m" % (wins, losses))
   # выводим 30 коротких тире
   print("-" * 30 + "\n")

   # раздаём по две карты игроку и раздающему
   dealer_hand = deal(deck)
   player_hand = deal(deck)

   # раздающий раскрывает одну карту
   print("Раздающий показывает " + str(dealer_hand[0]))
   # говорим игроку, что за карты у него на руке и сколько очков
   print("У вас на руке:" + str(player_hand) + ", в сумме количество очков равно " + str(total(player_hand)))
   # проверяем, есть ли у кого-то 21
   blackjack(dealer_hand, player_hand)

   # запускаем бесконечный цикл
   while True:
       # спрашиваем у игрока, что он хочет сделать
       choice = input("\033[1;33;40mВы хотите [д]обрать карту, [о]становиться или [в]ыйти из игры? \033[0m").lower()
       # при выборе добрать карту
       if choice == 'д':
           # запускаем функцию добавления карты
           hit(player_hand)
           # выводим новый список карт
           print(player_hand)
           # выводим на экран сумму очков
           print("Сумма ваших очков: " + str(total(player_hand)))
           # если у игрока больше 21 очка, выводим сообщение о проигрыше,
           # увеличиваем счётчик поражений, предлагаем сыграть заново
           if total(player_hand) > 21:
               print('У вас перебор')
               losses += 1
               play_again()

       # при выборе остановиться ход переходит раздающему
       elif choice == 'о':
           # пока у дилера меньше 17 очков, он должен добирать карты
           while total(dealer_hand) < 17:
               hit(dealer_hand)
               # после каждой новой карты выводим список карт раздающего
               print('Раздающий взял новую карту. У него на руках: ', dealer_hand)
               # если у раздающего больше 21 очка, выводим сообщение о выигрыше,
               # увеличиваем счётчик побед, предлагаем сыграть заново
               if total(dealer_hand) > 21:
                   print('У раздающего перебор, вы выиграли!')
                   wins += 1
                   play_again()
           # если раздающий набрал 17 очков и у него не перебор, подсчитываем очки обоих
           else:
               score(dealer_hand, player_hand)
               play_again()

       # если игрок решил завершить игру, выводим сообщение и завершаем программу
       elif choice == "в":
           print("\033[0;35;40mКазино всегда выигрывает!\033[0m")
           exit()
       # если пользователь ввёл какое-то непредусмотренное значение, просим повторить ввод
       else:
           print("Неверный ввод. Пожалуйста, введите 'д', 'о' или 'в'.")

# запускаем основную функцию игры
game()

Редактор:

Инна Долога

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Вам может быть интересно
easy