Blackjack

Blackjack

Exercício de aprendizagem

Introdução

A função switch() pode ser um substituto conciso para uma longa série de testes if ... else if. A variável sobre a qual se faz o switch é, habitualmente, uma string e, nesse caso, as aspas podem ser omitidas do seletor.

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"

Repara que as opções só passam para a seguinte se o valor for deixado em branco, como acontece com M no exemplo acima. Não é preciso incluir instruções break, ao contrário do que acontece em algumas outras linguagens.

Quando se faz o switch sobre o tipo character, o valor final é um valor predefinido, como aqui. Com tipos inteiros, não é possível indicar nenhum valor predefinido.

Funções em dplyr

O switch do R base é bastante limitado: só faz uma correspondência exata com um único valor de entrada. Isto parecia razoável quando o R foi lançado, em 1993, mas precisa de melhorias para o uso moderno.

Note

Como foi referido no Conceito Conditionals, a coleção de pacotes tidyverse foi concebida para complementar (e, por vezes, substituir) a funcionalidade do R base sem afetar a compatibilidade retrocompatível.

O pacote dplyr pode ser trazido para o âmbito adicionando library(dplyr) (para o pacote individual) ou library(tidyverse) (para a coleção completa) ao topo do teu código.

A biblioteca dplyr fornece duas funções extra relacionadas com o switch.

As funções recode_values e replace_values

Estas duas funções relacionadas permitem um mapeamento vetorizado, semelhante ao switch, de valores antigos para valores novos.

A principal diferença entre elas é que recode_values() cria um vetor completamente novo, enquanto replace_values() permite atualizações parciais de um vetor existente.

A correspondência continua a ser exata, mas:

  • As opções à esquerda podem ser vetores, e o valor de entrada corresponde se algum elemento corresponder.
  • As opções à esquerda e os resultados à direita são ligados com uma tilde ~ em vez de =.
  • Em todos os casos é possível indicar um valor predefinido.
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

A função case_when

A função case_when leva a sintaxe do case_match um passo mais além, ao permitir qualquer expressão lógica à esquerda do ~.

O vetor de entrada (x no exemplo abaixo) não é fornecido como argumento, só precisa de já estar definido.

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?"

A função between() também faz parte do dplyr.

Instruções

Neste exercício vamos simular a primeira jogada de um jogo de Blackjack.

Vais receber duas cartas e vais poder ver a carta destapada do dealer. Todas as cartas são representadas por uma string como "ace", "king", "three", "two", etc. Os valores de cada carta são:

carta valor carta valor
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

Nota: Normalmente, os ases podem valer 1 ou 11, mas, para simplificar, vamos assumir que só podem valer 11.

Dependendo das tuas duas cartas e da carta do dealer, existe uma estratégia para a primeira jogada, na qual tens as seguintes opções:

  • Ficar (S)
  • Pedir carta (H)
  • Dividir (P)
  • Ganhar automaticamente (W)

Embora ainda não seja a ideal, vais seguir a estratégia que o teu amigo Alex anda a desenvolver, que é a seguinte:

  • Se tiveres um par de ases, tens sempre de os dividir.
  • Se tiveres um Blackjack (duas cartas que somam 21) e o dealer não tiver um ás, uma figura ou um dez, ganhas automaticamente. Se o dealer tiver alguma dessas cartas, tens de ficar e esperar que a outra carta seja revelada.
  • Se as tuas cartas somarem um valor dentro do intervalo [17, 20], deves ficar sempre.
  • Se as tuas cartas somarem um valor dentro do intervalo [12, 16], deves ficar sempre, a não ser que o dealer tenha um 7 ou mais; nesse caso, deves pedir carta sempre.
  • Se as tuas cartas somarem 11 ou menos, deves pedir carta sempre.

1. Calcula o valor de uma carta qualquer.

Implementa uma função parse_card para calcular o valor numérico de uma carta:

parse_card("ace")
# => 11

2. Implementa a lógica de decisão para a primeira jogada.

Escreve uma função first_turn que implementa a lógica de decisão descrita acima:

first_turn(card1, card2, dealer_card)

Aqui estão alguns exemplos dos resultados esperados:

first_turn("ace", "ace", "jack") == "P"
first_turn("ace", "king", "ace") == "S"
first_turn("five", "queen", "ace") == "H"
Editar via GitHub A ligação abre numa nova janela ou separador
R Exercism

Estás pronto para começar Blackjack?

Inscreve-te no Exercism para aprenderes e dominares R com 21 conceitos111 exercícios, e mentoria humana real, tudo grátis.