Un concurso de Blackjack KOTH

13

Veintiuna

Como me divertí mucho trabajando en el desafío KOTH original, quería idear otro. Para mí, la diversión de estos desafíos de IA está en refinar un bot relativamente simple que juega un juego muy simple sutilmente. Debido a la naturaleza probabilística de los juegos de cartas, creo que el blackjack podría ser un juego KOTH interesante al igual que TPD.

Todas las reglas se derivan de la descripción de este sitio web de BlackJack con zapatos

Reglas sobre las cartas y el mazo

  • Los bots juegan en mesas de cuatro (4) competidores y un (1) distribuidor
  • Todos los jugadores y el crupier comparten un (1) zapato (un mazo barajado) hasta que se agote, en ese momento se agregará un nuevo mazo aleatorio y el juego continuará. Los bots NO ESTÁN (en la actualidad) NOTIFICADOS de la adición de este nuevo mazo. Dicha notificación puede agregarse si la falta de esta característica causa suficiente angustia / problema.
  • Hay un buy-in de 10 por ronda, y las tarjetas son gratis
  • La mano perfecta / ideal tiene una puntuación de 21
  • Todas las cartas de cara tienen un valor de 10
  • Todas las tarjetas numéricas valen su número.
  • Los ases valen 11 o 1. Esto será tratado automáticamente por el marco, no por los bots.
  • Según las reglas , todas las cartas de los jugadores se reparten boca arriba y son visibles. Una de las cartas del crupier está boca abajo y la otra boca arriba.

Puntuación

  • Los puntajes superiores a 21 que usan un as como 11 obligan al as a reducir su valor a 1
  • puntajes superiores a 21 que no se pueden forzar por debajo del umbral de 21 "reventar" el bot

El distribuidor

  • El crupier dibuja hasta que revienta, o supera un puntaje de 17, momento en el que se ve obligado a pararse.

Apuestas y fichas

  • Al comienzo de cada ronda, se cobra un buy-in de 10, por lo que hay una apuesta mínima de 10 y una apuesta mínima de 1. NOTA : la apuesta es el valor absoluto del argumento de apuesta, así que no se moleste probando apuestas negativas.
  • Los bots que no pueden pagar el buy-in se eliminan del concurso
  • Al hacer apuestas, los bots no pueden apostar más que las fichas que tienen
  • Si la apuesta es posible, las fichas se eliminan de forma inmediata del bot y se agregan a la apuesta
  • Ganar una apuesta le da al bot 2x fichas de apuesta. Sin embargo, debido a que la apuesta se resta de las fichas del bot, el bot se iguala y luego gana 1x la apuesta.
  • Los bots ganan apuestas solo si su puntaje es mayor que el del crupier

Desglose del juego

Una mano

  1. Cuando comienza el juego, cada jugador recibe una carta de forma iterativa y se le resta la tarifa mínima de compra de $ 10 / apuesta mínima de sus fichas.
  2. El distribuidor dibuja
  3. Se realiza un segundo pase y se reparte otra carta a todos los jugadores.
  4. El distribuidor dibuja
  5. Luego (en el mismo orden en que fueron tratados) cada bot se ejecuta como se describe en la sección "Interfaz del programador" y debe hacer un movimiento o pararse. Las apuestas se consideran un movimiento. TEN EN CUENTA QUE LAS APUESTAS NO AFECTAN LA CAPACIDAD DE BOTS PARA REALIZAR MÁS MOVIMIENTOS. Es muy posible apostar y luego robar una carta, y es posible robar varias cartas y apostar antes de ponerse de pie.
  6. Cuando todos los bots se han roto o parado, el crupier juega a su umbral de 17
  7. Las puntuaciones de los bots se comparan con las del distribuidor, las apuestas se ganan y se pierden.

Una vuelta

Se considera que constituyen cinco (5) manos. Entre las manos, la lista de concursantes se clasifica para eliminar jugadores y luego se procesa para garantizar que todos los bots jueguen la misma cantidad de manos (una disposición para el hecho de que el número de entradas no se dividirá uniformemente entre las mesas de cuatro bots) )

Interfaz del programador y movimientos legales

Como se documenta en el archivo CardShark:

#   DOCUMENTATION
#       INPUT SPECIFICATION
#          $ ./foo.bar <hand-score> <hand> <visible cards> <stake> <chips>
#          <hand-score>     is the present integer value of the player's hand.
#          <hand>           is a space-free string of the characters [1-9],A,J,Q,K
#          <visible cards>  every dealt card on the table. when new shoes are brought
#                           into play, cards drawn therefrom are simply added to this list
#                           NOTE: the first TWO (2) cards in this list belong to the dealer.
#                             one however will be "hidden" by a "#". the other is visible.
#                           !!! THE LIST IS CLEARED AT THE END OF HANDS, NOT SHOES !!!
#          <stake>          the  number of chips which the bot has bet this hand
#          <chips>          the number of chips which the bot has
#       SAMPLE INPUT
#          $ ./foo.bar 21 KJA KQKJA3592A 25 145
#
#       OUTPUT SPECIFICATION
#          "H"|"S"|"D"|"B"  (no quotes in output)
#          "H"              HIT - deal a card
#          "S"              STAND - the dealer's turn
#          "D"              DOUBLEDOWN - double the bet, take one card. FIRST MOVE ONLY
#          "B 15"           BET - raises the bot's stakes by $15.

Como (ahora) documentado en el archivo de Tarjetas:

#       class CARD
#           card is a container for representing paper playing cards in
#           otherwise fairly functional programming.
#           letter()
#               gets the letter used to identify the card in a string  
#               LETTER MAPPINGS  
#                   Ace     :   'A'
#                   Two     :   '2'
#                   Three   :   '3'
#                   Four    :   '4'
#                   Five    :   '5'
#                   Six     :   '6'
#                   Seven   :   '7'
#                   Eight   :   '8'
#                   Nine    :   '9'
#                   Ten     :   'T'
#                   Jack    :   'J'
#                   Queen   :   'Q'
#                   King    :   'K'
#                   "Hidden":   '#'

El código fuente para el sistema de puntuación está AQUÍ

Bots de muestra

Lim 17

#!/usr/bin/env python
import sys
s = sys.argv
if int(s[1]) < 17:
    print "H"
else:
    print "S"

Idiomas de entrada

En la actualidad, Java, c / c ++, Python y Lisp son compatibles. Se hará un esfuerzo razonable para incluir presentaciones en otros idiomas, pero recuerde que el concurso final se ejecutará en una caja de Linux.

Selección de ganador

El ganador sería el autor del bot que constantemente acumulaba la mayor cantidad de fichas en un número de mesas y rondas aún por determinar. El ganador se anunciará el 3 de junio, pero el anuncio puede retrasarse si todavía hay presentaciones. Concurso extendido indefinidamente.

arrdem
fuente
Pregunta: ¿las cartas visibles incluyen las de la mano del jugador?
dmckee --- ex gatito moderador
Segunda pregunta: ¿sabemos cuántas cartas se han repartido que no podemos ver?
dmckee --- gatito ex moderador
Responda al # 1 - sí; Respuesta a # 2: la forma en que se implementa este motor, no hay tarjetas ocultas. cartas visibles es cada carta que se ha repartido de cada zapato consumido durante la ronda actual. las devoluciones de tarjetas visibles no se borran en los zapatos nuevos (porque parte del zapato viejo probablemente todavía esté en juego), sino que se borran en la terminación de la ronda. Esta es una elección de arquitectura que hice por simplicidad, que se puede revisar si encuentra que la falta de tarjetas ocultas es problemática.
arrdem
Actualización: verifique el enlace de las reglas. El motor ahora implementa cartas ocultas, pero la única carta oculta actualmente es una de las cartas base del crupier.
arrdem
¿Cómo pueden los bots distinguir qué tarjeta visible son los distribuidores?
cthom06

Respuestas:

3

BlackJackDavey

Aburrido, anticuado c. Debe compilar bajo ANSI o c99.

/* BlackJackDavey
 *
 * A entry for
 * http://codegolf.stackexchange.com/questions/2698/a-blackjack-koth-contest
 * copyright 2011 
 *
 * Currently expects a slightly extended version of the spec. Two
 * expected changes:
 * - Tens will be represented as 'T'
 * - The visible card string will include '#' for those cards whose
 *     *backs* we can see (slight improvement in card counting technique)
 * 
 * No disaster if neither feature is present, just sligtly degraded
 * performance.
 */
#include <stdio.h>
#include <string.h>

/* A full deck has a total value of 4*( (11*5) + (3*10) + ace ) where
 * ace is 11 or according to our need.
 **/
int fullWeight(const int current){
  int ace = (current>10) ? 1 : 11;
  return 4 * ( 11*5 + 3*10 + ace);
}
/* Return the value of a particular card in the context of our
 * current score
 */
int cardWeight(const char c, const int current){
 switch (c) {
 case '1': case '2': case '3': case '4': case '5':
 case '6': case '7': case '8': case '9':
   return (c - '0');
 case 'T': case 'J': case 'Q': case 'K':
   return 10;
 case 'A':
   return current>10 ? 1 : 11;
 }
 return 0;
}
/* returns the mean card *value* to be expected from the deck 
 *
 * Works by computing the currently unknown value and diviing by the
 * number of remaining cards 
 */
float weight(const char*known, const int current){
  int weight = fullWeight(current);
  int count=52;
  int uCount=0;
  const char*p=known;
  while (*p != '\0') {
    if (*p == '#') { /* Here '#' is a stand in for the back of a card */
      uCount++;
    } else {
      weight -= cardWeight(*p,current);
    }
    count--;
    p++;
    if ( count==0 && *p != '\0') {
      count += 52;
      weight += fullWeight(current);
    }
  }
  return (1.0 * weight)/(count+uCount);
}


int main(int argc, char*argv[]){
  int score=atoi(argv[1]);
  const char*hand=argv[2];
  const char*visible=argv[3];
  int stake=atoi(argv[4]);
  int chips=atoi(argv[5]);

  /* If current stake is less than 10, bet all the rest because a loss
     does not leave us enough to continue */
  if (chips < 10 && chips > 0) {
    printf("B %d\n",chips);
    return 0;
  }
  /* First round stategy differs from the rest of the game */
  if (strlen(hand)==2 && stake==10) {
    switch(score){
    case 10:
    case 11: /* Double down on particularly strong hands */
      if (chips >= 10) {
    printf("D\n");
    return 0;
      }
      break;
    default:
      break;
    };
  }
  /* In future rounds or when first round spcialls don't apply it is
     all about maximizing chance of getting a high score */
  if ((score + weight(visible,score)) <= 21) {
    /* if the oods are good for getting away with it, hit */
    printf("H\n");
    return 0;
  }
  /* Here odd are we bust if we hit, but if we are too low, the dealer
     probably makes it.*/
  printf("%c\n", score>14 ? 'S' : 'H');
  return 0;
}

La estrategia aquí está documentada en los comentarios, pero es muy directa. Las apuestas adicionales se realizan solo en dos casos (no hay suficiente apuesta para la siguiente ronda, o se duplican), y esto puede necesitar cambiar.

El juego difiere de las guías ofrecidas para los jugadores de casino en que no hay información específica sobre la tarjeta de presentación del crupier (¿o podríamos ser la última entrada visible?), Por lo que algunos de los números mágicos son conjeturas.

Puede necesitar un poco de modestia dependiendo de la respuesta a dos preguntas en los comentarios.

Nombre del juego, mi nombre y el antigua balada popular .

dmckee --- gatito ex moderador
fuente
La tarjeta de diez está representada por el carácter T. Actualizará la publicación del concurso con la lista.
llega
3

Apuesta lineal

#!/usr/bin/env python
from __future__ import division
import sys
s = sys.argv

c=150    # chip modifier
f=15     # stand score

if int(s[1]) < f:
    print "H"
else:
    if int(s[4]) == 10:
        print "B", (int(s[1])/21)*c
    else:
        print "S"

Este bot es una modificación de la estrategia 17. Este bot dibuja hasta que excede un puntaje de 15 (f) y luego apuesta int (c * (puntaje / 21)) fichas. De esta manera, el bot apostará agresivamente siempre que sea posible.

arrdem
fuente