Игра в кости лжеца - отличная. Легко выучить, сложно освоить. Удачный баланс удачи и стратегии. Если вы не знаете игру, я рекомендую вам проверить ее, она отлично подходит для группы.

В нашей последней сессии мы столкнулись с интересной ситуацией, когда дошли до последних двух. У одного игрока были все 6 оставшихся кубиков, в то время как у его соперника остался один. Конечно, это вызвало много дискуссий и побочных ставок. В основном мы задались целью (читай: аргументировано), чтобы ответить на следующие вопросы:

Может ли игрок со всеми шестью кубиками разработать оптимальную стратегию, гарантирующую победу?

Если нет, каковы шансы игрока, у которого есть только один кубик?

И вот так родилась ставка. Ставка, даже не вовлекающая двух игроков, фактически играющих в игру.

Стратегия

Прежде чем мы перейдем к ставке, нам нужно было согласовать стратегию игрока со всеми 6 кубиками. Мы довольно быстро пришли к выводу, что во избежание «блефа» игроку с 6 следует просто коллировать самую высокую цену, которую он может уравнять, и надеяться, что оппонент с 1 кубиком не сможет его победить. Итак, учитывая кубик 1, 1, 3, 4, 4, 5, он должен назвать четыре 4 (1s - дикие).

Игроки

После прохождения минимальных курсов теории игр в колледже я склонен предполагать, что всегда есть какая-то странная оптимальная стратегия. Мне не удалось найти указанную стратегию, но я, конечно, сразу же начал пробовать. Моя цель состояла в том, чтобы найти некоторую последовательную стратегию (такую, которая не допускала бы переменного блефа, несмотря на то, что это ключевой компонент игры), а затем рассчитать шансы того, как часто она будет выигрывать. Статистический (а значит, верный, верно?) Подход к проблеме.

По другую сторону пари был мой друг Курт. Курт, давно играющий в карты, не сразу задумывается о математике. Вместо этого он быстро начинает прокручивать в своей голове тысячи итераций того, как могла бы развиваться игра. Его интуиция относительно шансов и возможность наблюдать за игрой столько раз позволяет ему определять, как часто каждый игрок будет выигрывать.

Ставка

Моя быстрая математика показала мне, что игрок со всеми 6 кубиками проиграет только в том случае, если у оппонента будет тот же номер, который он назвал, или если у него будет 1 (подстановочная карта). Учитывая 1, 1, 3, 4, 4, 5 и колл четырех 4, проигравший выигрывает только тогда, когда у него есть 4 или 1, что позволяет ему коллировать пять 4 и выиграть. Выпадение 1 и другой конкретный бросок будут происходить 1 из 3 раз, и это должно произойти 6 раз подряд, чтобы проиграть. Другими словами, только 1 из 729 раз выиграет проигравший.

Курт проделал в своей голове какой-то другой вид магии вуду игрока и смело воскликнул: «Если вы дадите мне 1 кубик против ваших 6 15 раз подряд, держу пари, я выиграю один». Я только что рассчитал шансы со 100% уверенностью (а может, и нет ...) увидел возможность нанести удар. Я так быстро ответила: «Ты в курсе», что Курт предположил, что он сомневается, основываясь на моей уверенности. Я немного отказался от его просьбы о коэффициенте 2: 1 (он уже получил коэффициенты, прогнав его 15 раз), но в конце концов сдался, думая, что я все еще статистический блокировщик.

6 кубиков против 1 кубика. 15 раз подряд.

Время играть.

Результат

Первые несколько поворотов прошли точно по плану. Я бы назвал что-то вроде трех 5, у Курта 3, игра окончена.

По большей части первые 10 игр прошли отлично. Курт бросил там пару 1, но каждый раз на следующем ходу он проигрывает. Но потом, где-то около 10-й игры, что-то произошло.

Я выбросил 1 1 3 4 4 5 и, в соответствии со стратегией, колл четыре 4, максимум, который я мог безопасно коллировать. Затем Курт возвращается с четырьмя 5, бросив свой собственный 5.

Вот дерьмо.

Я проиграл, а он не выполнил ни дубликата, ни 1. В конце концов я все равно выиграл ту игру, но он все же поставил у меня до трех кубиков. Я прошел следующие несколько игр без проблем и выиграл пари. Но мой интерес был возбужден. Мои предположения и, следовательно, мои шансы были неверными. Я должен узнать, что они на самом деле.

Моделирование

Теперь, понимая, что проблема, возможно, сложнее, чем может решить простая статистика, я решил написать простой сценарий моделирования, который мог бы запускать множество попыток, чтобы получить оценку шансов. Это также казалось хорошей возможностью протестировать Jupyter Notebooks, что я давно собирался сделать. Весь код и записные книжки iPython для этого проекта доступны на GitHub.

Построить рандомизацию игральных костей, общий игровой процесс и мою простую стратегию, основанную на правилах, не блефовать, было не так уж сложно. Реальной переменной в этой ситуации является стратегия, которую должен использовать Курт.

Заезд 1 - Первый верх

В качестве проверки вменяемости я хотел проверить свои первоначальные шансы и дать Курту базовую стратегию. Что бы я ни предлагал, Курт делает еще одну ставку и надеется, что у него есть 1 или какой бы номер я ни назвал. Не умно, но хорошая отправная точка.

def get_kurts_bid(my_dice, num_dice_matt_has, matts_bid=None):  
    if matts_bid is None:
        # If Matt has not bid yet start off with 1 of my dice
        return (1, my_dice)
    else:
        # Return one more of what Matt said
        return (matts_bid[0] + 1, matts_bid[1])

Полученные результаты:

Simulation Complete
-------------------
Num Simulations: 10,000,000
Took:            247.9 seconds
Kurt Wins:       13,742
Win Percent:     0.14%
Wins 1 in 727.70 times

Конечно, 10 миллионов симуляций показывают, что мои шансы 1 к 729 были правильными. Это также, что, возможно, более важно, показывает, что код работает. Пора начинать оптимизацию.

Заезд 2 - Хороший догадыватель

Может быть, мы сможем добиться большего, если попытаемся заманить Мэтта в ловушку на первоначальной ставке. Вместо того, чтобы позволить Мэтту вести дело, Курт может попытаться угадать номер, по которому Мэтт все равно позвонил бы. Первоначальное предположение о трех любых кубиках, которые бросает Курт, кажется хорошим предположением.

def get_kurts_bid(my_dice, num_dice_matt_has, matts_bid=None):
    if my_dice == 1:
        if matts_bid is None:
            return (1, 2) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])
    else:
        if matts_bid is None:
            return (3, my_dice) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])

Полученные результаты:

Simulation Complete
-------------------
Num Simulations: 10,000,000
Took:            243.0 seconds
Kurt Wins:       14,365
Win Percent:     0.14%
Wins 1 in 696.14 times

Незначительное улучшение, упало до 1 из 696 раз, когда Курт выигрывал. Это действительно имеет смысл, в основном из-за игрового процесса. Как только Курт выигрывает первый ход, Мэтт становится первым в последующих ходах. Так что на самом деле эта стратегия влияет только на самый первый ход игры.

Run 3 - The End Gamer

Поскольку предыдущая стратегия повлияла только на первый ход, давайте посмотрим, сможем ли мы стать умнее к концу игры, если у нас получится.

Когда дело доходит до Мэтта, имеющего два или меньше кубиков, Курт хочет угадать два из его кубиков. Надежда - Мэтт бросает 1, 3, а Курт 4. Мэтт угадывает два 3, Курт возвращается с двумя 4 и выигрывает.

def get_kurts_bid(my_dice, num_dice_matt_has, matts_bid=None):
    # When Matt has 2 or less dice, guess 2 of whatever I have if I can, otherwise guess 3 of them
    if num_dice_matt_has <= 2:
        if (2, my_dice) > matts_bid:
            return (2, my_dice)
        return (3, my_dice)
    
    if my_dice == 1:
        if matts_bid is None:
            return (1, 2) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])
    else:
        if matts_bid is None:
            return (3, my_dice) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])

Полученные результаты:

Simulation Complete
-------------------
Num Simulations: 10,000,000
Took:            243.5 seconds
Kurt Wins:       14,831
Win Percent:     0.15%
Wins 1 in 674.26 times

Немного лучше, но мы по-прежнему не причиняем такого большого ущерба. В любом случае Курт доходит до двух последних кубиков примерно 1 из 80 раз. Любая стратегия, которую мы здесь реализуем, не слишком помогает в целом.

Заезд 4 - Скрещивание пальцев

Давайте применим ситуацию, которая произошла в реальной игре. В качестве напоминания Мэтт выбросил 1 1 3 4 4 5 и назвал четыре 4. Затем Курт вернулся с четырьмя 5, скатав свой собственный 5. Таким образом, стратегия Курта состоит в том, чтобы угадать то же количество, которое предлагает Мэтт, но вместо того, которое у него есть. Есть надежда, что у Мэтта есть только один естественный бросок из этого числа, а остальные 1s.

def get_kurts_bid(my_dice, num_dice_matt_has, matts_bid=None):
    # When Matt has 2 or less dice, guess 2 of whatever I have if I can, otherwise guess 3 of them
    if num_dice_matt_has <= 2:
        if (2, my_dice) > matts_bid:
            return (2, my_dice)
        return (3, my_dice)
    
    if my_dice == 1:
        if matts_bid is None:
            return (1, 2) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])
    else:
        if matts_bid is None:
            return (3, my_dice)  # Might as well try and trap him
        elif (matts_bid[0], my_dice) > matts_bid:
            return (matts_bid[0], my_dice)  # Hoping for [1, 1, 3] against [4]
        else:
            return (matts_bid[0] + 1, my_dice) # Hope he has all 1s?

Полученные результаты:

Simulation Complete
-------------------
Num Simulations: 10,000,000
Took:            294.1 seconds
Kurt Wins:       89,389
Win Percent:     0.89%
Wins 1 in 111.87 times

Оооо, прогресс. Курт сейчас выигрывает 1 из 112 раз. Эта ситуация, когда есть все 1 и один натуральный, на самом деле случается часто, особенно ближе к концу игры, когда остается меньше кубиков.

В последнем случае, если Мэтт вызывает три 4, а у меня, например, 3, Курт вызовет четыре 3. Насколько я могу судить, это происходит только тогда, когда Мэтт выбрасывает все 1, так что, вероятно, не много.

Прогон 5 - Настройщик

Поразмыслив над последней стратегией, я понимаю, что она, по сути, такая же, как и исходная конечная стратегия. На самом деле, это даже лучшая стратегия в конце игры! Предыдущая стратегия конечной игры, предполагающая угадать 2 из того, что есть у Курта (если возможно), не учитывает бросок Мэтта на 45 и Курта на 46. Мэтт угадывает одну 4, Курт должен угадать одну 5, но раньше угадывал две 5.

Давайте применим общую стратегию игры и к финальной игре.

def get_kurts_bid(my_dice, num_dice_matt_has, matts_bid=None):
    if my_dice == 1:
        if matts_bid is None:
            return (1, 2) 
        else:
            return (matts_bid[0] + 1, matts_bid[1])
    else:
        if matts_bid is None:
            return (3, my_dice)  # Might as well try and trap him
        elif (matts_bid[0], my_dice) > matts_bid:
            return (matts_bid[0], my_dice)  # Hoping for [1, 1, 3] against [4]
        else:
            return (matts_bid[0] + 1, my_dice) # Hope he has all 1s

Полученные результаты:

Simulation Complete
-------------------
Num Simulations: 10,000,000
Took:            301.5 seconds
Kurt Wins:       354,633
Win Percent:     3.55%
Wins 1 in 28.20 times

Ухааа !! Курт выигрывает таким образом 1 из 28 раз!

Возможно, это имеет смысл. Курту просто нужно сделать пару поворотов, свернув 1 или такой же, как у меня, а затем он должен рассчитывать на то, что я брошу 1. Это определенно случается, и оказывается, что это случается примерно в 3,5% случаев.

Исход

Итак, 15 попыток с коэффициентом 2: 1 на самом деле сейчас выглядят неплохо.

Что еще более важно, это показывает, что интуиция Курта была почти правильной. Это действительно увлекательно для меня, просто опираясь на прошлый опыт и видя столько бросков кубиков, Курт смог почти точно предсказать шансы этого сложного сценария.

По крайней мере, я все же выиграл пари.

Это сообщение размещено в личном блоге Мэтта Доджа. Прочтите исходный пост здесь.