Quelle est la stratégie gagnante optimale pour ce jeu de blackjack modifié?
-
21-09-2019 - |
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
- Exactement deux joueurs humains (revendeur est hors de propos)
- 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
- 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é).
- 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
- 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
- Une fois que les deux joueurs sont soit restés ou Busted le gagnant est déterminé par la règle 3 ci-dessus.
- 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 »
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:
-
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.