Question

Questions

Y at-il un meilleurs valeur de rester sur pour que je gagne le plus grand pourcentage de jeux possibles? Si oui, quel est-il?

Modifier Y at-il une probabilité exacte de gagner qui peut être calculé pour une limite donnée, indépendamment de ce que l'adversaire? (Je ne l'ai pas fait la probabilité et les statistiques depuis le collège). Je serais intéressé à voir que comme une réponse à contraste avec mes résultats simulés.

Modifier. Correction de bugs dans mon algorithme, table de résultats mis à jour

Arrière-plan

Je joue un jeu de blackjack modifié avec quelques modifications de règles plutôt ennuyeux des règles standard. J'ai les règles qui apparaissent en italique sont différentes des règles de black jack standard, ainsi que inclus les règles de blackjack pour ceux qui ne connaissent.

Règles modifiées Blackjack

  1. Exactement deux joueurs humains (revendeur est hors de propos)
  2. Chaque joueur reçoit deux cartes face cachée
    • Ni _ever_ joueur connaît la valeur de _any_ des cartes de l'adversaire
    • Aucun joueur ne connaît la valeur de la main de l'adversaire jusqu'à ce que _both_ ont fini la main
  3. L'objectif est de se rapprocher de marquer de 21 possible. résultats:
    • Si A & B du joueur ont même score, jeu est un dessiner
    • Si ce joueur A & B ont tous deux un score de plus de 21 (un buste), est un jeu dessiner
    • Si le score du joueur A est <= 21 et le joueur B a éclaté, le joueur A gagne
    • Si le score du joueur A est plus que le joueur B, et n'ont éclaté, le joueur A gagne
    • Dans le cas contraire, le joueur A a perdu (B a gagné).
  4. Cartes valent:
    • Cartes de visite 2 à 10 valent le montant correspondant de points
    • Cartes de J, Q, K valent 10 points
    • Ace Card vaut 1 ou 11 points
  5. Chaque joueur peut demander des cartes supplémentaires un à la fois jusqu'à ce que:
    • Le joueur ne veut plus (séjour)
    • Le score du joueur, avec les as comptées comme 1, dépasse 21 (buste)
    • Aucun joueur ne sait combien de cartes l'autre a utilisé à tout moment
  6. Une fois que les deux joueurs sont soit restés ou Busted le gagnant est déterminé par la règle 3 ci-dessus.
  7. Après chaque main la plate-forme est entièrement remanié et les 52 cartes sont en jeu à nouveau

Qu'est-ce qu'un jeu de cartes?

Un jeu de cartes se compose de 52 cartes, quatre chacune des 13 valeurs suivantes:

  

2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A

Aucun autre propriété des cartes sont pertinentes.

Une représentation de cela est Ruby:

CARDS = ((2..11).to_a+[10]*3)*4

algorithme

J'ai approchais cela comme suit:

  • Je veux toujours frapper si mon score est de 2 à 11, comme il est impossible de buste
  • Pour chacun des scores 12 à 21 je simulera les mains N contre un adversaire
    • Pour ces mains N, le score sera mon « limite ». Une fois que j'atteint la limite ou plus, je rester .
    • Mon adversaire va suivre la même stratégie exacte
    • Je simulera les mains N pour chaque permutation des ensembles (12..21), (12..21)
  • Imprimer la différence pour chaque permutation victoires et des pertes ainsi que la différence de perte de gain net

Voici l'algorithme implémenté en Ruby:

#!/usr/bin/env ruby
class Array
  def shuffle
    sort_by { rand }
  end

  def shuffle!
    self.replace shuffle
  end

  def score
    sort.each_with_index.inject(0){|s,(c,i)|
      s+c > 21 - (size - (i + 1)) && c==11 ? s+1 : s+c
    }
  end
end

N=(ARGV[0]||100_000).to_i
NDECKS = (ARGV[1]||1).to_i

CARDS = ((2..11).to_a+[10]*3)*4*NDECKS
CARDS.shuffle

my_limits = (12..21).to_a
opp_limits = my_limits.dup

puts " " * 55 + "opponent_limit"
printf "my_limit |"
opp_limits.each do |result|
  printf "%10s", result.to_s
end
printf "%10s", "net"
puts

printf "-" * 8 + " |"
print "  " + "-" * 8
opp_limits.each do |result|
  print "  " + "-" * 8
end
puts

win_totals = Array.new(10)
win_totals.map! { Array.new(10) }

my_limits.each do |my_limit|
  printf "%8s |", my_limit
  $stdout.flush
  opp_limits.each do |opp_limit|

    if my_limit == opp_limit # will be a tie, skip
      win_totals[my_limit-12][opp_limit-12] = 0
      print "        --"
      $stdout.flush
      next
    elsif win_totals[my_limit-12][opp_limit-12] # if previously calculated, print
      printf "%10d", win_totals[my_limit-12][opp_limit-12]
      $stdout.flush
      next
    end

    win = 0
    lose = 0
    draw = 0

    N.times {
      cards = CARDS.dup.shuffle
      my_hand = [cards.pop, cards.pop]
      opp_hand = [cards.pop, cards.pop]

      # hit until I hit limit
      while my_hand.score < my_limit
        my_hand << cards.pop
      end

      # hit until opponent hits limit
      while opp_hand.score < opp_limit
        opp_hand << cards.pop
      end

      my_score = my_hand.score
      opp_score = opp_hand.score
      my_score = 0 if my_score > 21 
      opp_score = 0 if opp_score > 21

      if my_hand.score == opp_hand.score
        draw += 1
      elsif my_score > opp_score
        win += 1
      else
        lose += 1
      end
    }

    win_totals[my_limit-12][opp_limit-12] = win-lose
    win_totals[opp_limit-12][my_limit-12] = lose-win # shortcut for the inverse

    printf "%10d", win-lose
    $stdout.flush
  end
  printf "%10d", win_totals[my_limit-12].inject(:+)
  puts
end

Utilisation

ruby blackjack.rb [num_iterations] [num_decks]

Les valeurs par défaut de script à 100.000 itérations et 4 ponts. 100 000 prend environ 5 minutes sur un macbook pro rapide.

sortie (N = 100 000)

                                                       opponent_limit
my_limit |        12        13        14        15        16        17        18        19        20        21       net
-------- |  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------
      12 |        --     -7666    -13315    -15799    -15586    -10445     -2299     12176     30365     65631     43062
      13 |      7666        --     -6962    -11015    -11350     -8925      -975     10111     27924     60037     66511
      14 |     13315      6962        --     -6505     -9210     -7364     -2541      8862     23909     54596     82024
      15 |     15799     11015      6505        --     -5666     -6849     -4281      4899     17798     45773     84993
      16 |     15586     11350      9210      5666        --     -6149     -5207       546     11294     35196     77492
      17 |     10445      8925      7364      6849      6149        --     -7790     -5317      2576     23443     52644
      18 |      2299       975      2541      4281      5207      7790        --    -11848     -7123      8238     12360
      19 |    -12176    -10111     -8862     -4899      -546      5317     11848        --    -18848     -8413    -46690
      20 |    -30365    -27924    -23909    -17798    -11294     -2576      7123     18848        --    -28631   -116526
      21 |    -65631    -60037    -54596    -45773    -35196    -23443     -8238      8413     28631        --   -255870

Interprétation

C'est là que je lutte. Je ne suis pas tout à fait sûr de savoir comment interpréter ces données. À première vue, il semble que toujours rester à 16 ou 17 est le chemin à parcourir, mais je ne suis pas sûr que ce soit facile. Je pense qu'il est improbable qu'un adversaire humain EFFECTIVE stay sur 12, 13, 14 et peut-être, donc devrais-je jeter ces valeurs opponent_limit? En outre, comment puis-je modifier cela pour tenir compte de la variabilité d'un vrai adversaire humain? par exemple. un être humain réel est susceptible de rester sur 15 seulement basé sur un « sentiment » et peut également frapper sur 18 basée sur un « sentiment »

Était-ce utile?

La solution

Je me méfie de vos résultats. Par exemple, si l'adversaire vise 19, vos données dit que la meilleure façon de le battre est de frapper jusqu'à 20. Cela ne passe pas un test de l'odeur de base. Êtes-vous sûr que vous ne disposez pas d'un bug? Si mon adversaire cherche 19 ou mieux, ma stratégie serait d'éviter busting à tout prix: rester sur quoi que ce soit 13 ou plus (peut-être même 12?). Objectif 20 doit mal -. Et non pas seulement par une petite marge, mais beaucoup

Comment puis-je savoir que vos données sont mauvais? Parce que le jeu de blackjack que vous jouez est pas rare . C'est la façon dont un revendeur joue dans la plupart des casinos: le croupier frappe jusqu'à une cible, puis arrête, peu importe ce que les autres joueurs tiennent dans leurs mains. Qu'est-ce que la cible? Tenez-vous sur dur 17 et 17. Lorsque frappé doux vous débarrasser des bugs dans votre script, il devrait confirmer que les casinos connaissent leur métier.

Quand je fais les remplacements suivants à votre code:

# Replace scoring method.
def score
  s = inject(0) { |sum, c| sum + c }
  return s if s < 21
  n_aces = find_all { |c| c == 11 }.size
  while s > 21 and n_aces > 0
      s -= 10
      n_aces -= 1
  end
  return s
end

# Replace section of code determining hand outcome.
my_score  = my_hand.score
opp_score = opp_hand.score
my_score  = 0 if my_score  > 21
opp_score = 0 if opp_score > 21
if my_score == opp_score
  draw += 1
elsif my_score > opp_score
  win += 1
else
  lose += 1
end

Les résultats sont d'accord avec le comportement des croupiers. 17 est la cible optimale

n=10000
                                                       opponent_limit
my_limit |        12        13        14        15        16        17        18        19        20        21       net
-------- |  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------
      12 |        --      -843     -1271     -1380     -1503     -1148      -137      1234      3113      6572
      13 |       843        --      -642     -1041     -1141      -770       -93      1137      2933      6324
      14 |      1271       642        --      -498      -784      -662        93      1097      2977      5945
      15 |      1380      1041       498        --      -454      -242      -100       898      2573      5424
      16 |      1503      1141       784       454        --      -174        69       928      2146      4895
      17 |      1148       770       662       242       174        --        38       631      1920      4404
      18 |       137        93       -93       100       -69       -38        --       489      1344      3650
      19 |     -1234     -1137     -1097      -898      -928      -631      -489        --       735      2560
      20 |     -3113     -2933     -2977     -2573     -2146     -1920     -1344      -735        --      1443
      21 |     -6572     -6324     -5945     -5424     -4895     -4404     -3650     -2560     -1443        --

Quelques commentaires divers :

La conception actuelle est inflexible. Avec juste un peu refactoring, vous pourriez obtenir une séparation nette entre le fonctionnement du jeu (traitant, traînant, en gardant les statistiques en cours d'exécution) et la prise de décision du joueur. Cela vous permettra de tester différentes stratégies les uns contre les autres. À l'heure actuelle, vos stratégies sont intégrées dans les boucles qui sont tous enchevêtrés dans le code d'opération de jeu. Votre expérimentation serait mieux servie par un design qui vous a permis de créer de nouveaux joueurs et de définir leur stratégie à volonté.

Autres conseils

Deux commentaires:

  1. On dirait qu'il n'y a pas une seule stratégie dominante basée sur un "hit limit":

    • Si vous choisissez 16 votre adversaire peut choisir 17
    • si vous choisissez 17 votre adversaire peut choisir 18
    • si vous choisissez 18 votre adversaire peut choisir 19
    • si vous choisissez 19 votre adversaire peut choisir 20
    • si vous choisissez 20 votre adversaire peut choisir 12
    • si vous choisissez 12 votre adversaire peut choisir 16.

2. Vous ne mentionnez pas si les joueurs peuvent voir combien de cartes son adversaire a tiré (je pense que oui). Je me attends à ces informations à intégrer dans la stratégie « meilleur ». (réponse)


Avec aucune information sur les autres décisions des joueurs, le jeu devient plus simple. Mais puisqu'il n'y a manifestement pas « pure » stratégie , la stratégie optimale sera un « < a href = "http://en.wikipedia.org/wiki/Mixed_strategy" stratégie rel = "nofollow noreferrer"> mixte ». C'est: un ensemble de probabilités pour chaque score du 12 au 21 pour savoir si vous devez arrêter ou tirer une autre carte (EDIT:. Vous aurez besoin des probabilités pour un score donné sans aces contre le score aces) L'exécution de la stratégie nécessite alors vous de choisir au hasard (selon les probabilités) si vous souhaitez arrêter ou continuer après chaque nouveau tirage. Vous pouvez trouver équilibre de Nash pour le jeu.

Bien sûr, si vous ne posez la simple question: quelle est la stratégie gagnante optimale contre les joueurs suboptimales (pour exemple ceux qui s'arrêtent toujours 16, 17, 18 ou 19), vous posez une question tout à fait diiferent, et vous devra préciser exactement de quelle manière l'autre joueur est limité par rapport à vous.

Voici quelques réflexions sur les données que vous avez recueillies:

  • Il est légèrement utile pour vous dire ce que votre stratégie « hit limite » devrait être, mais seulement si vous savez que votre adversaire suit une similaire « hit limit ».
  • Même alors, il est seulement vraiment utile si vous savez ce que « a frappé la limite » de votre adversaire est ou est susceptible d'être. Vous pouvez choisir simplement une limite qui vous donne plus de victoires que les.
  • Vous pouvez plus ou moins ignorer les valeurs réelles de la table. Il est qu'ils soient positifs ou négatifs que les questions.

Pour afficher vos données d'une autre manière, le premier numéro est la limite de votre adversaire, et le deuxième groupe de numéros sont les limites que vous pouvez choisir et gagner avec. Celui d'un astérisque est le choix « winningest »:

12:   13, 14, 15, 16*, 17, 18
13:   14, 15, 16*, 17, 18, 19
14:   15, 16, 17*, 18, 19
15:   16, 17*, 18, 19
16:   17, 18*, 19
17:   18*, 19
18:   19*, 20
19:   12, 20*
20:   12*, 13, 14, 15, 16, 17
21:   12*, 13, 14, 15, 16, 17, 18, 19, 20

De là, vous pouvez voir qu'une limite de succès de 17 ou 18 est la plus sûre si l'adversaire suit une aléatoire « hit limit » stratégie de sélection parce que 17 et 18 va battre 7/10 adversaire « a frappé les limites ».

Bien sûr, si votre adversaire est humain, vous ne pouvez pas répondre à leur auto-imposer une « limite frappé » de moins de 18 ans ou plus de 19, de sorte que les calculs nie complètement précédents. Je pense toujours que ces chiffres sont cependant utiles:


Je suis d'accord que, pour toute main individuelle, vous pouvez être raisonnablement sûr que votre adversaire aura une limite après quoi ils cesseront de frapper, et ils vont rester. Si vous pouvez deviner cette limite, vous pouvez choisir votre propre limite en fonction de cette estimation.

Si vous pensez qu'ils sont optimistes ou ils sont heureux de risquer, choisissez une limite de 20 - vous les battre à long terme à condition que leur limite est au-dessus 17. Si vous êtes vraiment confiant, choisir une limite de 12 -. qui gagnera si leur limite est supérieure à 18 et il y a des gains beaucoup plus fréquents à avoir ici

Si vous pensez qu'ils sont conservateurs ou aversion au risque, choisir une limite de 18 ans qui va gagner s'ils restent partout en dessous de 18 eux-mêmes.

Pour un terrain neutre, pensez peut-être à ce que votre limite serait sans influence extérieure. Voulez-vous normalement touché sur un 16? A 17?

En bref, vous ne pouvez deviner ce que la limite de votre adversaire est, mais si vous devinez bien, vous pouvez les battre sur le long terme avec ces statistiques.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top