Blackjack

Blackjack

Lernübung

Einführung

case (in anderen Sprachen oft „switch“ genannt) ist eine Art Kontrollausdruck, ähnlich wie if-else. Mit case lassen sich mehrere if-else-if-Anweisungen verketten, das kann lesbarer sein und ermöglicht mächtige Konstrukte.

Ein case wird durch das Schlüsselwort case eingeleitet, auf das ein optionaler Ausdruck folgt. Dann wird für jeden Fall das Schlüsselwort when verwendet, gefolgt von einem Ausdruck, der mit dem case-Ausdruck verglichen wird. Das Schlüsselwort when sollte nicht gegenüber dem Schlüsselwort case eingerückt werden. Nach dem Schlüsselwort when folgt der Code, der ausgeführt werden soll, wenn der case-Ausdruck zum when-Ausdruck passt. Case erlaubt eine optionale else-Anweisung, die ausgeführt wird, wenn kein anderer Fall passt.

Der case-Ausdruck wird ausgewertet und dann mit jedem when-Ausdruck verglichen. Der Vergleich erfolgt mit dem Case-Subsumptionsoperator (===).

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-Subsumptionsoperator (===)

Der Case-Subsumptionsoperator (===) unterscheidet sich ein wenig vom Gleichheitsoperator (==). Der Operator prüft, ob die rechte Seite ein Element der Menge ist, die die linke Seite beschreibt. Das bedeutet, dass es sehr wohl darauf ankommt, an welcher Stelle die einzelnen Operanden stehen. Wie das genau funktioniert, hängt vom Typ der linken Seite ab: Eine Range prüft zum Beispiel, ob die rechte Seite im Bereich liegt, und ein Object prüft, ob die rechte Seite eine Instanz des Object ist.

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

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

Case mit mehreren Ausdrücken

In einem Case lassen sich mehrere Ausdrücke gleichzeitig abgleichen, wobei die einzelnen möglichen Werte durch ein Komma getrennt werden. Der Code wird ausgeführt, wenn einer der Ausdrücke passt. Das ist nützlich, wenn ein einzelner Fall mehrere mögliche Werte haben kann.

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

Cases mit Bereichen

Ein Case kann auch prüfen, ob ein Wert in einem Bereich liegt. Dazu verwendest du einen Bereich als when-Ausdruck.

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

Cases ohne case-Ausdruck

Wenn du keinen case-Ausdruck brauchst, kannst du ihn weglassen. Dadurch wird jeder when-Ausdruck auf seinen Wahrheitswert geprüft. So verhalten sie sich wie if-else-if-Anweisungen.

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

Einzeiliges when

Crystal erlaubt einzeilige Case-Anweisungen. Das bietet sich an, wenn du eine einfache einzeilige Anweisung hast. Die einzeilige when-Anweisung wird als when <expression> then <statement>. geschrieben. Und in der else-Anweisung wird sie als else <statement> geschrieben.

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

Case mit Typen

Case erlaubt auch den Abgleich mit Typen. Der Vergleich verwendet den Operator is_a?, um den Typ der Variable zu prüfen. So kannst du zum Beispiel für jeden Typ eines Union-Typs einen eigenen Zweig angeben.

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

Implizites Objekt

Case erlaubt die Verwendung eines impliziten Objekts. Damit kann ein when-Ausdruck zum Beispiel ein Methodenaufruf auf dem case-Ausdruck sein. Je nachdem, ob die Methode einen truthy- oder falsey-Wert zurückgibt, passt das Case oder nicht.

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

Anleitung

In dieser Übung simulieren wir den ersten Zug eines Blackjack-Spiels.

1. Berechne den Wert einer beliebigen Karte.

Du bekommst zwei Karten und siehst die offene Karte des Dealers. Alle Karten werden durch einen String wie „ace“, „king“, „three“, „two“ usw. dargestellt. Die Werte der einzelnen Karten sind:

Karte Wert Karte Wert
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
Note

Üblicherweise können Asse den Wert 1 oder 11 annehmen, aber der Einfachheit halber gehen wir davon aus, dass sie nur den Wert 11 annehmen können.

Implementiere die Methode Blackjack.parse_card, die eine Karte als String-Argument entgegennimmt. Die Methode sollte den Wert der Karte als Ganzzahl zurückgeben.

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

2. Benenne Wertebereiche.

Der Punktestand eines Spielers muss in Wertebereiche eingeteilt werden. Der Punktestand eines Spielers wird berechnet, indem man die Werte seiner beiden Karten addiert. Die verwendeten Bereiche sind:

Bereich Wert
low [4, 11]
mid [12, 16]
high [17, 20]
blackjack [21]

Implementiere die Methode Blackjack.card_range, die zwei Karten als String-Argumente entgegennimmt. Die Methode sollte den Namen des Wertebereichs zurückgeben, in den die beiden Karten fallen.

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

3. Implementiere die Entscheidungslogik für den ersten Zug.

Je nach deinen beiden Karten und der Karte des Dealers gibt es eine Strategie für den ersten Zug des Spiels, bei dem du die folgenden Optionen hast:

  • Stehen (S)
  • Ziehen (H)
  • Splitten (P)
  • Automatisch gewinnen (W)

Zwar ist die Strategie noch nicht optimal, aber du folgst der Strategie, die dein Freund Alex entwickelt hat. Sie sieht so aus:

  • Wenn du ein Paar Asse hast, musst du es immer splitten.
  • Wenn du einen Blackjack hast (zwei Karten, die zusammen einen Wert von 21 ergeben) und der Dealer weder ein Ass noch eine Bildkarte noch eine Zehn hat, gewinnst du automatisch. Hat der Dealer eine dieser Karten, musst du stehen und warten, bis die andere Karte aufgedeckt wird.
  • Wenn deine Karten zusammen einen Wert im Bereich [17, 20] ergeben, solltest du immer stehen.
  • Wenn deine Karten zusammen einen Wert im Bereich [12, 16] ergeben, solltest du immer stehen, es sei denn, der Dealer hat eine 7 oder höher. In dem Fall solltest du immer ziehen.
  • Wenn deine Karten zusammen 11 oder weniger ergeben, solltest du immer ziehen.

Implementiere die Methode Blackjack.first_turn, die drei Karten als String-Argumente entgegennimmt. Die Methode sollte die Entscheidung, die du treffen solltest, als String zurückgeben.

Blackjack.first_turn("ace", "ace", "two")
# => "P"
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Crystal Exercism

Bereit, mit Blackjack zu starten?

Melde dich bei Exercism an, um Crystal mit 26 Konzepte142 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.