Ruby 这个改良的21点游戏的最佳获胜策略是什么? 问题
是否有一个最佳的价值观可以让我尽可能多地赢得比赛?如果是,是什么 编辑:是否有一个精确的获胜概率可以根据给定的限制进行计算,而与对手所做的任何事情无关?(我从大学开始就没有做过概率统计)。我很想把它作为一个答案,与我的模拟结果进行对比 编辑:修复了我的算法中的错误,更新了结果表 背景 我一直在玩一个修改过的21点游戏,其中有一些来自标准规则的恼人的规则调整。我已经将与标准21点规则不同的规则斜体化了,还为那些不熟悉的人加入了21点规则 修改21点规则Ruby 这个改良的21点游戏的最佳获胜策略是什么? 问题,ruby,algorithm,language-agnostic,probability,playing-cards,Ruby,Algorithm,Language Agnostic,Probability,Playing Cards,是否有一个最佳的价值观可以让我尽可能多地赢得比赛?如果是,是什么 编辑:是否有一个精确的获胜概率可以根据给定的限制进行计算,而与对手所做的任何事情无关?(我从大学开始就没有做过概率统计)。我很想把它作为一个答案,与我的模拟结果进行对比 编辑:修复了我的算法中的错误,更新了结果表 背景 我一直在玩一个修改过的21点游戏,其中有一些来自标准规则的恼人的规则调整。我已经将与标准21点规则不同的规则斜体化了,还为那些不熟悉的人加入了21点规则 修改21点规则 正好有两个人类玩家(与庄家无关) 每位玩家正
- 任何一个玩家都不知道对方牌的价值
- 在双方完成手牌之前,双方都不知道对方手牌的价值
- 若球员的A&B得分相同,则比赛为平局
- 若球员的A&B得分均超过21分(半身),则比赛为平局
- 如果玩家A的得分,以下是您收集的数据的一些想法:
- 这对于告诉你你的“命中极限”应该是什么有点帮助,但前提是你知道你的对手也在遵循类似的“命中极限”策略
- 即使如此,只有当你知道对手的“命中极限”是或可能是什么时,它才真正有用。你可以选择一个能给你比他们更多胜利的极限
- 您可以或多或少忽略表中的实际值。重要的是它们是积极的还是消极的
我同意,对于任何一只手,你都有理由相信你的对手会有一个极限,在这个极限之后,他们会停止击球,并留下来。如果你能猜到这个极限,你可以根据这个估计选择你自己的极限 如果你认为他们是乐观的,或者他们乐于冒险,那么选择20个上限——如果他们的上限在17以上,你将在长期内击败他们。如果你真的很有信心,选择12个上限——如果他们的上限超过18,并且这里有更频繁的赢家,那么这将获胜 如果你认为他们是保守的或是规避风险的,那么选择18的上限。如果他们自己保持在18岁以下的话,那就赢了 对于中性接地,考虑一下在没有任何外部影响的情况下,你的极限是多少。你通常会打16分吗?17岁 简而言之,你只能猜测对手的极限是多少,但如果你猜对了,你就可以用这些统计数据在长期内击败他们。两条评论: - 似乎没有一个基于“命中极限”的单一主导战略:
- 如果你选择16,你的对手可以选择17
- 如果你选择17,你的对手可以选择18
- 如果你选择18,你的对手可以选择19
- 如果你选择19,你的对手可以选择20
- 如果你选择20,你的对手可以选择12
- 如果你选择12,你的对手可以选择16
二,。你没有提到玩家是否能看到他们的对手抽了多少张牌(我想是的)。我希望这些信息能纳入“最佳”战略。(回答)
由于没有关于其他玩家决策的信息,游戏变得更简单。但是,由于显然没有主导战略,最优战略将是“战略”。也就是说:每个分数的一组概率,从12到21,决定你是否应该停牌或抽另一张牌(编辑:对于给定的没有得分的分数和有得分的分数,你需要不同的概率)。执行策略需要你随机选择(根据概率)每次新绘图后是停止还是继续。然后你可以找到游戏的答案
当然,如果你只是问一个简单的问题:对次优玩家(例如总是停在16、17、18或19号的玩家)的最佳获胜策略是什么?你问的是一个完全不同的问题,你必须明确指出,与你相比,另一个玩家在哪些方面受到限制。我对你的结果表示怀疑。例如,如果对手的目标是19,你的数据显示击败他的最好方法是一直打到20。这不能通过基本的气味测试。你确定你没有窃听器吗?如果我的对手争取19岁或更高,我的策略是不惜一切代价避免失败:坚持13岁或更高(甚至12岁?)。选择20肯定是错误的——而且不仅仅是小幅度的,而是大幅度的 我怎么知道你的数据是坏的?因为你玩的21点游戏并不罕见。这是大多数赌场中庄家的游戏方式:庄家击中目标,然后停下来,不管其他玩家手里拿着什么。这个目标是什么?站在硬17上,打软17。当您清除脚本中的bug时,它应该确认
CARDS = ((2..11).to_a+[10]*3)*4
#!/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
ruby blackjack.rb [num_iterations] [num_decks]
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
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
# 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
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 --