Qual é a estratégia ideal para este jogo de blackjack modificado?
-
21-09-2019 - |
Pergunta
Perguntas
Tem alguma melhor valor para permanecer para ganhar a maior porcentagem de jogos possíveis? Se assim for, o que é?
Editar: Existe uma probabilidade exata de vencer que possa ser calculada para um determinado limite, independente de qualquer que seja o oponente? (Não faço probabilidade e estatística desde a faculdade). Eu estaria interessado em ver isso como uma resposta para contrastá -la com meus resultados simulados.
Editar: Corrigido erros no meu algoritmo, tabela de resultados atualizados.
Fundo
Eu tenho jogado um jogo de blackjack modificado com alguns ajustes de regra bastante irritantes das regras padrão. Eu em itálico as regras diferentes das regras padrão do Blackjack, bem como incluíram as regras do Blackjack para aqueles que não estão familiarizados.
Regras de blackjack modificadas
- Exatamente dois jogadores humanos (revendedor é irrelevante)
- Cada jogador recebe duas cartas de bruços
- Nenhum dos jogadores _ever_ conhece o valor de _any_ das cartas do oponente
- Nenhum dos jogadores sabe o valor da mão do oponente até que você tenha terminado a mão
- O objetivo é chegar o mais próximo possível de 21. Resultados:
- Se o jogador de A&B tem uma pontuação idêntica, o jogo é um empate
- Se o jogador de A&B tem uma pontuação acima de 21 (um busto), o jogo é um empate
- Se a pontuação do jogador A for <= 21 e o jogador B quebrou, o jogador A vence
- Se a pontuação do jogador A é maior que o jogador B, e nenhum dos dois, o jogador A vence
- Caso contrário, o jogador A perdeu (B venceu).
- Cartões valem a pena:
- Os cartões 2 a 10 valem a quantidade correspondente de pontos
- Cartões j, q, k valem 10 pontos
- Card Ace vale 1 ou 11 pontos
- Cada jogador pode solicitar cartas adicionais uma de cada vez até:
- O jogador não quer mais (ficar)
- A pontuação do jogador, com qualquer ases contado como 1, excede 21 (busto)
- Nenhum jogador sabe quantas cartas o outro usou a qualquer momento
- Depois que os dois jogadores permaneceram ou prejudicaram, o vencedor é determinado por regra 3 acima.
- Depois de cada mão, todo o baralho é reorganizado e todas as 52 cartas estão em jogo novamente
O que é um baralho de cartas?
Um baralho de cartas consiste em 52 cartas, quatro cada um dos 13 valores a seguir:
2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A
Nenhuma outra propriedade dos cartões é relevante.
Uma representação rubi disso é:
CARDS = ((2..11).to_a+[10]*3)*4
Algoritmo
Eu tenho me aproximado disso da seguinte maneira:
- Eu sempre vou querer acertar se minha pontuação for de 2 a 11, pois é impossível quebrar
- Para cada uma das pontuações 12 a 21, simularei as mãos contra um oponente
- Para essas n mãos, a pontuação será meu "limite". Quando eu atingir o limite ou mais, eu irei fique.
- Meu oponente seguirá exatamente a mesma estratégia
- Vou simular n mãos para cada permutação dos conjuntos (12..21), (12..21)
- Imprima a diferença de vitórias e perdas para cada permutação, bem como a diferença de perda de vitória líquida
Aqui está o algoritmo implementado em 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
Uso
ruby blackjack.rb [num_iterations] [num_decks]
O script padrão é de 100.000 iterações e 4 decks. 100.000 leva cerca de 5 minutos em um MacBook Pro rápido.
Saída (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
Interpretação
É aqui que eu luto. Não tenho muita certeza de como interpretar esses dados. À primeira vista, parece que sempre Ficar aos 16 ou 17 anos é o caminho a seguir, mas não tenho certeza se é tão fácil. eu acho que é improvável Que um oponente humano real permaneceria em 12, 13 e possivelmente 14, então devo jogar fora esses valores do oponente_limit? Além disso, como posso modificar isso para levar em consideração a variabilidade de um oponente humano real? por exemplo, um humano real provavelmente permanecerá em 15 apenas com base em um "sentimento" e também pode atingir 18 com base em um "sentimento"
Solução
Eu suspeito dos seus resultados. Por exemplo, se o oponente pretende 19, seus dados dizem que a melhor maneira de vencê -lo é acertar até você atingir 20. Isso não passa em um teste básico de cheiro. Tem certeza de que não tem um bug? Se meu oponente estiver se esforçando por 19 ou melhor, minha estratégia seria evitar o fracasso a todo custo: permaneça em qualquer coisa 13 ou superior (talvez até 12?). Ir para 20 tem que errado - e não apenas por uma pequena margem, mas por muita coisa.
Como sei que seus dados são ruins? Porque O jogo de blackjack que você está jogando não é incomum. É a maneira como um revendedor toca na maioria dos cassinos: o revendedor atinge um alvo e depois para, independentemente do que os outros jogadores mantêm em suas mãos. O que é esse alvo? Fique no Hard 17 e acerte o Soft 17. Quando você se livrar dos insetos do seu script, ele deve confirmar que os cassinos conhecem seus negócios.
Quando eu faço as seguintes substituições ao seu código:
# 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
Os resultados concordam com o comportamento dos revendedores de cassinos: 17 é o alvo ideal.
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 --
Alguns comentários diversos:
O design atual é inflexível. Com apenas uma pequena refatoração, você pode obter uma separação limpa entre a operação do jogo (negociando, embaralhando, mantendo estatísticas em execução) e a tomada de decisão do jogador. Isso permitiria que você testasse várias estratégias uma contra a outra. Atualmente, suas estratégias estão incorporadas em loops que estão todos emaranhados no código de operação do jogo. Sua experimentação seria melhor servida por um design que lhe permitia criar novos jogadores e definir sua estratégia à vontade.
Outras dicas
Dois comentários:
Parece que não há uma única estratégia dominante baseada em um "limite de sucesso":
- Se você escolher 16, seu oponente pode escolher 17
- Se você escolher 17, seu oponente pode escolher 18
- Se você escolher 18, seu oponente pode escolher 19
- Se você escolher 19, seu oponente pode escolher 20
- Se você escolher 20, seu oponente pode escolher 12
- Se você escolher 12, seu oponente poderá escolher 16.
2. Você não menciona se os jogadores podem ver quantas cartas seu oponente desenhou (eu acho que sim). Eu esperaria que essas informações fossem incorporadas à estratégia "melhor". (respondidas)
Sem informações sobre as decisões de outros jogadores, o jogo fica mais simples. Mas já que claramente não há não dominante "puro" estratégia, a estratégia ideal será uma "misturado"Estratégia. isto é: um conjunto de probabilidades para cada pontuação de 12 a 21 para se você deve parar ou desenhar outra carta (editar: você precisará de probabilidades diferentes para uma determinada pontuação sem ACEs versus a pontuação com ases.) Executando o A estratégia então exige que você escolha aleatoriamente (de acordo com as probabilidades) se deve parar ou continuar após cada novo empate. Você pode encontrar o equilíbrio de Nash para o jogo.
Obviamente, se você está apenas fazendo a pergunta mais simples: qual é a estratégia de vitória ideal contra jogadores abaixo do ideal (por exemplo, que sempre param em 16, 17, 18 ou 19), você está fazendo uma pergunta totalmente diiferente, e você terá que ter que ter que Especifique exatamente de que maneira o outro jogador é limitado em comparação com você.
Aqui estão algumas reflexões sobre os dados que você coletou:
- É um pouco útil para dizer o que seu "limite de hit" deve ser, mas apenas se você souber que seu oponente está seguindo uma estratégia semelhante "Hit Limit".
- Mesmo assim, é apenas verdade Útil se você souber qual é o "limite de hit" do seu oponente ou provavelmente será. Você pode simplesmente escolher um limite que lhe dê mais vitórias do que elas.
- Você pode ignorar mais ou menos os valores reais na tabela. É se eles são positivos ou negativos que importa.
Para mostrar seus dados de outra maneira, o primeiro número é o limite do seu oponente e o segundo grupo de números são os limites que você pode escolher e vencer. Aquele com um asterisco é a escolha "mais vencedora":
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
A partir disso, você pode ver que um limite de hit de 17 ou 18 é a opção mais segura se o oponente estiver seguindo uma estratégia de seleção aleatória "Hit Limit", porque 17 e 18 vencerão 7/10 "Limites de sucesso".
Obviamente, se o seu oponente é humano, você não pode responder a eles auto-impondo um "limite de acerto" com menos de 18 anos ou mais de 19, de modo que nega completamente os cálculos anteriores. Eu ainda acho que esses números são úteis no entanto:
Concordo que, por qualquer mão individual, você pode estar razoavelmente confiante de que seu oponente terá um limite, após o qual eles pararão de bater, e eles ficarão. Se você conseguir adivinhar esse limite, poderá escolher seu próprio limite com base nessa estimativa.
Se você acha que eles estão sendo otimistas ou felizes em arriscar, escolha um limite de 20 - você os vencerá a longo prazo, desde que seu limite seja acima de 17. Se você estiver realmente confiante, escolha um limite de 12 - Isso vencerá se o limite deles estiver acima de 18 e há ganhos muito mais frequentes a serem adquiridos aqui.
Se você acha que eles estão sendo conservadores ou avessos ao risco, escolha um limite de 18. Isso vencerá se eles ficarem em qualquer lugar abaixo dos 18.
Para terreno neutro, talvez pense em qual seria seu limite sem nenhuma influência externa. Você normalmente acertaria em 16? A 17?
Em suma, você só pode adivinhar qual é o limite do seu oponente, mas se você adivinhar bem, poderá vencê -los a longo prazo com essas estatísticas.