Un concours BlackJack KOTH

13

BlackJack

Comme je me suis éclaté à travailler sur le défi KOTH original, je voulais en trouver un autre. Pour moi, le plaisir de ces défis d'IA est d'affiner un bot relativement simple qui joue subtilement un jeu très simple. En raison de la nature probabiliste des jeux de cartes, je pense que le blackjack pourrait être un jeu KOTH intéressant tout comme le TPD.

Toutes les règles sont dérivées de la description de ce site Web de BlackJack avec des chaussures

Règles concernant les cartes et le jeu

  • Les bots jouent à des tables de quatre (4) concurrents et d'un (1) croupier
  • Une (1) chaussure (un deck mélangé) est partagée par tous les joueurs et le croupier jusqu'à ce qu'elle soit épuisée, auquel cas un nouveau deck mélangé au hasard sera ajouté et le jeu continuera. Les bots NE SONT PAS (à l'heure actuelle) AVISÉS de l'ajout de ce nouveau deck. Une telle notification peut être ajoutée si l'absence de cette fonction provoque suffisamment de détresse / trouble.
  • Il y a un buy-in de 10 par tour et les cartes sont gratuites
  • La main parfaite / idéale a un score de 21
  • Toutes les cartes face ont une valeur de 10
  • Toutes les cartes numériques valent leur numéro
  • Les as valent 11 ou 1. cela sera traité automatiquement par le framework, pas par les bots.
  • Conformément aux règles , toutes les cartes des joueurs sont distribuées face visible et sont visibles. L'une des cartes du donneur est face cachée et l'autre est face visible.

Notation

  • Les scores supérieurs à 21 qui utilisent un as comme 11 forcent l'as à réduire sa valeur à 1
  • des scores supérieurs à 21 qui ne peuvent pas être contraints en dessous du seuil de 21 "buste" le bot

Le revendeur

  • Le croupier tire jusqu'à ce qu'il tombe en panne, ou dépasse un score de 17, auquel cas il est obligé de rester

Paris et jetons

  • Au début de chaque tour, un buy-in de 10 est facturé, il y a donc une mise minimale de 10 et une mise minimale de 1. REMARQUE - la mise est la valeur absolue de l'argument de la mise, alors ne vous embêtez pas essayer des paris négatifs.
  • Les bots qui ne peuvent pas se permettre le buy-in sont retirés du concours
  • Lors des paris, les bots ne peuvent pas parier plus que les jetons qu'ils ont
  • Si le pari est possible, les jetons de jetons sont immédiatement retirés du bot et ajoutés à la mise
  • Gagner un pari donne au bot 2x des jetons. Cependant, parce que le pari est soustrait des jetons du bot, le bot atteint l'équilibre et gagne ensuite 1x le pari.
  • Les bots ne gagnent des paris que si leur score est supérieur à celui du croupier

Répartition du gameplay

Une main

  1. Lorsque le jeu commence, chaque joueur reçoit une carte de manière itérative et les frais de 10 $ de buy-in / mise minimale sont soustraits de ses jetons.
  2. Le croupier tire
  3. Une deuxième passe est effectuée et une autre carte est distribuée à tous les joueurs.
  4. Le croupier tire
  5. Ensuite (dans le même ordre que celui auquel ils ont été distribués), chaque bot est exécuté comme décrit dans la section "Interface du programmeur" et doit se déplacer ou se tenir debout. Les paris sont considérés comme un mouvement. NOTEZ QUE PARI N'AFFECTE PAS LA CAPACITÉ DES BOTS DE FAIRE D'AUTRES DÉPLACEMENTS. Il est très possible de miser puis de piocher une carte, et il est possible de piocher plusieurs cartes et de les parier avant de se tenir.
  6. Lorsque tous les robots ont éclaté ou se sont tenus, le croupier joue à son seuil de 17
  7. Les scores des bots sont ensuite comparés à ceux du croupier, les paris sont gagnés et perdus

Un tour

Est considéré comme constituant cinq (5) mains. Entre les mains, la liste des participants est triée pour éliminer les joueurs, puis traitée pour garantir que tous les bots jouent le même nombre de mains (une disposition prévoyant que le nombre d'entrées ne sera pas réparti également entre les tables à quatre bots). ).

Interface du programmeur et mouvements légaux

Comme indiqué dans le fichier 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.

Comme (maintenant) documenté dans le fichier Cards:

#       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":   '#'

Le code source du système de notation est ICI

Exemples de robots

Lim 17

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

Langues d'entrée

À l'heure actuelle, Java, c / c ++, Python et Lisp sont pris en charge. Un effort raisonnable sera fait pour inclure les soumissions dans d'autres langues, mais n'oubliez pas que le concours final se déroulera sur une boîte Linux.

Sélection des gagnants

Le gagnant serait l'auteur du bot qui a systématiquement accumulé le plus de jetons sur un nombre de tables et de tours encore à déterminer. Le gagnant sera annoncé le 3 juin, mais l'annonce peut être retardée s'il reste des soumissions. Le concours s'est prolongé indéfiniment.

arrdem
la source
Question: les cartes visibles incluent-elles celles dans la main du joueur?
dmckee --- chaton ex-modérateur
Deuxième question: savons-nous combien de cartes ont été distribuées que nous ne pouvons pas voir?
dmckee --- chaton ex-modérateur
Réponse à # 1 - oui; Réponse à # 2 - la façon dont ce moteur est implémenté, il n'y a pas de cartes cachées. visible-cards est chaque carte qui a été distribuée à partir de chaque chaussure consommée pendant le tour en cours. les retours de cartes visibles ne sont pas effacés sur les chaussures neuves (car une partie de l'ancienne chaussure est probablement encore en jeu) mais sont effacés à la fin de la ronde. C'est un choix d'architecture que j'ai fait pour plus de simplicité, qui peut être révisé si vous trouvez que le manque de cartes cachées pose problème.
arrdem
Mise à jour: vérifiez le lien des règles. Le moteur implémente désormais les cartes cachées, mais la seule carte cachée actuellement est l'une des cartes de base du croupier.
arrdem
Comment les bots peuvent-ils distinguer quelle carte visible sont les revendeurs?
cthom06

Réponses:

3

BlackJackDavey

Ennuyeux, démodé c. Devrait compiler sous ANSI ou 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 stratégie ici est documentée dans les commentaires, mais est très simple. Des paris supplémentaires sont faits dans seulement deux cas (pas assez de mise pour le prochain tour, ou doubler), et cela peut devoir changer.

Le jeu diffère certains des guides proposés pour les joueurs de casino en ce sens qu'il n'y a pas d'informations spécifiques sur la carte de présentation du croupier (ou pouvons-nous le faire étant la dernière entrée dans visible?), Donc certains des nombres magiques sont des suppositions.

Il faudra peut-être quelques petits gestes selon la réponse à deux questions dans les commentaires.

Nom du jeu, mon prénom et le vieille ballade folklorique .

dmckee --- chaton ex-modérateur
la source
Les dix cartes sont représentées par le caractère T. Met à jour le message du concours avec la liste.
arrdem
3

Pari linéaire

#!/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"

Ce bot est une modification de la stratégie 17. Ce bot tire jusqu'à ce qu'il dépasse un score de 15 (f) puis mise sur des jetons int (c * (score / 21)). De cette façon, le bot pariera agressivement dans la mesure du possible.

arrdem
la source