--- title: Гадалка Шеннона description: Демо-версия электронной гадалки Шеннона keywords: [гадалка, угадыватель, шеннон, чет-нечет] styles: - /static/predictor.css scripts: - /static/predictor.js --- В студенческое время я наткнулся на интересную статью об [игре "Чет-нечет"][game] на домашней страничке пользователя [ltwood][ltwood]. Правила очень простые. Игрок загадывает один вариант из двух: "чет" или "нечет", а оппонент пытается угадать выбор игрока. Если угадать не удалось, то очко получает загадавший, а если угадать получилось - то угадывающий. Кто первым наберет 20 очков, тот и молодец! Кажется, что в этой игре все случайно. Случайно загадывается число, потом случайно второй игрок пытается угадать что же было загадано. Я очень сильно удивился, когда попробовал поиграть в эту игру с программой и за десять попыток так ни разу и не выиграл. Парадокс в том, что мы _думаем_ что загадываем числа случайно. На самом деле все не так, и последовательность загаданных чисел не случайна. Исходного кода оригинальной гадалки в открытом доступе нет, есть только [описание алгоритма][algo], по которому я сделал свою реализацию на TypeScrypt. ## Демоверсия Попробуйте набрать 50 очков и выиграть. Чтобы выбирать вариант с клавиатуры, кликните внутри серой рамки, а потом пользуйтесь клавишами "1" - нечет или "2" - чет. ---
--- ## Как Это работает Математически алгоритм на [странице][algo] сайта ltwood. Я рассмотрю простой пример, чтобы показать принцип. В основе алгоритма находится популяция "демонов" - автоматов, которые на основании ходов игрока и предсказанных значениях выдают новое предсказание. Демонами управляет супервайзер. Задача супервайзера в том, чтобы опросить всех демонов, выбрать ответ от одного их них, а после получения ответа игрока пометить тех, кто выдал правильный ответ. Алгоритм состоит из двух шагов: - предсказать следующих ход игрока; - учесть реальный ход игрока, добавив веса тому демону, который предугадал ход. Рассмотрим работу на примере одного демона. Пусть у нас есть демон, который смотрит на последний хода игрока и на свое последнее предсказание. Строим два вектора: - `[<1 ход демона>, <1 ход игрока>, 0]` - `[<1 ход демона>, <1 ход игрока>, 1]` В самом начале, когда у демона нет никакой информации о ходах игрока, эти векторы будут выглядеть как `[0]` и `[1]`. Но с накоплением данных, они всегда будут каждый по 5 элементов. После чего смотрим, который из таких наборов в прошлом приносил победу чаще, и соответственно выбираем или вариант с 0, или с 1. После получения действительного хода игрока, мы увеличиваем вес того набора, который оказался верным. И далее снова предсказываем ход. Теперь с числами. #### Ход 1 У демона нет информации, наборы `[0]` и `[1]` равнозначны, выбираем `[0]`, а значит предсказываем ход игрока 0. Игрок загадывал 1. Обновляем веса: ``` [0] = 0 [1] = 1 ``` #### Ход 2 Строим векторы на основе последних ходов: ``` 0: [0, 1, 0] 1: [0, 1, 1] ``` Для этих векторов тоже еще нет весов, так что снова выбираем первый, предсказываем 0. Игрок снова выбрал 1. Обновляем веса (помним, что еще были прошлые вектора из одного элемента): ``` [0] = 0 [1] = 1 [0, 1, 0] = 0 [0, 1, 1] = 1 ``` #### Ход 3 Картина такая же, как на втором ходу, но отличие в том, что у нас есть веса с прошлого хода: ``` 0: [0, 1, 0] - 0 1: [0, 1, 1] - 1 ``` Выбираем вариант 1, игрок снова выбирает 1. Предсказание удалось! ## Расширение алгоритма Это был самый элементарный вариант. Понятно, что на таком далеко не уедешь, и никого не обыграешь. Чтобы хорошо предугадывать ходы игроков, используется несколько демонов с разной величиной просматриваемой истории. Следит за ними "супервайзер", который ведет для каждого демона рейтинг. На основе этого рейтинга выбираются ответы тех демонов, которые были наиболее успешны в своих предсказаниях. ## Ссылки - [Код гадалки][repo] - [Описание алгоритма][algo] - [Описание игры у ltwood][game] [ltwood]: https://sites.google.com/site/ltwood/ [game]: https://sites.google.com/site/ltwood/projects/heshby [algo]: https://sites.google.com/site/ltwood/projects/heshby/algorithm [repo]: https://github.com/anwinged/predictor