Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
58 / 42 / 21
Регистрация: 01.01.2018
Сообщений: 273

Хеширование состояния поля в игре Nine Men's Morris (мельница)

26.12.2019, 10:20. Показов 2237. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Не уверен, что в тот раздел. Подскажите, если что

Итак, есть поле для игры на 24 ячейки, есть 2 игрока с девятью фишками на руках.
Фаза 1: каждый игрок поочередно выставляет на свободную ячейку фишки
Фаза 2: игроки перемещают фишки по линиям на поле
Фаза 3: игрок с 3 оставшимися фишками получает возможность переставлять свою фишку на любое свободное поле

Если игрок собрал мельницу (3 фишки в ряд), то он забирает любую фишку соперника. Дальше уточнять правила не буду, только приведу ссылку на англоязычную статью: http://library.msri.org/books/... gasser.pdf

Там описываются идеи, заложенные в основу вычисления хеш-функции, и приводятся правила игры.

Теперь о задаче: необходимо закодировать любое возможное в ходе игры состояние поля наименьшим количеством бит (короче, оценочная функция должна описывать любое состояние и при этом возвращать числовое значение в разумных пределах)

Немного моих выкладок (в терминах памяти): итак, если 24 клетки могут иметь три состояния (свободна либо занята игроком), то грубая оценка сверху дает 3^24 состояний доски. Допустим, состояние 5 клеток мы поместим в один байт (241 из 256 значений, почти полностью займем место), тогда на всю доску у нас уйдет 5 байт. При количестве состояний 3^24 (282 млрд) мы можем хранить их, используя всего лишь 282*5 Гб дискового пространства. На руках сейчас имеется 700 гб, и очень не хотелось бы использовать их все. Вот так как-то.

Из бонусов: это все нужно для предпросчета игры для примитивненького ИИ, и для упрощения можно предположить, что у соперника нет шансов построить мельницу и отнять у нас фишку
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
26.12.2019, 10:20
Ответы с готовыми решениями:

Предпросчет возможных ходов в игре Nine Men's Morris (Мельница)
Пытаюсь сделать хотя бы частичный предпросчет возможных ходов в игре Nine Men's Morris (Мельница). Была мысль построить что-то вроде дерева...

Определение состояния соседей в игре в жизнь
Здравствуйте. Пытаюсь сделать свою вариацию игры в жизнь. Она у меня будет довольно маленькой, всего 64 клетки на площади 8Х8. Состояние...

Изменение состояния кнопки и поля в бд по клику
PHP уровень-'ниже плинтуса' но времени очень мало.Пытаюсь сделать редактирования поля бд. на сайте. В поле сделал кнопку, при нажатии на...

12
Модератор
Эксперт функциональных языков программирования
3133 / 2280 / 469
Регистрация: 26.03.2015
Сообщений: 8,874
26.12.2019, 15:54
Цитата Сообщение от Ksardas_178 Посмотреть сообщение
При количестве состояний 3^24 (282 млрд)
Не все состояния допустимы. Например, если на доске 1 белая фишка, то чёрных может быть не больше 1. Или на доске не может быть больше 9 фишек одного цвета.

Состояние, кроме расположения фишек должно включать фазу и чей ход.
Можно отдельно хранить (и кодировать) состояния для фазы 1 и состояния для фаз 2/3.

Добавлено через 21 минуту
Заглянул в статью. Там всё это написано. И даже приводится алгоритм для вычисления цены всех состояний. В чём вопрос?
0
58 / 42 / 21
Регистрация: 01.01.2018
Сообщений: 273
26.12.2019, 17:35  [ТС]
Shamil1, возможно, я чего-то не разглядел, но в статье описаны идеи, примененные для сокращения количества состояний. Да, на их основе можно перебрать все состояния, выкинуть лишние и получить около 8 млрд в сухом остатке, но вопрос в том, как построить алгоритм перевода состояния поля в число.

Добавлено через 2 минуты
И да, надеюсь, вариант вроде "перебирать что есть, выкидывая лишнее, и пересчитывать новый индекс для реально существующих состояний" мы не рассматриваем. Неприемлемо по времени.
0
Модератор
Эксперт функциональных языков программирования
3133 / 2280 / 469
Регистрация: 26.03.2015
Сообщений: 8,874
27.12.2019, 00:50
В статье описан алгоритм, который работает на десктопе 1990-го года. Полагаю, проблем по времени быть не должно.
0
294 / 265 / 48
Регистрация: 09.04.2013
Сообщений: 1,038
27.12.2019, 18:55
А ты действительно хочешь делать ИИ в виде гигабайт данных вида (состояние -> ход) ?
Почему бы не реализовать что-то наподобие шахматного ИИ? Например, для каждого хода - дерево возможных будущих событий с отсеченем плохих веток.

Цитата Сообщение от Ksardas_178 Посмотреть сообщение
но вопрос в том, как построить алгоритм перевода состояния поля в число.
Ячейки доски имеют 3 состояния, 24 ячеек - следовательно у тебя число из 24 цифр по основанию 3.
А перевести число из одной системы счисления в другое - не должно составить проблем.
Там получается 39 бит. Записываем ответ в буфер uint64 и выдергиваем из него эти 5 байт информации, и также в обратную сторону.
0
58 / 42 / 21
Регистрация: 01.01.2018
Сообщений: 273
28.12.2019, 11:43  [ТС]
Цитата Сообщение от wingblack Посмотреть сообщение
Почему бы не реализовать что-то наподобие шахматного ИИ?
Фактически эта часть уже реализована и худо-бедно работает через минимакс. Хранить для нее поле вообще бессмысленно. Есть операции makeTurn(t) и reverseTurn(t), рекурсивный алгоритм просто копает на n шагов вглубь, потом оценивает доску и выбирает лучший ход из возможных, затем откатывает ходы, сделанные для анализа. Все на этом. На глубине 7 ему предсказуемо становится плохо. Играть играет, но зачастую тупит.

Цитата Сообщение от wingblack Посмотреть сообщение
Ячейки доски имеют 3 состояния, 24 ячеек - следовательно у тебя число из 24 цифр по основанию 3.
Это было написано уже в первом посте, только я округлил 39 бит до 5 байт информации. Сейчас с битами никто и не работает. Если писать в int64, получим вместо 5 байт 8.

На вопрос о том, как закодировать поле не функцией с 2^34 состояниями мне, видимо, никто ответить не сможет.
0
Модератор
Эксперт функциональных языков программирования
3133 / 2280 / 469
Регистрация: 26.03.2015
Сообщений: 8,874
29.12.2019, 00:17
Нужно хранить оценки для фаз 2/3 и считать минимаксом фазу 1.
0
294 / 265 / 48
Регистрация: 09.04.2013
Сообщений: 1,038
29.12.2019, 02:44
Цитата Сообщение от Ksardas_178 Посмотреть сообщение
Сейчас с битами никто и не работает. Если писать в int64, получим вместо 5 байт 8.
uint64 удобно использовать как буфер где ты будешь создавать это число по основанию 3. Иначе тебе нужно несколько переменных поменьше и для них реализовывать мини-длинную арифметику.
Да, оно будет занимать 8 байт памяти, но значимыми тут являются только крайние 5 (остальное всегда нули), вот их и хранить.
Ты во время своей рекурсии как хранишь состояние доски - как 24 байта, или кратковременно развертываешь в 24 байта, а перед стартом новой вложенной рекурсии сворачиваешь ее до 5 байт, предварительно освободив память?
А ты учел момент что тебе не нужно сворачивать все ветки, а только после хода противника откидывать "не сработавшие" и расширять ту которая соответствует новому ходу?
Еще можно состояние доски обрабатывать в виде 48 бит, по 2 бита на ячейку, где единица это флаг где какого цвета камень сидит. А для хранения все также в 5 байт сворачивать.

Цитата Сообщение от Ksardas_178 Посмотреть сообщение
На вопрос о том, как закодировать поле не функцией с 2^34 3^24 состояниями мне, видимо, никто ответить не сможет.
А ты думал что у доски есть 3 оси симметрии, что ее можно повернуть в 4 положения и зеркалить по осям?
С точки зрения стратегии все такие "картинки" будут абсолютно одинаковыми состояниями.
0
294 / 265 / 48
Регистрация: 09.04.2013
Сообщений: 1,038
29.12.2019, 12:23
*4 оси симметрии.

А в что у тебя упирается рекурсия, в объем памяти или по времени перебора всех вариантов?
0
58 / 42 / 21
Регистрация: 01.01.2018
Сообщений: 273
29.12.2019, 21:45  [ТС]
Цитата Сообщение от wingblack Посмотреть сообщение
С точки зрения стратегии все такие "картинки" будут абсолютно одинаковыми состояниями.
Одинаковыми-то они будут, вот только если по приведенному алгоритму кодировать состояние доски, даже пытаясь ее покрутить всеми предложенными способами, мы даже на треть не сократим максимальное возвращаемое значение функции. Уберутся промежуточные состояния, что не повлияет на объем памяти, затрачиваемый на хранение. Если неликвидные доски из середины структуры данных вырезать, мы лишимся доступа к базе по индексу доски.

Добавлено через 6 минут
Цитата Сообщение от wingblack Посмотреть сообщение
Ты во время своей рекурсии как хранишь состояние доски - как 24 байта, или кратковременно развертываешь в 24 байта, а перед стартом новой вложенной рекурсии сворачиваешь ее до 5 байт, предварительно освободив память?
Я уже писал выше, что не храню новые доски. Лишь меняю состояние текущей, а после расчетов откатываю назад.

Цитата Сообщение от wingblack Посмотреть сообщение
А ты учел момент что тебе не нужно сворачивать все ветки, а только после хода противника откидывать "не сработавшие" и расширять ту которая соответствует новому ходу?
Да, мелькали такие мысли, но с приведенной выше логикой будет проблемно претворить идею в жизнь. На данный момент программа легко просчитывает 3 хода и с некоторыми задержками выдает 5. Достаточно, чтобы выиграть у большинства людей. Энивей, в этой теме я хотел бы обсудить именно составление полной базы знаний.
0
294 / 265 / 48
Регистрация: 09.04.2013
Сообщений: 1,038
30.12.2019, 11:37
Цитата Сообщение от Ksardas_178 Посмотреть сообщение
даже пытаясь ее покрутить всеми предложенными способами, мы даже на треть не сократим максимальное возвращаемое значение функции
Цитата Сообщение от Ksardas_178 Посмотреть сообщение
Энивей, в этой теме я хотел бы обсудить именно составление полной базы знаний.
Вот и нужно в первую очередь использовать тот факт, что много уникальных состояний будут абсолютно равносильны друг другу!

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

Нужно посмотреть какая последовательность операций позволит перебирать все равносильные состояния доски без повторений.
Например, можно повернуть доску на 90 градусов 0,1,2,3 раза, потом 0,1 раз отзеркалить по вертикали, потом повернуть 0,1,2,3 раза, потом отзеркалить 0,1 раз по главной диагонали, потом повернуть 0,1,2,3 раз
Я не сильно в этом шарю, но предположу что это сокращает размер функции до (4 + 4*4 + 4*4*4) раз (впрочем, здесь будет много состояний которые имеют симметрию - они не будут давать такого большого сокращения функции)

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


P.S. Если делать не рекурсивно, а строить наподобие K-D дерева, то многие ветки будут переплетаться, экономя немного времени.
Кстати говоря, дерево... В программировании же извечный выбор между памятью и производительностью, очевидно что у тебя выбор в сторону уменьшения памяти, почему бы тогда не хранить доску по принципу дерева, но хранить не состояния, а только ходы обоих игроков? Тогда на одно состояние нужно только 5 бит.

Добавлено через 54 минуты
а если их еще не округлять до байта, а хранить пакетами по 8 штук - еще немного места сэкономим
0
Модератор
Эксперт функциональных языков программирования
3133 / 2280 / 469
Регистрация: 26.03.2015
Сообщений: 8,874
30.12.2019, 12:04
ИМХО
Нужно взять фиксированное распределение - например, 3 белых и 3 чёрных фишки - и построить для него все варианты. Затем уменьшить в 16? раз (4 поворота и 2 оси симметрии). После чего, попробовать построить хеш-функцию для данного распределения.
0
Модератор
Эксперт функциональных языков программирования
3133 / 2280 / 469
Регистрация: 26.03.2015
Сообщений: 8,874
31.12.2019, 13:28
Лучший ответ Сообщение было отмечено Ksardas_178 как решение

Решение

Цитата Сообщение от Shamil1 Посмотреть сообщение
Затем уменьшить в 16? раз (4 поворота и 2 оси симметрии).
У квадрата есть 4 оси симметрии - горизонталь, вертикаль и две диагонали. Одна из них вырожденная - любые три преобразования в сумме дают четвёртое. Поэтому можно выбрать из них любые три. Кроме того, у поля Мельницы есть ещё одна ось симметрии - внешний квадрат ничем не отличается от внутреннего. Итого 4 преобразования. Применением от 0 до 4 из них получаем 16 вариантов.

Преобразования можно описать массивами замен:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static int[] vert = new int[] 
{ 
    2,           1,          0, 
         5,      4,      3,  
             8,  7,  6,
    14, 13, 12,     11, 10,  9,
            17, 16, 15,
        20,     19,     18,
    23,         22,         21,
};
 
public static int[] horiz = new int[]
{
    21,         22,         23,
        18,     19,     20,
            15, 16, 17,
     9, 10, 11,     12, 13, 14,
             6,  7,  8,
         3,      4,      5,
     0,          1,          2,
};
 
public static int[] diag = new int[]
{
    23,         14,          2,
        20,     13,      5,
            17, 12,  8,
    22, 19, 16,      7,  4,  1,
            15, 11,  6,
        18,     10,      3,
    21,          9,          0,
};
 
public static int[] invert = new int[]
{
     6,          7,          8,
         3,      4,      5,
             0,  1,  2,
    11, 10,  9,     14, 13, 12,
            21, 22, 23,
        18,     19,     20,
    15,         16,         17,
};
У нас есть массив из 24 элементов, каждый из которых может принимать 3 значения. Для фиксированного количества белых и чёрных фишек получаем перестановки с повторениями - "n элементов m различных типов, причем в каждом типе все элементы одинаковы". Количество перестановок равно мультиномиальному коэффициенту. Можно перебрать их все в лексикографическом порядке и пронумеровать те, которые являются лексикографически минимальными в своём классе из 16 вариантов.

Фактически, предыдущем абзаце описан алгоритм кэшфункции. Проблема в том, что для поиска элемента с индексом эн нужно перебрать все предшествующие (напоминает поиск в линейном списке). Для ускорения используем кэш - массив перестановок с их индексами. Методом деления пополам находим максимальную перестановку меньше/равно искомой и её индекс. Дальше запускаем алгоритм из предыдущего абзаца, но не с самого начала, а с найденного значения. Например, можно "закэшировать" каждую 10,000-ую перестановку (нужно найти баланс между скоростью вычисления нужного индекса и памятью под кэш).
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
31.12.2019, 13:28
Помогаю со студенческими работами здесь

Отображение содержимого текстового поля в строке состояния
Помогите, спасите! Как создать в Java Script текстовое поле, которое при изменении, будет выводить содержимое в строку состояния?

Активность текстового поля, зависящая от состояния переключателя
Доброго времени суток. Помогите решить задачу в Access. Есть таблица: Таб_измерения. Она выводится в форму Измерения. Задача сделать так,...

Создать строку состояния, содержащую три информационных поля
Создать строку состояния, содержащую три информационных поля, отображающих текущую дату, время и координаты указателя мыши. Используя...

Обновление графика morris.js
Необходимо обновить график в зависимости от события, например клика. При загрузке страницы создается дом элемент графика, и соответственно...

База данных и плагин morris.js
Имеется таблица БД следующего вида: id link visit redirect date id - id link - ссылка на какой-то странице сайта visit -...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru