Треки
/
Crystal
Crystal
/
Вправи
/
Блекджек
Блекджек

Блекджек

Навчальна вправа

Вступ

case (в інших мовах його часто називають switch) належить до керуючих виразів, як і if-else. case дає змогу обʼєднувати в ланцюжок кілька інструкцій if-else-if, буває читабельнішим і уможливлює потужні конструкції.

case визначають ключовим словом case, після якого йде необовʼязковий вираз. Далі для кожної гілки використовують ключове слово when, після якого йде вираз, що порівнюється з виразом case. Ключове слово when не повинно мати відступу відносно ключового слова case. Після ключового слова when іде код, який потрібно виконати, якщо вираз case збігається з виразом when. case дозволяє необовʼязкову інструкцію else, яка виконується, якщо жодна інша гілка не збігається.

Вираз case обчислюється, а потім порівнюється з кожним виразом when. Порівняння виконується за допомогою оператора підпорядкування case (===).

case 1
when 1
  puts "One"
when 2
  puts "Two"
else
  puts "Other"
end
# => One

# This is the same as:
tmp = 1
if 1 === tmp
  puts "One"
elsif 2 === tmp
  puts "Two"
else
  puts "Other"
end

Оператор підпорядкування case (===)

Оператор підпорядкування case (===) дещо відрізняється від оператора рівності (==). Він перевіряє, чи права частина належить до множини, описаної лівою частиною. Це означає, що порядок операндів має значення. Як саме це працює, залежить від типу лівої частини: наприклад, Range перевірить, чи права частина входить у діапазон, а Object перевірить, чи права частина є екземпляром Object.

(1..3) == 1  # => false
(1..3) === 1 # => true

String == "foo"  # => false
String === "foo" # => true

case з кількома виразами

case дає змогу зіставити кілька виразів в одній гілці, розділяючи кожне можливе значення комою. Код виконається, якщо збігається будь-який із виразів. Це буває корисно, коли в одній гілці може бути кілька можливих значень.

case 1
when 1, 2
  puts "One or two"
else
  puts "Other"
end

case з діапазонами

case також може перевіряти, чи значення належить діапазону. Для цього як вираз when використовують діапазон.

case var
when 1..3
  puts "One to three"
else
  puts "Other"
end

case без виразу case

Коли вираз case не потрібен, його можна опустити. Тоді кожен вираз when перевіряється на істинність. Це робить конструкцію схожою на інструкції if-else-if.

case
when 1 == 1
  puts "One is equal to one"
when 1 > 2
  puts "One is greater than two"
else
  puts "Other"
end

when в один рядок

Crystal дозволяє записувати case в один рядок. Це можна використати, коли потрібна проста однорядкова інструкція. Гілку when в один рядок записують як when <expression> then <statement>. А в інструкції else це має такий вигляд: else <statement>.

case var
when 1 then puts "One"
when 2 then puts "Two"
else puts "Other"
end

case з типами

case дає змогу зіставляти за типами. Для порівняння використовується оператор is_a?, який перевіряє тип змінної. Наприклад, це дає змогу мати окрему гілку для кожного типу в обʼєднаному типі.

case var
when Int32
  puts "Int32"
when String
  puts "String"
else
  puts "Other"
end

Неявний обʼєкт

case дає змогу використовувати неявний обʼєкт. Завдяки цьому вираз when може бути, наприклад, викликом методу на виразі case. Залежно від того, чи повертає метод істинне значення, гілка збігається або ні.

case 1
when .odd?
  puts "Odd"
when .even?
  puts "Even"
end

Вказівки

У цій вправі ми змоделюємо перший хід гри в блекджек.

1. Обчислимо значення будь-якої карти.

Ми отримаємо дві карти й побачимо відкриту карту дилера. Усі карти подано як рядок тексту (англ. string), наприклад "ace", "king", "three", "two" тощо. Значення кожної карти такі:

card value card value
ace 11 eight 8
two 2 nine 9
three 3 ten 10
four 4 jack 10
five 5 queen 10
six 6 king 10
seven 7 інші 0
Note

Зазвичай тузи можуть мати значення 1 або 11, але для простоти припустімо, що вони можуть мати лише значення 11.

Реалізуйте метод Blackjack.parse_card, який приймає карту як рядок тексту в аргументі. Метод має повернути значення карти як ціле число.

Blackjack.parse_card("ace")
# => 11

2. Назвімо діапазони значень.

Рахунок гравця треба розподілити за діапазонами значень. Рахунок гравця обчислюється додаванням значень двох карт гравця. Використовуються такі діапазони:

range value
low [4, 11]
mid [12, 16]
high [17, 20]
blackjack [21]

Реалізуйте метод Blackjack.card_range, який приймає дві карти як рядки тексту в аргументах. Метод має повернути назву діапазону значень, до якого належать ці дві карти.

Blackjack.card_range("ten", "king")
# => "high"

3. Реалізуємо логіку ухвалення рішень для першого ходу.

Залежно від наших двох карт і карти дилера для першого ходу в грі є стратегія, яка передбачає такі варіанти:

  • Зупинитися (S)
  • Взяти карту (H)
  • Розділити (P)
  • Автоматична перемога (W)

Хоча вона ще не оптимальна, ми будемо дотримуватися стратегії, яку розробляє наш друг Алекс. Ось вона:

  • Якщо в нас пара тузів, їх треба завжди розділяти.
  • Якщо в нас блекджек (дві карти, які в сумі дають 21), і в дилера немає туза, фігурної карти чи десятки, ми автоматично перемагаємо. Якщо ж у дилера є одна з цих карт, доведеться зупинитися й чекати, поки відкриють другу карту.
  • Якщо сума наших карт потрапляє в діапазон [17, 20], треба завжди зупинятися.
  • Якщо сума наших карт потрапляє в діапазон [12, 16], треба завжди зупинятися, крім випадку, коли в дилера 7 або більше: тоді треба завжди брати карту.
  • Якщо сума наших карт 11 або менше, треба завжди брати карту.

Реалізуйте метод Blackjack.first_turn, який приймає три карти як рядки тексту в аргументах. Метод має повернути рішення, яке треба ухвалити, як рядок тексту.

Blackjack.first_turn("ace", "ace", "two")
# => "P"
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Crystal Exercism

Час розпочати Блекджек?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Crystal, а також 26 концепцій142 вправи та справжнє наставництво від людей, і все це безкоштовно.