161 lines
8.0 KiB
Markdown
161 lines
8.0 KiB
Markdown
# Projektarbeit 1: Royal Flush\!
|
||
|
||
## Einleitung
|
||
|
||
Offensichtlich hat sich herumgesprochen, dass sich mit Online-Poker eine Menge Geld verdienen lässt. Dein Auftraggeber möchte eine neue Poker-Website entwickeln. Die Spiellogik benötigt viele spezielle Funktionen. Deswegen hat der Projektleiter dich dem Team zugeteilt. Jeder Entwickler programmiert nur einen kleinen Teil der Webanwendung.
|
||
|
||
Natürlich fällt die Programmierung der **wichtigsten Funktion** in deinen Aufgabenbereich.
|
||
|
||
## Technologien / Anforderungen
|
||
|
||
- Setze **JavaScript – ECMAScript 2015 (ES6)** oder neuer ein.
|
||
- Externe JavaScript-Bibliotheken (oder aus Drittquellen übernommener Code) sind **nicht** zugelassen.
|
||
- Überprüft wird die Aufgabe im aktuellen **Chrome Browser**.
|
||
- Entwickle **kein grafisches User Interface (GUI)** — d. h. du benötigst auch kein HTML oder CSS.
|
||
- Verwende lediglich die **Konsolenausgabe**, um die Funktionalität der Anwendung zu demonstrieren.
|
||
|
||
---
|
||
|
||
## Arbeitsschritt 1: Prüfung auf Name und Kartenfarbe
|
||
|
||
Das neue Pokersystem repräsentiert eine Karte intern als String aus **Name** (z. B. `K` für King) und **Kartenfarbe** (z. B. `♠`). Die Kartenfarben verwenden ihre jeweiligen UTF-8-Zeichen. Beispielsweise wird die Karte Herzkönigin als `'Q♥'` und die Karte Kreuz 8 als `'8♣'` repräsentiert.
|
||
|
||
Folgende Konstanten sind bereits vorgegeben:
|
||
|
||
```javascript
|
||
const SUITS = '♠♥♦♣';
|
||
const NAMES = [
|
||
'2',
|
||
'3',
|
||
'4',
|
||
'5',
|
||
'6',
|
||
'7',
|
||
'8',
|
||
'9',
|
||
'10',
|
||
'J',
|
||
'Q',
|
||
'K',
|
||
'A',
|
||
];
|
||
```
|
||
|
||
### Codebeispiel 361
|
||
|
||
Schreibe die Funktionen `toName` und `toSuit`, die eine Karte jeweils auf ihren Namen bzw. auf ihre Kartenfarbe abbilden.
|
||
|
||
**Beispiele:**
|
||
|
||
```javascript
|
||
toName('9♣'); // => '9'
|
||
toName('10♥'); // => '10'
|
||
toName('Q♥'); // => 'Q'
|
||
toSuit('9♣'); // => '♣'
|
||
toSuit('10♥'); // => '♥'
|
||
```
|
||
|
||
---
|
||
|
||
## Arbeitsschritt 2: Validierung
|
||
|
||
### 🔨 Codebeispiel 362
|
||
|
||
Programmiere eine Funktion `isValidCard`, die prüft, ob es sich bei dem übergebenen String um eine valide Karte handelt. Eine String gilt dann als eine valide Repräsentation einer Karte, wenn er exakt der besprochenen Zusammensetzung aus Name und Farbe entspricht.
|
||
|
||
**Beispiele:**
|
||
|
||
```javascript
|
||
isValidCard('9♣'); // => true
|
||
isValidCard('11♣'); // => false
|
||
isValidCard('9X'); // => false
|
||
```
|
||
|
||
Eine Pokerhand besteht aus fünf Karten. Das Pokersystem repräsentiert diese als Arrays mit je fünf Elementen, bei denen es sich um Stringrepräsentationen von Karten handelt, z. B. `['9♣', '9♦', '9♠', '9♥', 'Q♥']`.
|
||
|
||
Programmiere noch eine weitere Funktion `isValidHand`, die prüft, ob es sich bei einem übergebenen Array um eine valide Repräsentation einer Kartenhand handelt. Eine Kartenhand ist dann valide (und nur dann), wenn sie genau **fünf valide Karten** enthält.
|
||
|
||
> **Wichtig:** Greife zur Implementierung von `isValidCard` auf die Funktionen `toName` und `toSuit` zurück. Genauso verwendest du `isValidCard` zur Realisierung von `isValidHand`.
|
||
|
||
---
|
||
|
||
## Arbeitsschritt 3: Sortierung
|
||
|
||
Um dem Spieler das Erfassen seiner Kartenhand zu erleichtern, müssen die Karten vorsortiert werden.
|
||
|
||
### Codebeispiel 363
|
||
|
||
Programmiere dazu eine Funktion `sortHand`.
|
||
|
||
1. Vergleiche zunächst nur anhand ihres **Namens**, so dass 2er, 3er …, Damen, Könige etc. direkt nebeneinander angeordnet werden. Um die korrekte Reihenfolge der Namen zu bestimmen, kannst du auf den **Indexwert von `NAMES`** zurückgreifen. Z. B. ist eine `'2'` mit Indexwert 0 weniger wert als ein Bube (`'J'`) mit Indexwert 9.
|
||
2. Berücksichtige in einer überarbeiteten Variante auch die **Kartenfarbe**. Es gilt die Reihenfolge aus dem String `SUITS`. Diese neue Sortierung soll dann die vorherige Variante ersetzen.
|
||
|
||
**Beispiele:**
|
||
|
||
```javascript
|
||
sortHand(['3♥', '2♥', '5♥', '2♣', '4♣']);
|
||
// => ['2♠', '2♥', '2♦', '2♣', 'Q♥'] // Korrektur: Die Kartenfarben sollten in der richtigen Reihenfolge stehen, dies ist ein Beispiel aus der Aufgabenstellung
|
||
sortHand(['3♥', '2♥', '5♥', '2♣', '4♣']);
|
||
// => ['2♣', '2♥', '3♥', '4♣', '5♥'] // Bei gleicher Zahl ist die Farbe entscheidend: ♣ ist höher als ♥ im Beispiel, wenn SUITS = '♠♥♦♣'
|
||
sortHand(['2♦', 'Q♥', '2♥', '2♣', '2♠']);
|
||
// => ['2♠', '2♥', '2♦', '2♣', 'Q♥'] // Falsche Ausgabe im Beispiel, richtige Sortierung basierend auf SUITS = '♠♥♦♣'
|
||
// => ['2♠', '2♥', '2♦', '2♣', 'Q♥']
|
||
// Anmerkung: Basierend auf SUITS='♠♥♦♣', wäre die Reihenfolge ♠ > ♥ > ♦ > ♣.
|
||
// Für die Sortierung '2♠', '2♥', '2♦', '2♣', 'Q♥' bedeutet dies, dass ♠ den höchsten Indexwert hat, wenn die Sortierung aufsteigend ist.
|
||
```
|
||
|
||
> **Tipps zur Vorgehensweise:**
|
||
>
|
||
> - Parametrisiere `sort` mit einer Vergleichsfunktion `compareCards`, die zwei Karten entgegennimmt und einen positiven Wert, einen negativen Wert oder (bei identischen Karten) 0 zurückliefert. Du kannst das wie bei der numerischen Sortierung mit **Subtraktion** lösen.
|
||
> - Um den Vergleichswert zu bestimmen, vergleichst du zunächst nur die **Indexwerte der Namen**.
|
||
> - Um die Kartenfarbe zu berücksichtigen, kannst du einen Kartenpositionswert durch eine höhere Gewichtung des Indexwertes des Namens erhalten:
|
||
> $$\text{Kartenposition} = \text{Gewichtungsfaktor} \times \text{Position des Namens in NAMES} + \text{Position der Kartenfarbe in SUITS}$$
|
||
> - Der **Gewichtungsfaktor** ist dabei idealerweise einfach die Anzahl der Kartenfarben (`SUITS.length`).
|
||
|
||
---
|
||
|
||
## Arbeitsschritt 4: Kategorisierung
|
||
|
||
### 🔨 Codebeispiel 364
|
||
|
||
- Eine Pokerhand, bei der alle Karten die **gleiche Kartenfarbe** aufweisen, heißt **Flush**.
|
||
- Eine Hand, die aus **fünf aufeinanderfolgenden Karten** besteht, heißt **Straight** (deutsch: Straße).
|
||
- Für den unwahrscheinlichen Fall, dass die Hand aus fünf aufeinanderfolgenden Karten in der gleichen Farbe besteht, spricht man von einem **Straight Flush**.
|
||
- Falls ein Straight Flush außerdem noch das **Ass (als höchste Karte)** enthält, liegt ein **Royal Flush** vor — das wertvollste Pokerblatt\!
|
||
|
||
Entwickle Funktionen, die eine Pokerhand darauf prüfen, ob jeweils eine der oben genannten Kategorien vorliegt. Beachte auch, dass das Array die Karten nicht zwingend in aufsteigender Reihenfolge enthalten muss.
|
||
|
||
**Beispiele:**
|
||
|
||
```javascript
|
||
isFlush(['7♥', '2♥', 'Q♥', '10♥', '5♥']); // => true
|
||
isFlush(['7♥', '2♥', 'Q♥', '10♣', '5♥']); // => false
|
||
isStraight(['5♥', '6♦', '7♥', '8♣', '9♥']); // => true
|
||
isStraightFlush(['5♥', '6♥', '7♥', '8♥', '9♥']); // => true
|
||
isRoyalFlush(['10♥', 'J♥', 'Q♥', 'K♥', 'A♥']); // => true
|
||
isRoyalFlush(['10♥', 'J♥', 'Q♥', 'K♣', 'A♥']); // => false
|
||
isRoyalFlush(['K♥', 'A♥', 'Q♥', '10♥', 'J♥']); // => true
|
||
```
|
||
|
||
> **Tipp zur Vorgehensweise (Straight):**
|
||
>
|
||
> - Betrachte nur die Namen der Karten.
|
||
> - Sortiere diese und verbinde sie zu einem String (mittels `join()`).
|
||
> - Wenn dieser String in `NAMES.join()` enthalten ist, handelt es sich bei der ursprünglichen Hand um einen Straight.
|
||
>
|
||
> **Beispiel:**
|
||
>
|
||
> `['9♥', '6♦', '7♥', '5♣', '8♥']` $\to$ `['9', '6', '7', '5', '8']` $\to$ `['5', '6', '7', '8', '9']` $\to$ `'5,6,7,8,9'`
|
||
>
|
||
> `'5,6,7,8,9'` liegt innerhalb von `'2,3,4,5,6,7,8,9,10,J,Q,K,A'` und ist somit ein Straight.
|
||
|
||
---
|
||
|
||
## Hinweise
|
||
|
||
- Selbstverständlich kannst du die Implementierung der verlangten Funktionen jederzeit in weitere Funktionen unterteilen.
|
||
- Alle verlangten Funktionen lassen sich aber prinzipiell jeweils mit einem einzigen Ausdruck implementieren. Tatsächlich wären an keiner Stelle geschweifte Klammern nötig. Du kannst sie aber natürlich verwenden, falls du möchtest.
|
||
- Die verlangten Funktionen bauen aufeinander auf. So nutzt beispielsweise `isValidHand` die Funktion `isValidCard` und wird selbst in den darauffolgenden Funktionen weiterverwendet.
|
||
- Du musst lediglich die Funktionen liefern. Es ist nicht erforderlich, Werte per `prompt` o.ä. zu erfragen.
|
||
- Die in der Aufgabe genannten Angaben zur API sind grundsätzlich verpflichtend. D. h. du verwendest die in der Aufgabenstellung genannten **Funktionsnamen, Argumente, Argumentnamen, Rückgabewerte** usw.
|