Blackjack-Basisstrategie in JavaScript umsetzen
Ein ausführlicher Guide für Entwickler: die Basisstrategie als JSON abbilden und im Code blitzschnell nachschlagen.
Warum die Basisstrategie in den Code gehört
Die Basisstrategie ist eine deterministische Entscheidungstabelle, die den Hausvorteil auf nur 0,5 % senkt. Wenn du einen Simulator, einen Trainer oder einen KI-gestützten Dealer baust, ist es viel einfacher und besser wartbar, diese Tabelle als strukturierte Daten (JSON) abzulegen und mit einer schnellen Lookup-Funktion abzufragen, als Hunderte verschachtelter Bedingungen zu schreiben.
Dieser Ansatz trennt Daten von Logik. Dein Code wird dadurch lesbarer, besser testbar und lässt sich leichter an andere Regelvarianten anpassen. Ob Casinospiel, Trainings-App oder Statistiktool: Dieses Muster spart dir Zeit und vermeidet Bugs.
Datenmodell: JSON-Nachschlagetabelle
Speichere die Strategietabelle als JSON-Objekt. Jeder Schlüssel steht für die Zeile der Spielerhand (harte Summen, weiche Summen und Paare), jeder Wert ist eine Zuordnung von der offenen Dealerkarte zum Aktionscode:
// small excerpt (full table would include all rows)
const blackjackStrategy = {
"5-8": {"2":"H","3":"H","4":"H","5":"H","6":"H","7":"H","8":"H","9":"H","10":"H","A":"H"},
"9": {"2":"H","3":"D","4":"D","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"10": {"2":"D","3":"D","4":"D","5":"D","6":"D","7":"D","8":"D","9":"D","10":"H","A":"H"},
"11": {"2":"D","3":"D","4":"D","5":"D","6":"D","7":"D","8":"D","9":"D","10":"D","A":"D"},
"12": {"2":"H","3":"H","4":"S","5":"S","6":"S","7":"H","8":"H","9":"H","10":"H","A":"H"},
"13": {"2":"S","3":"S","4":"S","5":"S","6":"S","7":"H","8":"H","9":"H","10":"H","A":"H"},
"14": {"2":"S","3":"S","4":"S","5":"S","6":"S","7":"H","8":"H","9":"H","10":"H","A":"H"},
"15": {"2":"S","3":"S","4":"S","5":"S","6":"S","7":"H","8":"H","9":"H","10":"SR","A":"SR"},
"16": {"2":"S","3":"S","4":"S","5":"S","6":"S","7":"H","8":"H","9":"SR","10":"SR","A":"SR"},
"A2": {"2":"H","3":"H","4":"H","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"A3": {"2":"H","3":"H","4":"H","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"A4": {"2":"H","3":"H","4":"D","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"A5": {"2":"H","3":"H","4":"D","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"A6": {"2":"H","3":"D","4":"D","5":"D","6":"D","7":"H","8":"H","9":"H","10":"H","A":"H"},
"A7": {"2":"D/S","3":"D/S","4":"D/S","5":"D/S","6":"D/S","7":"S","8":"S","9":"H","10":"H","A":"H"},
"2-2": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"P","8":"H","9":"H","10":"H","A":"H"},
"3-3": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"P","8":"H","9":"H","10":"H","A":"H"},
"4-4": {"2":"H","3":"H","4":"H","5":"P","6":"P","7":"H","8":"H","9":"H","10":"H","A":"H"},
"6-6": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"H","8":"H","9":"H","10":"H","A":"H"},
"7-7": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"P","8":"H","9":"H","10":"H","A":"H"},
"8-8": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"P","8":"P","9":"P","10":"P","A":"SP"},
"9-9": {"2":"P","3":"P","4":"P","5":"P","6":"P","7":"S","8":"P","9":"P","10":"S","A":"S"}
};
Der Auszug folgt der Basisstrategie-Tabelle für 6 Decks, Dealer zieht bei weicher 17, Verdoppeln auf beliebige zwei Karten, Verdoppeln nach dem Teilen erlaubt, spätes Aufgeben.
- H
- Karte
- S
- Halten
- D
- Verdoppeln (sonst Karte)
- P
- Teilen
- SR
- Aufgeben (sonst Karte)
- SP
- Aufgeben (sonst Teilen)
- D/S
- Verdoppeln, sonst Halten
Lookup-Funktion: einfach und schnell
Mit einer kleinen Funktion schlägst du den empfohlenen Zug über den Tabellenschlüssel und die offene Dealerkarte nach. Sie gibt direkt den Aktionscode zurück und hat die Komplexität O(1).
// Lookup-Funktion
function getBlackjackAction(playerHand, dealerCard, strategyTable) {
if (!strategyTable) strategyTable = blackjackStrategy; // ohne Parameter auf die globale Tabelle zurückgreifen
playerHand = String(playerHand).toUpperCase();
dealerCard = String(dealerCard).toUpperCase();
const row = strategyTable[playerHand];
if (!row) return null; // unbekannte Zeile
return row[dealerCard] || null; // Aktion oder null bei unbekannter Dealerkarte
}
// Beispiele
console.log(getBlackjackAction("A7", "6")); // "D/S"
console.log(getBlackjackAction("16", "10")); // "SR"
console.log(getBlackjackAction("9-9", "7")); // "S"
So bleiben Strategie und Logik getrennt: Das JSON sind die Daten, die Funktion ist der Lookup bzw. Adapter. Regelvarianten (z. B. Dealer zieht/hält bei weicher 17 oder andere Regeln zum Aufgeben) tauschst du ganz einfach aus, indem du ein anderes JSON-Objekt lädst.
Sofortige Lookups
Komplexität O(1) bedeutet gleichbleibende Performance, auch bei komplizierten Regelvarianten.
Einfache Wartung
Du änderst Strategieregeln in den JSON-Daten statt in verschachtelter Bedingungslogik.
Skalierbares Design
Ideal für Simulationen, die Tausende Hände pro Sekunde durchspielen.
Erweiterung für echte Karten als Eingabe
Im Produktiveinsatz soll die Funktion vielleicht rohe Karten (z. B. ['A','6']) statt vorberechneter Zeilenschlüssel annehmen.
Schreib dafür einen kleinen Normalisierer, der:
- Paare erkennt (beide Ränge gleich) → Zeile wie
"8-8" - weiche Summen erkennt (enthält ein Ass, das als 11 zählt) → Zeile wie
"A6" - sonst auf harte Summen zurückfällt (Zahlensumme) → Zeile wie
"16"
// Beispiel für einen Normalisierer (sehr klein)
function normalizeHand(cards) {
// cards: Array mit Rängen, z. B. ['A','6'] oder ['9','9'] oder ['10','6']
const ranks = cards.map(c => String(c).toUpperCase());
if (ranks.length === 2 && ranks[0] === ranks[1]) {
// Paar
return `${ranks[0]}-${ranks[1]}`;
}
const hasAce = ranks.includes('A');
const numeric = ranks.reduce((sum, r) => sum + (r === 'A' ? 11 : (r === 'J' || r === 'Q' || r === 'K' ? 10 : parseInt(r,10) || 0)), 0);
// einfache Erkennung weicher Hände bei zwei Karten
if (hasAce && ranks.length === 2) {
const other = ranks.find(r => r !== 'A');
return `A${other}`;
}
return String(numeric);
}
Kombiniere den Normalisierer mit getBlackjackAction, damit sowohl strukturierte Schlüssel als auch rohe Karten-Arrays funktionieren. So wird deine API flexibler und angenehmer zu benutzen.
Warum Entwickler dieses Modell nutzen sollten
Klarheit
Der datengetriebene Ansatz hält die Logik lesbar und wartbar. Schluss mit Spaghetticode aus verschachtelten if-Anweisungen.
Performance
Lookup in konstanter Zeit, ideal für Simulationen mit Tausenden Händen pro Minute.
Flexibilität
Tausche Tabellen für Regelvarianten aus oder baue Trainingsmodi, ohne deine Kernlogik anzufassen.
Testbarkeit
Lässt sich mit verschiedenen Strategietabellen und Grenzfällen leicht per Unit-Test prüfen.
Modularität
Strategiedaten lassen sich unabhängig aus Dateien, APIs oder Datenbanken laden.
Internationalisierung
Unterstütze regionale Blackjack-Varianten mit separaten JSON-Dateien.
Ressourcen & nächste Schritte
Bereit, das Gelernte anzuwenden? Probier unseren interaktiven Trainer aus und sieh die Basisstrategie in Aktion:
21Count — interaktiver Basisstrategie-Trainer
Komplette JavaScript-Datei mit Beispielen herunterladen
Enthält die vollständige Strategietabelle, Lookup-Funktionen, den Normalisierer und Anwendungsbeispiele – bereit für deine Projekte.