Какова оптимальная стратегия выигрыша для этой модифицированной игры в блэкджек?
Вопросы
Есть ли лучшая цена, чтобы я мог выиграть как можно больший процент игр? Если так, то, что это?
Изменить: Существует ли точная вероятность выигрыша, которая может быть рассчитана для данного лимита, независимо от того, что делает противник? (Я не делал вероятности и статистику с колледжа). Мне было бы интересно увидеть это как ответ, чтобы сопоставить его с моими смоделированными результатами.
Редактировать: Исправлены ошибки в моем алгоритме, обновлена таблица результатов.
Фон
Я играл в модифицированную игру в блэкджек с некоторыми довольно раздражающими изменениями правил из стандартных правил. Я выделил курсивом правила, которые отличаются от стандартных правил блэкджека, а также включил правила блэкджека для тех, кто не знаком.
Модифицированные правила блэкджека
- Ровно два человека (дилер не имеет значения)
- Каждому игроку сдаются две карты лицом вниз
- Ни один из игроков _ever_ не знает значения _any_ карт противника
- Ни один из игроков не знает значения руки противника, пока _both_ не закончит раздачу
- Цель - приблизиться к 21 очку. Результаты:
- Если у игрока A & B одинаковый счет, игра является ничьей
- Если оба игрока A & B набрали более 21 балла, игра считается ничьей
- Если счет игрока А равен <= 21, а игрок Б выиграл, игрок А выигрывает
- Если счет игрока А больше, чем у игрока Б, и ни один из них не выиграл, игрок А выигрывает
- В противном случае игрок A проиграл (B выиграл).
- Карты стоят:
- Карты со 2 по 10 приносят соответствующее количество очков
- Карты J, Q, K стоят 10 очков.
- Карта туза стоит 1 или 11 очков
- Каждый игрок может запросить дополнительные карты по одной до тех пор, пока:
- Игрок больше не хочет (остаться)
- Оценка игрока, с любым тузом, подсчитанным как 1, превышает 21 (бюст)
- Ни один из игроков не знает, сколько карт использовал другой.
- После того, как оба игрока останутся или будут разыграны, победитель определяется согласно правилу 3 выше.
- После каждой раздачи вся колода перетасовывается, и все 52 карты снова в игре.
Что такое колода карт?
Колода карт состоит из 52 карт по четыре из следующих 13 значений:
2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A
Никакое другое свойство карт не имеет отношения к делу.
Представление Ruby об этом:
CARDS = ((2..11).to_a+[10]*3)*4
Алгоритм
Я подхожу к этому следующим образом:
- Я всегда буду хотеть ударить, если мой счет от 2 до 11, так как невозможно разорить
- Для каждой из оценок от 12 до 21 я буду моделировать N рук против оппонента.
- Для этих N рук счет будет моим "пределом". Как только я достигну предела или больше, я останусь.
- Мой противник будет следовать той же стратегии
- Я буду моделировать N рук для каждой перестановки множеств (12..21), (12..21)
- Выведите разницу в выигрышах и проигрышах для каждой перестановки, а также разницу в чистых выигрышах
Вот алгоритм, реализованный в 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
использование
ruby blackjack.rb [num_iterations] [num_decks]
По умолчанию в скрипте 100000 итераций и 4 колоды. 100000 занимает около 5 минут на быстром MacBook Pro.
Выход (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
интерпретация
Вот где я борюсь. Я не совсем уверен, как интерпретировать эти данные. На первый взгляд кажется, что всегда оставаться в 16 или 17 - это путь, но я не уверен, так ли это легко. Я думаю, что маловероятно, что реальный человеческий оппонент останется на 12, 13 и, возможно, 14, так что я должен выбросить эти значения противник-предел? Кроме того, как я могу изменить это, чтобы учесть изменчивость реального человеческого оппонента? например, реальный человек, скорее всего, останется на 15 только из-за "чувства" и может также попасть в 18 из-за "чувства"
3 ответа
Я с подозрением отношусь к вашим результатам. Например, если противник стремится к 19, ваши данные говорят о том, что лучший способ победить его - это наносить удары, пока вы не достигнете 20. Это не проходит базовый тест на запах. Вы уверены, что у вас нет ошибки? Если мой оппонент стремится к 19 или выше, моя стратегия состоит в том, чтобы избежать разорения любой ценой: остаться на что-нибудь 13 или выше (может быть, даже 12?). Идти за 20 - неправильно, и не только с небольшим отрывом, но и с большим.
Откуда я знаю, что ваши данные плохие? Потому что игра в блэкджек, в которую вы играете, не является необычной. Именно так играет дилер в большинстве казино: он достигает цели и затем останавливается, независимо от того, что другие игроки держат в руках. Что это за цель? Встаньте на жесткий 17 и нажмите на мягкий 17. Когда вы избавитесь от ошибок в вашем скрипте, это должно подтвердить, что казино знают свое дело.
Когда я делаю следующие замены для вашего кода:
# 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
Результаты согласуются с поведением дилеров казино: 17 является оптимальной целью.
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 --
Несколько разных комментариев:
Нынешний дизайн негибкий. С помощью небольшого рефакторинга вы можете добиться четкого разделения между работой игры (раздачей, перетасовкой, сохранением статистики бега) и принятием решения игроком. Это позволит вам проверить различные стратегии друг против друга. В настоящее время ваши стратегии встроены в циклы, которые все запутаны в коде игры. Ваши эксперименты будут лучше подкреплены дизайном, который позволит вам создавать новых игроков и устанавливать их стратегию по своему желанию.
Два комментария:
Похоже, что не существует единой доминирующей стратегии, основанной на "пределе попаданий":
- Если вы выберете 16, ваш противник может выбрать 17
- если вы выберете 17, ваш противник может выбрать 18
- если вы выберете 18, ваш противник может выбрать 19
- если вы выберете 19, ваш противник может выбрать 20
- если вы выберете 20, ваш противник может выбрать 12
- если вы выберете 12, ваш противник может выбрать 16.
2. Вы не упоминаете, могут ли игроки видеть, сколько карт вытянул их противник (я бы так предположил). Я ожидаю, что эта информация будет включена в "лучшую" стратегию. (Ответил)
Без информации о решениях других игроков игра становится проще. Но поскольку явно не существует доминирующей "чистой" стратегии, оптимальной стратегией будет " смешанная " стратегия. То есть: набор вероятностей для каждой оценки от 12 до 21 для того, стоит ли вам останавливать или брать другую карту (РЕДАКТИРОВАТЬ: вам понадобятся разные вероятности для данной оценки без тузов по сравнению со счетом с тузами.) Выполнение стратегии требует Вы случайным образом выбираете (в соответствии с вероятностями), останавливаться или продолжать после каждого нового розыгрыша. Затем вы можете найти равновесие Нэша для игры.
Конечно, если вы задаете только более простой вопрос: какова оптимальная стратегия выигрыша против неоптимальных игроков (например, тех, которые всегда останавливаются на 16, 17, 18 или 19), вы задаете совершенно другой вопрос, и вам придется точно укажите, каким образом другой игрок ограничен по сравнению с вами.
Вот несколько соображений о данных, которые вы собрали:
- Это мягко полезно для определения того, каким должен быть ваш "предел попадания", но только если вы знаете, что ваш оппонент придерживается аналогичной стратегии "ограничения попадания".
- Даже тогда, это действительно очень полезно, если вы знаете, каков или может быть "предел" попадания вашего оппонента. Вы можете просто выбрать лимит, который даст вам больше побед, чем они.
- Вы можете более или менее игнорировать фактические значения в таблице. Важен ли он положительным или отрицательным.
Чтобы показать ваши данные иначе, первое число - это предел вашего оппонента, а вторая группа чисел - это пределы, которые вы можете выбрать и выиграть. "Звездочка" - самый выигрышный выбор:
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
Из этого вы можете видеть, что предел попадания 17 или 18 является наиболее безопасным вариантом, если противник следует случайной стратегии выбора "предела попадания", потому что 17 и 18 побьют 7/10 "пределов попадания" противника.
Конечно, если ваш оппонент человек, вы не можете ответить на него, налагая "лимит попадания" до 18 или более 19, так что это полностью сводит на нет предыдущие вычисления. Я все еще думаю, что эти цифры полезны, однако:
Я согласен, что для любой отдельной руки вы можете быть достаточно уверены, что у вашего оппонента будет предел, после которого он перестанет бить, и он останется. Если вы можете угадать этот предел, вы можете выбрать свой собственный предел на основе этой оценки.
Если вы думаете, что они настроены оптимистично или они готовы рисковать, выберите лимит 20 - вы победите их в долгосрочной перспективе, если их предел превысит 17. Если вы действительно уверены в себе, выберите лимит 12 - выиграет, если их лимит превысит 18, и здесь будет гораздо более частый выигрыш.
Если вы думаете, что они консервативны или склонны к риску, выберите предел 18. Это победит, если они останутся где-то ниже 18 лет.
Для нейтральной земли, возможно, подумайте, каким будет ваш лимит без какого-либо влияния извне. Вы обычно бы попали на 16? 17?
Короче говоря, вы можете только догадываться, каков предел вашего оппонента, но если вы хорошо угадываете, вы можете победить их в долгосрочной перспективе с помощью этой статистики.