Конь-светлячок

Делись идеей, получай поддержку и критику!
Ответить
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Конь-светлячок

Сообщение FireFly »

Хочу поделиться своим нынешним вариантом алгоритма для олимпиады "Ход-конем 2011"

Конь-светлячок v1.0.1
FireFly.zip
LV10
(95.17 КБ) 270 скачиваний
Надеюсь версия рабочая (внес парочку изменений толком проверить времени не было).

Полное описание выложу завтра, сейчас уже хочу спать. Вообще в коде много комментов, так что должно быть понятно и так. VI вычисления веса/рейтинга клетки специально не комментил, т.к. там нужно развернутое объяснение, да и меняться она будет ещё очень сильно.
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Re: Конь-светлячок.

Сообщение FireFly »

Используемые понятия:
Позиция.png
Позиция.png (2.46 КБ) 5275 просмотров
Позиция - кластер, предложенный нам организаторами, состоящий из координат коня и его номера
ИС.png
ИС.png (6.99 КБ) 5275 просмотров
Игровая ситуация (далее ИС) - кластер включающий в себя:
1) Текущее состояние поля
2) Текущую позицию нашего коня
3) Итоговый вес/рейтинг игровой ситуации (полученный как сумма рейтингов всех посещенных клеток на пути от клетки старта до текущей позиции).
4) Первый ход, который привел в итоге к данной игровой ситуации

Позиции врагов в игровую ситуацию не входят!

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

Для объяснения своей идеи я нагло воспользуюсь картинкой наших конкурентов:
массивы.png
В нашу VI подают поле, позицию нашего коня и массив позиций соперника. Из нашей позиции и поля формируем начальную ИС.
Из нашей позиции в условиях текущего поля есть несколько доступных ходов. Количество от 1 до 8*. Выполняем все N доступных ходов (при этом изменяем поле) и получаем N новых ИС.
Теперь для КАЖДОЙ из этих ИС ищем новые доступные ходы, делаем их, получаем следующий массив ИС. Таким образом каждая ИС порождает ещё от 1 до 8 новых ИС (следующей "глубины").

По оценке сверху ИС могут расти в геометрической прогрессии увеличивая свое количество в 8 раз при понижении глубины на 1. Однако обычно доступных ходов меньше 8, поэтому рост количества медленнее.
Помимо этого количество ИС можно уменьшить удаляя повторяющиеся. Например мы пришли в одну клетку разными путями, не изменив при этом поле (шли по уже занятым клеткам).

Таким образом задача сводится к определению какой пройденных путей лучше (какая из ветвей дерева выгоднее). Для этого для каждого шага лошади введем рейтинговую систему.

Если честно я уже сам запутался в объяснении, поэтому лучше перейду к реализации.

*Доступные ходы могут отсутствовать только при старте игры в искусственных ситуациях. При нормальной игре они есть всегда.
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Re: Конь-светлячок.

Сообщение FireFly »

Блок-диаграмма основной Vi:
Horse.vi_1.png
Horse.vi.png
Собственно о чем я и говорил выше. Из поля и позиции формируем ИС. Вес берем равным нулю. Первый ход пока не заполняем.
Для основного цикла создаем шифт-регистр в котором будем передавать массив ИС для анализа в следующую итерацию. Инициализируем шифт-регистр нашей начальной ИС (через Build Array).
Помимо этого засекаем время старта VI. Это нам нужно чтобы не выйти за пределы 3 секунд.

Чтобы в наших ИС заполнить поле "Первый ход" будем рассматривать первую итерацию в отдельном Case. Берем нашу начальную ИС и выполняем SubVI "AI". Данная SubVI занимается формированием массива новых ИС (создает ИС для каждого доступного хода из текущей позиции). В новых полученных ИС значения поля "Текущая позиция" копируем в поле "Первый ход". Теперь в будущем, на любой глубине анализа мы легко сможем узнать какой же первый ход привел нас к этой конкретной ИС. И если эта ИС нам очень-очень нравится мы поймем какой ход нам надо делать.

Итак глубину 1 мы проанализировали. Подаем массив ИС на шифт-регистр, переходим к следующей итерации. Второй Case предназначен для всех следующих итераций.
Массив ИС полученный с предыдущей глубины мы подаем на цикл For. У этого цикла For есть шифт-регистр (инициализированный пустым массивом ИС). В этом шифт-регистре мы будем накапливать ИС текущей глубины для последующей передачи их на анализ в следующую итерацию.
Для каждой ИС как и раньше получаем массив новых доступных ИС. Но в массив ИС текущей глубины добавляем только те ИС, которые не являются повторами уже находящихся в массиве. Для этого используем SubVI "Cleaning".

В каждой итерации цикла For мы смотри - не истекло ли время. Если время истекло - мы бросаем анализ и подаем на выход цикла While массив ИС предыдущей глубины.

Напоминаю что ИС хранит в себе параметр "Вес/рейтинг", как он формируется расскажу потом. Этот параметр используется в финальной части нашей VI. Из всего массива выбирается ИС с максимальным рейтингом, после чего из неё извлекается параметр "Первый ход". Это значение и является результатом работы нашего алгоритма и оно подается на выход VI.
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Re: Конь-светлячок.

Сообщение FireFly »

Основные идеи алгоритма "Конь-Светлячок":
1) Рассматриваем все возможные цепочки ходов нашего коня на столько ходов вперед (на такую глубину), на сколько хватит времени. Т.е. строим "дерево всех возможных ходов" из начальной позиции.
Глубина 0 - от 1 до 8 возможных ходов из начальной позиции.
...
Глубина N+1 - от 1 до 8 возможных ходов, для КАЖДОГО возможного хода глубины N.
2) У каждого хода есть вес/рейтинг. Вес цепочки равен сумме весов каждого хода из неё.
3) В конце алгоритма на выход подаём координаты клетки с которой началась цепочка с максимальным весом. Т.е. фактически ходим нашим конем в эту клетку.
4) Вес незанятой клетки всегда (на любой глубине анализа) больше нуля.
5) Вес уже занятой нами клетки всегда равен нулю. Т.о. ход на занятую клетку возможен только благодаря большому весу последующей цепочки ходов.
6) Вес хода падает с увеличением глубины анализа. Т.о. при прочих равных, будет выгоднее сходить в ту пустую клетку, которая ближе.
7) Рассматривать все возможные ходы противников слишком затратно. Вместо этого будем учитывать в весе хода расстояние противника до данной клетки.
8) Вес незанятой клетки, до которой не может добраться ни один противник, существенно меньше, чем вес всех остальных пустых клеток (даже на большой глубине), но больше нуля. Т.о. конь до самого конца игры будет игнорировать такие клетки, и стремиться занимать клетки доступные врагу. И только когда спорные клетки закончатся, "добьет" все недоступные врагам клетки.
9) В самом начале работы алгоритма "Конь-Светлячок" для каждого соперника с помощью волнового алгоритма считаем сколько ходов ему нужно из его позиции до каждой пустой клетки. Тут же определяем до каких пустых клеток он не способен добраться.
10) Вес хода на пустую клетку складывается из трех составляющих:
а) Константа больше нуля. Реализует п.4
б) Стратегическая ценность клетки. Определяется как произведение константы, на количество пустых клеток, из неё доступных.
в) Агрессивный вклад. Некая функция зависящая от расстояний всех противников до данной клетки. На N-ой глубине анализа максимальный агрессивный вклад будет у тех клеток, расстояние противника до которой совпадает с глубиной анализа. Т.е. нам до клетки столько же ходов, сколько и противнику, следовательно есть возможность его "подрезать". Функция максимальна, когда расстояние до клетки совпадает, равна нулю, когда противник к клетке ближе и убывает в с торону "противник от клетки дальше", но не должна убывать слишком быстро, чтобы избежать ситуации, когда наш конь из двух путей до клетки при прочих равных выберет тот, что длиннее (из-за того что расстояние станет сильнее совпадать с расстоянием до неё противника, агрессивный вклад станет больше, и превысит падение рейтинга от глубины анализа). В случае нескольких соперников их агрессивный вклад складывается и делится на их количество. Деление агрессивного вклада не дает нашему коню увлечься "подрезанием" одного противника забив на других, т.к. влияние стратегической ценности клетки становится больше.
Все три составляющие складываются и делятся на функцию, возрастающую с глубиной, и отвечающую за п.6
На данный момент функция в знаменателе это 1.2^N, где N-глубина анализа
Константа в стратегической ценности 0.15
Агрессивный вклад высчитывается через Case. Значения можно посмотреть в алгоритме.
Все цифры получены после долгих расчетов различных ситуаций на бумажке.
11) В ходе работы алгоритма будем работать с кластером "Игровая ситуация" (далее ИС), включающим в себя:
а) Текущее состояние поля. Каждый ход в пустую клетку в цепочке изменяет игровое поле, и результат сохраняется в ИС
б) Текущая позиция нашего коня на нынешней глубине анализа.
в) Суммарный вес цепочки ходов. Upd: Вместо одного значения храним массив - значение веса цепочки на каждой глубине.
г) Первый ход, который привел нас к текущей ИС. Хранить всю цепочку ходов не имеет смысла. В конце работы алгоритма, после выбора ИС с максимальным весом её первый ход и будет результатом работы алгоритма (ходом нашего коня).
12) Расстояние противников до каждой пустой клетки считаем только для начального игрового поля, а не для каждой ИС. Это немного угрубляет модель, но экономит ресурсы.
13) После получения всех возможных ИС на данной глубине проводим очистку от дублей, т.е. таких ИС, у которых совпадает текущее положение коня и игровое поле (разными путями пришли в одну и ту же клетку, одинаково изменив поле). Выбираем ИС с бОльшим рейтингом.
14) ИС первой глубины анализа рассчитываем отдельно (перед циклом). Очистку от дублей не проводим. Заполняем поле "первый ход" в ИС значением "текущая позиция".
15) По ходу работы алгоритма постоянно смотрим время. Если на некоторой глубине анализа обнаруживаем, что время больше, чем время старта алгоритма+2.6 сек - останавливаем работу алгоритма, и из ИС предыдущей глубины ищем ИС с максимальным рейтингом, берем её "первый ход" и подаем на выход.
16) Хочется отмечать повышенным рейтингом такие ходы, которые могут сделать одну или несколько пустых клеток недоступными для врагов (т.е. поощрять ходы, создающие области доступные только нам, для захвата их в конце игры). Но пока не придумал не слишком затратной реализации этого. Скорее всего так и останется нереализованным :(
17) По хорошему нужно сильнее подрезать противников, с бОльшим счетом и слабее с меньшим. не успеваю сделать :(
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Аватара пользователя
FireFly

Activity Black
expert
expert
Сообщения: 1321
Зарегистрирован: 25 апр 2009, 08:58
Награды: 2
Версия LabVIEW: 2014
Откуда: Санкт-Петербург
Поблагодарили: 1 раз

Re: Конь-светлячок.

Сообщение FireFly »

Это решение я отправил на конкурс.
Вложения
LabVIEW Portal .vi
(105.07 КБ) 227 скачиваний
LabVIEW Portal.png
Иногда лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.
Ответить

Вернуться в «Проекты»