Блэкджек в Blazor, часть 2 - Классы C #

Добро пожаловать в нашу серию Deep Dive о создании игры для казино Blackjack на C # и Blazor WebAssembly!

Во второй части мы собираемся использовать идеи моделирования, которые мы записали в предыдущем посте, чтобы построить полную модель C # для игры в блэкджек.

В покере: потрясающая комбинация! В блэкджеке: тоже отличная рука!

Возможно, вы захотите прочитать предыдущий пост в этой серии, прежде чем читать этот. Вот:

Кроме того, есть образец репозитория GitHub, в котором есть весь код, использованный в этой серии.

Все догнали? Хороший! Давайте сразу же приступим.

Основные перечисления

Давайте начнем моделирование C # с самого простого типа, который мы можем моделировать: перечисления масти и достоинства карты.

Мы разберемся со счетом позже в этом посте.

Играя в карты

Следующий по простоте объект, который мы можем смоделировать, - это отдельные игральные карты. Вы можете вспомнить из предыдущего поста, что мы решили, что объект Card должен иметь следующие атрибуты:

  • Костюм
  • Ценность
  • Оценка

Масти и значения уже определены как перечисления, и, сделав их свойствами объекта Card, мы можем вычислить оценку.

Если вас интересуют тузы, я объясню это подробнее в следующем разделе, посвященном подсчету очков.

Видимость

Нам нужно рассмотреть еще одну ситуацию для этой модели, а именно: у дилера есть одна карта, которая не видна игроку. Итак, частью какой модели должно быть это свойство (видимость)?

Есть несколько способов ответить на этот вопрос; мы собираемся создать новое свойство IsVisible для объекта Card. Это свойство будет установлено вне объекта, чтобы дилер мог пометить свои карты как невидимые.

Обратите внимание, что по умолчанию карты ВИДИМЫ.

IsTenCard

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

URL изображений

Мы реализуем отображение наших карточек в виде отдельных изображений с такими именами, как cardClubsJack.png, cardHeartsSix.png, cardSpadesAce.png и т. Д.

Изображения выглядят так:

Нашему объекту Card потребуется свойство, в котором будет храниться имя изображения, отображаемого для этой карты.

Палуба

Следующий объект, который мы можем построить, - это колода карт.

Это одноцветные карты? Фото Шери Хули / Unsplash

Коллекция карточек

Колода по своей сути очень проста: это набор объектов Card. Но что вид из коллекции?

Одно из свойств реальной колоды карт заключается в том, что при вытягивании карты мы всегда тянем ее сверху. В .NET есть класс коллекции, который реализует аналогичную функциональность: класс Stack . Stack определяет метод Pop (), который удаляет и возвращает «самый верхний» объект в коллекции.

Нашему новому объекту CardDeck потребуется свойство типа Stack , в котором хранятся отдельные объекты Card.

Обратите внимание, что коллекция защищена; он недоступен вне класса CardDeck.

Подсчитать, сложить и нарисовать

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

Как мы решили в предыдущем посте, нам нужны методы для добавления карт в колоду и для извлечения карты из колоды. Эти методы довольно просты в реализации:

Push () и Pop () определяются Stack

Инициализация и перемешивание

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

Начнем с создания конструктора для нашего объекта CardDeck, который сначала создает и вставляет все необходимые карты.

Функция GetDisplayName () - это настраиваемая функция; вы можете увидеть его код в репозитории GitHub.

Теперь нам нужно расширить этот конструктор, чтобы перемешать карты. Для этого мы будем использовать почтенный алгоритм перетасовки Фишера-Йейтса, о котором я писал в блоге некоторое время назад:

Вот эта реализация:

Наш объект CardDeck теперь готов к использованию! Мы можем перейти к более сложным объектам, начиная с Person.

Объект Person

Вспомните из предыдущего поста, что нам нужен общий объект Person, от которого наследуются и Player, и Dealer. Этому Человеку необходимы следующие способности:

  • Держите руку в карты
  • Используйте руку, чтобы подсчитать счет
  • Используйте руку, чтобы определить, разорены ли они

Проблема видимого счета

Однако сначала нам нужно решить нерешенную проблему из предыдущего поста: как нам поступить с видимым счетом объекта Dealer (например, счетом только по открытым картам)?

Видимая оценка 7 + 8 = 15, истинная оценка неизвестна. Фото Андрика Лэнгфилда / Unsplash

Это одно из тех мест, где модельер (то есть мы) может принимать «исполнительные решения». Есть несколько способов смоделировать видимую оценку, например сделать ее свойством объекта Dealer, свойством объекта Person или внешним методом. Для этого поста я выбрал второй вариант: мы создадим свойство VisibleScore, которое является частью корневого объекта Person, поскольку именно Person содержит свойство для Cards. Обратите внимание, что ни один из этих вариантов по своей сути не хуже других, они просто требуют других деталей реализации.

Имея все это в виду, мы можем создать объект Person с набором свойств для представления этих способностей. Вот скелет объекта:

Теперь нам нужно заполнить другие свойства.

Истинные и видимые результаты

Самое сложное, что будет делать объект Person, - это вычислить текущий счет этого человека. Поскольку нам нужно свойство для VisibleScore и свойство Score для истинной оценки, мы будем использовать частный метод для вычисления оценки.

Алгоритм подсчета очков выглядит следующим образом:

  1. PASS IN значение, которое определяет, рассчитываем ли мы только видимую оценку или истинную оценку.
  2. ЕСЛИ сумма всех карт меньше или равна 21, верните эту сумму.
  3. ЕСЛИ на руке у человека нет тузов И сумма больше 21, значит, у человека перебор, поэтому верните счет.
  4. ЕСЛИ в руке у человека есть тузы.
  5. ПОКА остались тузы, которые не были конвертированы
  6. ПРЕВРАЩАЙТЕ одного туза в 1 очко.
  7. ЕСЛИ оценка теперь меньше или равна 21, верните результат.
  8. КОНЕЦ ПОКА
  9. ЕСЛИ оценка ЕЩЕ больше 21, значит, у человека бюст, верните результат.

Полученный код выглядит примерно так:

Затем мы можем создать два свойства; один для истинного счета и один для видимого счета.

Проверка на блэкджек и бюст

В предыдущем посте мы решили, что нам нужен специальный дисплей, который обычно отображает счет человека, но также будет отображаться, когда он получает блэкджек и когда он проигрывает.

Буквальное значение. Найдено на Викимедиа, используется по лицензии.

Для этого нам сначала нужно свойство, которое проверяет, есть ли у человека блэкджек. У человека есть блэкджек, если;

  • Их оценка ровно 21 И
  • У них ровно две карты И
  • Одна из их карт - туз И
  • Другая карта - десятикарточная.

Вот свойство для этого:

Этот синтаксис называется членами, содержащими выражение. Вы увидите это довольно часто в этой серии.

Нам также нужно удобное свойство, которое показывает, есть ли у Person перебор:

Правильный термин - не «разорился», а скорее «разорился». Я игнорирую это в своем коде.

Дисплей партитуры

Используя свойства HasNaturalBlackjack и IsBusted, которые мы только что определили, теперь мы можем создать свойство для отображения оценки объекта Person. Это свойство использует все свойства Person, которые мы определили до сих пор:

Удобные методы - добавление карты и снятие раздачи

Нам все еще нужны два удобных метода, хотя в вашей реализации они могут отсутствовать.

Сначала нам нужен простой способ добавления карт в руку Человека:

Почему мы делаем здесь Task.Delay? Вы узнаете из следующей части этой серии.

Наконец, нам нужен метод, чтобы очистить руку Человека:

Итак, наш корневой объект Person готов! Теперь мы можем перейти к объектам Dealer и Player.

Объект дилера

Начнем с объекта Dealer.

Все улыбаются, кроме одного парня. Изображение из Викимедиа, используется по лицензии.

Дилеру необходимо унаследовать от корневого объекта Person:

Оттуда мы можем добавить свойства, уникальные для Дилера.

Колода карт

Начнем со свойства для объекта CardDeck:

При создании экземпляра CardDeck он создает и перемешивает все необходимые карты.

Дилинг

Для объекта Dealer также потребуются три метода:

  • Метод извлечения карты из колоды.
  • Метод вытягивания карты из колоды для передачи игроку.
  • Метод вытягивания карты из колоды для передачи дилеру.

Эти методы оказываются довольно простыми:

Показывает туз

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

На этом наш дилер готов, и мы можем перейти к реализации объекта Player.

Объект игрока

Объект Player, как и Dealer, должен быть унаследован от Person.

Фонды

Наиболее отличительной чертой игрока является то, что у него есть средства, то есть деньги, с которыми он подошел к столу. Давайте создадим собственность для этих средств и установим начальную сумму:

Нам также нужны свойства для отслеживания ставок игрока: их основная ставка, которую они делают перед каждой рукой, и дополнительная страховая ставка.

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

Сумма изменения

После каждой раздачи средства игрока могут меняться в зависимости от того, выиграл он или проиграл ставку. Напишем свойство, отслеживающее величину этого изменения.

Стоял

Нам нужно удобное свойство, чтобы показать, решил ли игрок встать:

Выплаты

Наконец, нам нужен метод, позволяющий игроку корректировать свойство Funds в зависимости от того, выиграл он или проиграл ставку после каждой раздачи.

Теперь наш объект Player готов и готов поставить свои фишки!

Остерегайтесь, вы, как правило, получаете меньше, чем начинали. Фото Аманды Джонс / Unsplash

Резюме

Уф! Это было много работы. Но теперь наша реализация блэкджека на C # готова к работе, и мы можем приступить к созданию компонентов Blazor, которые будут составлять область отображения игры.

Теперь мы можем создавать компоненты для:

  • Руки игрока и дилера
  • Очки игрока и дилера (видимые и общие)
  • Средства игрока и как они меняются после каждой руки
  • Текущая ставка
  • Статус игрока (например, остались ли они в игре) И
  • Результат раздачи (например, выигрывает или проигрывает игрок)

Реализация этих и других компонентов - именно то, чем мы займемся в следующей части этой серии. Ошиваться!

У вас есть способ улучшить мой дизайн? Отправьте запрос на перенос или дайте мне знать в комментариях! Я всегда жду отзывов моих дорогих читателей.