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

Блекджек

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

Вступ

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

star <- function(type) {
  switch(type,
    M = , # will "fall through" if no value given
    K = "red dwarf",
    G = "Earth-like",
    "bigger star" # only correct for O,B,A,F
  )
}

> star("M")
[1] "red dwarf"

Зауважмо, що варіанти переходять далі лише тоді, коли значення залишено порожнім, як у випадку M у прикладі вище. Немає потреби додавати інструкції break, як у деяких інших мовах.

Коли перемикання відбувається за типами character, останнє значення є типовим, як тут. З цілими числами типове значення вказати не можна.

Функції в dplyr

switch у базовому R досить обмежений: він робить точний збіг лише з одними вхідними даними. Це здавалося розумним, коли R уперше вийшов 1993 року, але для сучасного використання його треба вдосконалити.

Note

Як зазначено в концепції Conditionals, набір пакетів tidyverse створено, щоб доповнювати (а іноді й замінювати) функціональність базового R, не порушуючи зворотної сумісності.

Пакет dplyr можна залучити в область видимості, додавши library(dplyr) (для одного пакета) або library(tidyverse) (для всього набору) на початок коду.

Бібліотека dplyr надає дві додаткові функції, повʼязані зі switch.

Функції recode_values і replace_values

Ці дві споріднені функції дають змогу векторно зіставляти старі значення з новими за принципом, схожим на switch.

Головна різниця між ними в тому, що recode_values() створює цілком новий вектор, а replace_values() дає змогу частково оновлювати наявний вектор.

Зіставлення все ще точне, але:

  • Варіанти ліворуч можуть бути векторами, і вхідні дані збігаються, якщо збігається будь-який елемент.
  • Варіанти ліворуч і результати праворуч зʼєднуються тильдою ~, а не знаком =.
  • Типове значення можна вказати в усіх випадках.
library(dplyr)

x <- c("a", "b", "a", "d", "b", NA, "c", "e", "z")
recode_values(
  x,
  "a" ~ 1,
  "b" ~ 2,
  "c" ~ 3,
  c("d", "e") ~ 4, # either "d' or "e" will match
  NA ~ 0,          # matches missing values
  default = 100   # note the different syntax for the default
)
#> [1]   1   2   1   4   2   0   3   4 100

Функція case_when

case_when робить наступний крок у синтаксисі case_match, дозволяючи будь-який логічний вираз ліворуч від ~.

Вхідний вектор (x у прикладі нижче) не передається як аргумент, він просто має бути вже визначеним.

x <- 1:10
case_when(
  x < 3 ~ "low",
  between(x, 3, 5) ~ "mid",
  between(x, 6, 8) ~ "high",
  .default = "what?"
)
#>  [1] "low"   "low"   "mid"   "mid"   "mid"   "high"  "high"  "high"  "what?" "what?"

Функція between() також є частиною dplyr.

Вказівки

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

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

карта значення карта значення
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 other 0

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

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

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

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

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

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

Реалізувати функцію parse_card, щоб обчислити числове значення карти:

parse_card("ace")
# => 11

2. Реалізувати логіку рішень для першого ходу.

Написати функцію first_turn, яка реалізує описану вище логіку рішень:

first_turn(card1, card2, dealer_card)

Ось кілька прикладів очікуваних результатів:

first_turn("ace", "ace", "jack") == "P"
first_turn("ace", "king", "ace") == "S"
first_turn("five", "queen", "ace") == "H"
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
R Exercism

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

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