Cómo implementar la estrategia básica del blackjack en JavaScript

Una guía completa para desarrolladores sobre cómo representar la estrategia básica en JSON y hacer consultas ultrarrápidas desde el código.

Aprende la estrategia básica: entrenador interactivo

Por qué la estrategia básica encaja en el código

La estrategia básica es una tabla de decisiones determinista que reduce la ventaja de la casa a solo un 0,5 %. Si desarrollas un simulador, un entrenador o un crupier asistido por IA, codificar esa tabla como datos estructurados (JSON) y usar una función de consulta rápida es mucho más sencillo y fácil de mantener que cientos de condicionales anidados.

Este enfoque separa los datos de la lógica, con lo que tu código es más legible, más fácil de probar y se adapta mejor a distintas variantes de reglas. Tanto si creas un juego de casino como una aplicación de entrenamiento o un analizador estadístico, este patrón te ahorrará tiempo y errores.

Modelo de datos: tabla de consulta en JSON

Guarda la tabla de estrategia como un objeto JSON. Cada clave representa la fila de la mano del jugador (totales duros, totales blandos y parejas), y cada valor es un mapa de la carta visible del crupier al código de acción:

Tabla de estrategia en JSON
// 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"}
};

El extracto sigue la tabla de estrategia básica para estas reglas: 6 barajas, el crupier pide con 17 blando, doblar con dos cartas cualesquiera, doblar tras dividir permitido, rendición tardía.

H
Pedir
S
Plantarse
D
Doblar (si no, pedir)
P
Dividir
SR
Rendirse (si no, pedir)
SP
Rendirse (si no, dividir)
D/S
Doblar; si no, plantarse

Función de consulta: sencilla y rápida

Usa una pequeña función para obtener la jugada recomendada a partir de la clave de la tabla y la carta visible del crupier. Devuelve directamente el código de acción y tiene complejidad O(1).

Función de consulta en JavaScript
// función de consulta
function getBlackjackAction(playerHand, dealerCard, strategyTable) {
  if (!strategyTable) strategyTable = blackjackStrategy; // usa la tabla global si no se pasa ninguna
  playerHand  = String(playerHand).toUpperCase();
  dealerCard  = String(dealerCard).toUpperCase();

  const row = strategyTable[playerHand];
  if (!row) return null; // fila desconocida
  return row[dealerCard] || null; // acción, o null si la carta del crupier es desconocida
}

// ejemplos
console.log(getBlackjackAction("A7", "6"));   // "D/S"
console.log(getBlackjackAction("16", "10"));  // "SR"
console.log(getBlackjackAction("9-9", "7"));  // "S"

Así la estrategia y la lógica quedan separadas: el JSON son los datos y la función es la consulta/adaptador. Es fácil cambiar a otras variantes de reglas (por ejemplo, que el crupier pida o se plante con 17 blando, u otras reglas de rendición) cargando otro objeto JSON.

Consultas instantáneas

La complejidad O(1) garantiza un rendimiento constante incluso con variantes de reglas complejas.

Mantenimiento sencillo

Actualiza las reglas de estrategia modificando datos JSON, no una lógica condicional complicada.

Diseño escalable

Perfecto para simulaciones que juegan miles de manos por segundo.

Ampliación para cartas reales

En producción quizá quieras que la función acepte cartas tal cual (p. ej. ['A','6']) en lugar de claves de fila ya calculadas. Implementa un pequeño normalizador que:

  • detecte parejas (los dos valores iguales) → fila como "8-8"
  • detecte totales blandos (con un As que cuenta como 11) → fila como "A6"
  • recurra a los totales duros (suma numérica) → fila como "16"
Función normalizadora de manos
// ejemplo de normalizador (muy pequeño)
function normalizeHand(cards) {
  // cards: array de valores, p. ej. ['A','6'], ['9','9'] o ['10','6']
  const ranks = cards.map(c => String(c).toUpperCase());
  if (ranks.length === 2 && ranks[0] === ranks[1]) {
    // pareja
    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);
  // detección sencilla de manos blandas de dos cartas
  if (hasAce && ranks.length === 2) {
    const other = ranks.find(r => r !== 'A');
    return `A${other}`;
  }
  return String(numeric);
}

Combina el normalizador con getBlackjackAction para aceptar tanto claves estructuradas como arrays de cartas. Así tu API será más flexible y cómoda de usar.

Por qué los desarrolladores deberían usar este modelo

Claridad

El enfoque basado en datos mantiene la lógica legible y fácil de mantener. Se acabó el código espagueti con if anidados.

Rendimiento

Consultas en tiempo constante, aptas para simulaciones que juegan miles de manos por minuto.

Flexibilidad

Cambia de tabla para otras variantes de reglas o añade modos de entrenamiento sin tocar la lógica principal.

Facilidad de prueba

Fácil de cubrir con pruebas unitarias usando distintas tablas de estrategia y casos límite.

Modularidad

Los datos de estrategia pueden cargarse de forma independiente desde archivos, APIs o bases de datos.

Internacionalización

Admite distintas variantes regionales del blackjack con archivos JSON separados.

Recursos y próximos pasos

¿Listo para poner en práctica lo aprendido? Prueba nuestro entrenador interactivo y verás la estrategia básica en acción:

21Count: entrenador interactivo de estrategia básica

Descargar el archivo JavaScript completo con ejemplos

Incluye la tabla de estrategia completa, las funciones de consulta, el normalizador y ejemplos de uso listos para tus proyectos.