Blackjack

Blackjack

Exercice d'apprentissage

Introduction

case (souvent appelé switch dans d'autres langages) est une forme d'expression de contrôle, comme if-else. case permet d'enchaîner plusieurs instructions if-else-if, ce qui peut être plus lisible, et autorise des constructions puissantes.

Un case est défini par le mot-clé case, suivi d'une expression facultative. Ensuite, pour chaque cas, on utilise le mot-clé when, suivi d'une expression que l'on compare à l'expression du case. Le mot-clé when ne doit pas être indenté par rapport au mot-clé case. Après le mot-clé when vient le code à exécuter si l'expression du case correspond à l'expression du when. case accepte une instruction else facultative, qui est exécutée si aucun autre cas ne correspond.

L'expression du case est évaluée, puis comparée à chaque expression when. La comparaison utilise l'opérateur de subsomption (===).

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

L'opérateur de subsomption (===)

L'opérateur de subsomption (===) est un peu différent de l'opérateur d'égalité (==). Cet opérateur vérifie si l'opérande de droite est un membre de l'ensemble décrit par l'opérande de gauche. Cela signifie que l'ordre dans lequel les opérandes sont placés a son importance. Le fonctionnement dépend du type de l'opérande de gauche : par exemple, un Range vérifie si l'opérande de droite se trouve dans l'intervalle, tandis qu'un Object vérifie si l'opérande de droite est une instance de Object.

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

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

Le case avec plusieurs expressions

Un case permet de faire correspondre plusieurs expressions dans un seul cas, chaque valeur possible étant séparée par une virgule. Le code est exécuté si l'une des expressions correspond. C'est utile pour un même cas ayant plusieurs valeurs possibles.

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

Le case avec des intervalles

Un case peut aussi vérifier qu'une valeur se trouve dans un intervalle. Pour cela, on utilise un intervalle comme expression when.

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

Le case sans expression

Quand l'expression du case n'est pas nécessaire, il est possible de l'omettre. Chaque expression when est alors évaluée pour sa valeur de vérité, ce qui les fait se comporter comme des instructions 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

Le when sur une seule ligne

Crystal autorise les instructions case sur une seule ligne. C'est utile lorsque l'instruction tient sur une ligne simple. La forme sur une seule ligne s'écrit when <expression> then <statement>. Et dans l'instruction else, elle s'écrit else <statement>.

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

Le case avec des types

case permet de faire correspondre des types. La comparaison utilise l'opérateur is_a? pour vérifier le type de la variable. Cela permet par exemple d'avoir une branche pour chaque type d'un type union.

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

L'objet implicite

case permet d'utiliser un objet implicite. Une expression when peut alors être, par exemple, un appel de méthode sur l'expression du case. Selon que la méthode renvoie une valeur considérée comme vraie ou comme fausse, le cas correspond ou non.

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

Instructions

Dans cet exercice, on va simuler le premier tour d'une partie de Blackjack.

1. Calcule la valeur d'une carte.

Tu recevras deux cartes et pourras voir la carte visible du croupier. Toutes les cartes sont représentées par une string telle que « ace », « king », « three », « two », etc. Les valeurs de chaque carte sont les suivantes :

carte valeur carte valeur
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 autre 0
Note

Le plus souvent, un as peut valoir 1 ou 11, mais pour simplifier, on considérera qu'il ne peut valoir que 11.

Implémente la méthode Blackjack.parse_card qui prend une carte sous forme de string en argument. La méthode doit renvoyer la valeur de la carte sous forme d'entier.

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

2. Nomme les intervalles de valeurs.

Le score du joueur doit être classé dans des intervalles de valeurs. Les scores du joueur s'obtiennent en additionnant les valeurs de ses deux cartes. Les intervalles utilisés sont les suivants :

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

Implémente la méthode Blackjack.card_range qui prend deux cartes sous forme de strings en argument. La méthode doit renvoyer le nom de l'intervalle dans lequel tombent les deux cartes.

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

3. Implémente la logique de décision du premier tour.

Selon tes deux cartes et la carte du croupier, il existe une stratégie pour le premier tour de la partie, qui te donne les options suivantes :

  • Rester (S)
  • Tirer (H)
  • Séparer (P)
  • Gagner automatiquement (W)

Même si elle n'est pas encore optimale, tu vas suivre la stratégie que ton ami Alex a développée, qui est la suivante :

  • Si tu as une paire d'as, tu dois toujours les séparer.
  • Si tu as un blackjack (deux cartes dont la somme vaut 21) et que le croupier n'a ni « ace », ni figure, ni « ten », tu gagnes automatiquement. Si le croupier a l'une de ces cartes, tu devras rester et attendre que l'autre carte soit révélée.
  • Si la somme de tes cartes se situe dans l'intervalle [17, 20], tu dois toujours rester.
  • Si la somme de tes cartes se situe dans l'intervalle [12, 16], tu dois toujours rester, sauf si le croupier a un 7 ou plus, auquel cas tu dois toujours tirer.
  • Si la somme de tes cartes vaut 11 ou moins, tu dois toujours tirer.

Implémente la méthode Blackjack.first_turn qui prend trois cartes sous forme de strings en argument. La méthode doit renvoyer la décision à prendre sous forme de string.

Blackjack.first_turn("ace", "ace", "two")
# => "P"
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Crystal Exercism

Prêt à commencer Blackjack ?

Inscris-toi sur Exercism pour apprendre et maîtriser Crystal avec 26 concepts142 exercices, et un vrai mentorat humain, le tout gratuitement.