Правда тут есть баланс. Либо делать сложную проверку, тогда больше получится отсечь, но работать будет медленней.
Да, я тоже над этим долго ломал голову. В итоге пришёл к выводу, что лучше решать задом наперёд. Статистика показывает, что при решении обратным ходом мёртвых позиций возникает на порядок меньше, в связи с чем от проверки тупиковых состояний можно вообще отказаться. Получается два зайца одним выстрелом: решается быстро и рационально. Особенно, если сделать небольшой препроцессинг карты.
Да, для оптимизации можно выбрать разные цели. Можно оптимизировать количество ходов агента. А можно оптимизировать количество толканий ящика...
По второй цели состояние - это просто положение ящиков и в какой области агент (если ящики разбили поле на несколько областей между которыми агент не может перемещаться не трогая ящики). По первой цели - это положение ящиков и положение агента.
Это, вообще говоря, не верно. Вне зависимости от того, какая цель оптимизации является первоочередной, для каждого пути в графе решений подсчитывается как число ходов, так и количество толканий. Потому что при сравнении двух путей используемая (в зависимости от цели) компараторная функция учитывает обе эти величины. Поэтому в обоих случаях состояния задачи представляются одинаково. Я писал об этом вкратце в первом посте. Если владеете инглишем, то на
Sokoban-Wiki в статье
Moves vs. Pushes подробно этот вопрос разбирается. В частности:
Цитата:
Note: a ratio of 1 to
doesn't mean that the other value is completely irrelevant!
Exmaple:
A solution of 20 moves / 4 pushes is a better solution for a level than 20 moves / 6 pushes
Нашел в архивах последнюю версию солвера.
Она эту карту номер 10 за 373 секунды решила.
Интересно было бы посмотреть код.
Тема с
А-стар, конечно, интересна, этот алгоритм позволяет искать не просто в ширину, а направленно в сторону искомого состояния. Особенно, если функция оценки близости двух состояний достаточно точна. Однако, я тут на протяжении всего этого времени понемногу размышлял над решением Сокобана в целом и мне видится следующее.
Основная проблема задачи в том, что пространство решений задачи невероятно велико и растёт практически экспоненциально с размером карты. При решении в лоб это требует пропорционального расхода памяти, и, вне зависимости от метода решения, — серьёзных временных затрат. Это связано с тем, что большинство алгоритмов обрабатывают всю карту целиком. Представим себе задачу с двумя комнатами. Для каждого положения ящиков одной комнате такие алгоритмы рассматривают каждое положение ящиков в другой комнате. В результате полное число
рассматриваемых состояний задачи с
ящиками будет равно сумме произведений количества состояний
в первой комнате с
ящиками на число состояний
во второй комнате с
ящиками:
Было бы здорово разделить решение задачи на такой карте на две части: отдельно для каждой комнаты, а потом их сложить. Тогда новое число рассматриваемых состояний будет значительно меньше:
Плюс накладные расходы на сшивку двух решений. Фактически, это идея метода
Разделяй и властвуй, который отлично работает с задачами экспоненциальной сложности. Только здесь происходит остановка после первого деления. Решив задачу в каждой комнате и найдя оптимальные пути и их композитные "длины" между
граничными нодами в пространстве решений для каждой комнаты, можно будет без труда найти решение всей задачи. Более того, функция оценки расстояния от текущего состояния до искомого будет гораздо более точна, а поиск не будет упираться в мёртвые позиции.
К сожалению, это пока всё на стадии размышлений. Не представляю даже как организовать техническую сторону этого подхода, слишком много вопросов. Как хранить состояние каждой комнаты, и как — состояние всей задачи? Как организовать пространство решений для каждой комнаты, и как — для задачи целиком? Ведь при обычном поиске расстояние измеряется от одной (или нескольких) начальных нод, а сам граф решений представляет дерево (или, соответственно, несколько деревьев), растущее из этой ноды (каждое новое состояние цепляется к тому состоянию, через которое проходит оптимальный маршрут). При решении через разбиения на комнаты придётся для каждой комнаты строить полноценный направленный граф решений, а после его построения находить кратчайшие расстояния между
граничными нодами. Под
граничными я здесь понимаю такие состояния, в которых ящик или двигающий агент входят в или покидают комнату.
Ну и про автоматизацию разбиения задачи на комнаты я вообще молчу. Тут для начала можно вообще отдать это на откуп человеку.