Пустой решатель кроссвордов на Python

Мне дали матрицу, содержащую план кроссворда — незаполненный, конечно. Цель состоит в том, чтобы заполнить всю головоломку — это задача от Checkio, и я уже довольно давно борюсь с этим.

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

Итак, некоторые из вещей, которые я пробовал:

  • простой брутфорс. Не работал вообще, так как игнорировал и перезаписывал пересечения.
  • брутфорс с сохранением всех релевантных данных - работал как положено с конкретным словарем, превратился в ад с умеренно большим словарем даже с оптимизацией длины слова. Цифры.
  • заполнение слепого пересечения - идея, в которой я подумал, что было бы лучше не заморачиваться с пересекающимися словами, вместо этого сосредоточившись на буквах. Например, начните с As и проверьте, сможете ли вы заполнить весь кроссворд с этими ограничениями. Если это не сработало для какого-то слова, увеличьте одну из букв и попробуйте все снова. Результаты были ужасны, как и следовало ожидать.
  • рекурсивное исследование - отлично работало на более простых чертежах, но не работало с более сложными. Была проблема с простыми петлями, которая разрешилась достаточно просто, но я не нашел разумного решения для ситуации, когда путь разветвляется, а затем снова соединяется несколькими дальнейшими разветвлениями (поэтому для второй ветви уже нечего решать, но она не не знаю).
  • минимизация пересечений — еще не проверял, но выглядит многообещающе. Идея в том, что я нахожу кратчайший список слов, содержащий все пересечения... которые также не пересекаются друг с другом. Затем я могу просто использовать генератор для каждого из этих слов, а затем проверить, существуют ли зависимые слова с этими пересечениями. Если нет, я просто беру следующее слово из генератора.

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

Итак, как есть правильный способ сделать это?

Редактировать: ввод представляет собой список строк, представляющих кроссворд, и список строк, представляющих словарь. Результатом является список строк, представляющих заполненный кроссворд.

И пример кроссворда:

['...XXXXXX', 
 '.XXX.X...', 
 '.....X.XX', 
 'XXXX.X...', 
 'XX...X.XX', 
 'XX.XXX.X.', 
 'X......X.', 
 'XX.X.XXX.', 
 'XXXX.....']

кроссворд

На выходе будет аналогичный список с заполненными буквами вместо точек.

Обратите внимание, что «словарь» — это всего лишь небольшой словарь английского языка, а не список слов, подходящих для ответов на эту головоломку.


person Lainesius    schedule 31.08.2017    source источник
comment
Хорошо, спасибо за описание, не могли бы вы также добавить пример головоломки? Более того, я не уверен, что понял это полностью. У вас есть кроссворд, и у вас есть список слов, которые заполняют эту головоломку, и вы ищете, куда их поместить? Или я совсем не прав? ^^   -  person Mathieu    schedule 31.08.2017
comment
(...) оптимального решения не существует (...) должен быть лучший способ сделать это, верно? Ну, лучший способ сделать это - это буквально определение оптимального решения. Чего может не существовать, так это хорошего алгоритма, понимаемого как алгоритм с полиномиальной сложностью в наихудшем случае. В любом случае вы не предоставили надлежащего описания вашей проблемы (входные данные, ожидаемый результат, пример...).   -  person jdehesa    schedule 31.08.2017
comment
Спасибо за пример, но я просто не вижу на нем пересечения слов. Я до сих пор не вижу там кроссворда, сори.   -  person Mathieu    schedule 31.08.2017
comment
Дайте мне минуту, я сделаю визуальное представление этого ввода.   -  person Lainesius    schedule 31.08.2017
comment
Чтобы сократить трудоемкий процесс, вы можете попытаться улучшить способ выбора слова, изучив перераспределение букв в английском языке. Какие буквы используются чаще? Какие самые распространенные первые буквы? Последнее письмо ? Улучшив выбор слов, у вас будет меньше ошибок, а затем и более быстрое решение.   -  person Mathieu    schedule 31.08.2017
comment
@Mathieu Да, это определенно было бы улучшением. Однако, поскольку пересечения не появляются все время в заданных местах, я считаю практически невозможным заранее отсортировать словарь, чтобы он работал над всей головоломкой. И динамическая реализация, которая сортировала бы вещи в зависимости от потребностей прямо сейчас, наверное, была бы такой же сложной, как и основной алгоритм. Так что, хотя это, безусловно, правильный путь для дальнейшего улучшения, я не думаю, что это то, чем мне нужно заниматься прямо сейчас.   -  person Lainesius    schedule 31.08.2017
comment
Если вы просто попытаетесь решить эту проблему, подход Класа Линдбака будет правильным и, вероятно, лучшим, что я могу придумать. Единственный недостаток, как вы видели, заключается в том, что ошибка на последних ветвях дерева может заставить вас вернуться к началу. Вот почему я говорю, что это может быть очень долго. Но если вам удастся мудро выбрать слово, которое вы пробуете, у вас будет меньше ошибок.   -  person Mathieu    schedule 31.08.2017


Ответы (1)


Итак, как правильно это сделать?

Не знаю, оптимально ли это, но я бы использовал принципы Floodfill.

Структуры данных:

Слова кроссворда и их пересечения. Отсортируйте их по количеству слов в словаре для соответствующей длины слова. Скорее всего, это будет означать, что вы начнете с одного из самых длинных слов.

Словарь доступен по длине слова.

Если словарь большой, было бы полезно иметь возможность быстро находить слова определенной длины с определенной n:й буквой, где n соответствует позиции пересечения.

Обратите внимание, что для каждого слова кроссворда любые два слова, которые подходят и имеют одинаковые буквы во всех пересечениях, эквивалентны. Таким образом, можно выбрать подмножество из словаря для каждого слова кроссворда. Подмножество — это множество классов эквивалентности. Таким образом, для каждого слова кроссворда вы можете создать подмножество словаря, содержащее не более [количество букв в алфавите] в степени [количество пересечений]. Это подмножество будет составлять классы эквивалентности, которые могут соответствовать конкретному слову кроссворда.

Алгоритм:

  • Возьмите первое/следующее неразгаданное слово кроссворда. Назначьте ему первое/следующее слово, которое подходит.

  • Возьмите первый/следующий перекресток. Назначьте другому слову кроссворда первое подходящее слово.

  • Если больше нет перекрестков, чтобы следовать дальше, вернитесь к перекрестку, с которого вы пришли, и продолжайте движение до следующего перекрестка.
  • Если в словаре нет подходящего слова, пройдите назад на одно пересечение и найдите следующее подходящее слово.
person Klas Lindbäck    schedule 31.08.2017
comment
Было бы очень долго, если бы словарь был слишком большим. - person Mathieu; 31.08.2017
comment
@ Матье Было бы так. Но обратите внимание, что словарь можно сжать до классов эквивалентности. Если вам нужно слово из n буквы с одним пересечением, то есть только 26 классов эквивалентности, по одному для каждой возможной буквы в пересечении. Я добавлю это к решению! - person Klas Lindbäck; 31.08.2017
comment
Проблема, которую я вижу в этом методе, заключается в том, что его отправная точка настолько уязвима. Например, если исходное слово имеет 3 отдельные ветки, и вы заполняете их одну за другой, когда вы дойдете до третьей, если нет подходящего слова, соответствующего критериям, вам придется изменить это исходное слово и повторить все заново. Это фактически заставило меня попробовать упомянутое рекурсивное исследование — вся его идея заключалась в том, чтобы попытаться сделать прямую линию как можно дольше, поэтому, если бы произошла какая-либо ошибка в сопоставлении, вы могли бы ее исправить сразу — это не повлияло бы на предыдущие совпадения. - person Lainesius; 31.08.2017
comment
@Lainesius Когда ваш подход терпит неудачу, вам, возможно, придется долго отступать. Если вы сделали выбор, который в конечном итоге терпит неудачу, то вы хотите потерпеть неудачу как можно быстрее. Таким образом, вы должны начать с кроссворда, у которого есть много способов провалиться и несколько слов, которые совпадают. - person Klas Lindbäck; 31.08.2017