Я придумал решение, которое, вероятно, не самое эффективное, но работает достаточно хорошо. В принципе:
- Отсортируйте все слова по длине в порядке убывания.
- Возьмите первое слово и поместите его на доску.
- Возьми следующее слово.
- Просмотрите все слова, которые уже есть на доске, и посмотрите, есть ли какие-либо возможные пересечения (любые общие буквы) с этим словом.
- Если есть возможное место для этого слова, прокрутите все слова, которые есть на доске, и проверьте, не мешает ли новое слово.
- Если это слово не сломает доску, поместите его туда и переходите к шагу 3, в противном случае продолжайте поиск места (шаг 4).
- Продолжайте этот цикл, пока все слова не будут размещены или не могут быть размещены.
Это рабочий, но зачастую довольно плохой кроссворд. Я внес ряд изменений в основной рецепт, приведенный выше, чтобы добиться лучшего результата.
- В конце создания кроссворда дайте ему оценку в зависимости от того, сколько слов было размещено (чем больше, тем лучше), насколько велика доска (чем меньше, тем лучше), а также соотношение между высотой и шириной (чем ближе к 1 лучше). Сгенерируйте несколько кроссвордов, затем сравните их результаты и выберите лучший.
- Вместо того, чтобы запускать произвольное количество итераций, я решил создать как можно больше кроссвордов за произвольный промежуток времени. Если у вас есть только небольшой список слов, вы получите десятки возможных кроссвордов за 5 секунд. Кроссворд побольше можно выбрать только из 5-6 возможных.
- При размещении нового слова вместо того, чтобы размещать его сразу после нахождения приемлемого местоположения, присвойте этому местоположению слова оценку в зависимости от того, насколько оно увеличивает размер сетки и сколько пересечений имеется (в идеале вы хотите, чтобы каждое слово было скрещено еще 2-3 слова). Следите за всеми позициями и их счетами, а затем выбирайте лучшую.
Я недавно написал свой собственный на Python. Вы можете найти его здесь: http://bryanhelmig.com/python-crossword-puzzle-generator/ . Он создает не сложные кроссворды в стиле NYT, а стиль кроссвордов, который вы можете найти в детской книжке-головоломке.
В отличие от нескольких алгоритмов, которые я обнаружил там, которые реализовали случайный метод грубой силы для размещения слов, как предлагали некоторые, я попытался реализовать немного более умный подход грубой силы при размещении слов. Вот мой процесс:
В конце концов, у вас есть приличный кроссворд или головоломка для поиска слов, поскольку они примерно одинаковы. Как правило, он работает довольно хорошо, но дайте мне знать, если у вас есть предложения по улучшению. Более крупные сети работают экспоненциально медленнее; линейно большие списки слов. Списки слов большего размера также имеют гораздо больше шансов на лучшее размещение слов.
источник
array.sort(key=f)
является стабильным, что означает (например), что простая сортировка алфавитного списка слов по длине сохранит все 8-буквенные слова в алфавитном порядке.На самом деле я написал программу генерации кроссвордов около десяти лет назад (она была загадочной, но те же правила применялись и для обычных кроссвордов).
В нем был список слов (и связанных с ними подсказок), хранящийся в файле, отсортированный по убыванию использования на текущий момент (так, чтобы наименее используемые слова находились в верхней части файла). Шаблон, в основном битовая маска, представляющая черные и свободные квадраты, был выбран случайным образом из пула, предоставленного клиентом.
Затем для каждого неполного слова в головоломке (в основном найдите первый пустой квадрат и посмотрите, является ли пустым тот, который справа (поперечное слово) или тот, что внизу (нижнее слово)), был выполнен поиск файл ищет первое подходящее слово с учетом букв, уже присутствующих в этом слове. Если подходящего слова не было, вы просто отмечали все слово как неполное и переходили к следующему.
В конце будет несколько незавершенных слов, которые компилятор должен будет заполнить (и при желании добавить слово и подсказку к файлу). Если они не могли придумать какие-либо идеи, они могли вручную отредактировать кроссворд, чтобы изменить ограничения, или просто попросить его полностью пересоздать.
Как только файл слов / подсказок достигал определенного размера (а он добавлял 50-100 подсказок в день для этого клиента), редко возникало более двух или трех исправлений вручную, которые приходилось делать для каждого кроссворда. ,
источник
Этот алгоритм создает 50 сложных кроссвордов со стрелками 6x9 за 60 секунд. Он использует базу данных слов (со словом + подсказками) и базу данных плат (с предварительно настроенными досками).
Большая база данных слов значительно сокращает время генерации, и некоторые доски сложнее заполнять! Для правильного заполнения больших досок требуется больше времени!
Пример:
Предварительно настроенная плата 6x9:
(# означает один наконечник в одной ячейке,% означает два наконечника в одной ячейке, стрелки не показаны)
Сгенерированная доска 6x9:
Советы [строка, столбец]:
источник
Хотя это более старый вопрос, попытаюсь ответить на основе аналогичной работы, которую я проделал.
Существует много подходов к решению проблем ограничений (которые обычно относятся к классу сложности NPC).
Это связано с комбинаторной оптимизацией и программированием в ограничениях. В этом случае ограничениями являются геометрия сетки и требование уникальности слов и т. Д.
Подходы рандомизации / отжига также могут работать (хотя и при правильных настройках).
Эффективная простота может быть высшей мудростью!
Требовалось наличие более или менее полного компилятора кроссвордов и (визуального WYSIWYG) построителя.
Не говоря уже о построении WYSIWYG, схема компилятора была такой:
Загрузить доступные словари (отсортированные по длине слова, например, 2,3, .., 20)
Найдите слоты слов (то есть слова сетки) в созданной пользователем сетке (например, слово в точках x, y с длиной L, по горизонтали или вертикали) (сложность O (N))
Вычислить точки пересечения слов сетки (которые необходимо заполнить) (сложность O (N ^ 2))
Вычислить пересечения слов в списках слов с различными буквами используемого алфавита (это позволяет искать совпадающие слова, используя шаблон, например, тезис Сика Камбона, используемый cwc ) (сложность O (WL * AL))
Шаги .3 и .4 позволяют выполнить эту задачу:
а. Пересечения слов сетки сами с собой позволяют создать «шаблон» для поиска совпадений в соответствующем списке слов доступных слов для этого слова сетки (с использованием букв других пересекающихся с этим словом слов, которые уже заполнены в определенное время). шаг алгоритма)
б. Пересечения слов в списке слов с алфавитом позволяют находить подходящие (кандидаты) слова, которые соответствуют заданному «шаблону» (например, «A» на 1-м месте и «B» на 3-м месте и т. Д.)
Итак, с реализованными этими структурами данных алгоритм был примерно таким:
ПРИМЕЧАНИЕ: если сетка и база слов постоянны, предыдущие шаги можно выполнить только один раз.
Первым шагом алгоритма является случайный выбор пустого слота слов (слово сетки) и заполнение его словом-кандидатом из связанного с ним списка слов (рандомизация позволяет производить различные решения при последовательном выполнении алгоритма) (сложность O (1) или O ( N))
Для каждого еще пустого слота слов (которые имеют пересечения с уже заполненными слотами слов) вычислите коэффициент ограничения (он может варьироваться, sth simple - количество доступных решений на этом шаге) и отсортируйте пустые слоты слов по этому соотношению (сложность O (NlogN ) или O (N))
Прокрутите пустые слоты слов, вычисленные на предыдущем шаге, и для каждого попробуйте несколько решений cancdidate (убедитесь, что «согласованность дуги сохраняется», т.е. сетка имеет решение после этого шага, если это слово используется) и отсортируйте их в соответствии с максимальная доступность для следующего шага (т.е. следующий шаг имеет максимально возможные решения, если это слово используется в то время в этом месте и т. д.) (сложность O (N * MaxCandidatesUsed))
Заполните это слово (отметьте его как заполненное и переходите к шагу 2)
Если не найдено ни одного слова, удовлетворяющего критериям шага .3, попробуйте вернуться к другому варианту решения некоторого предыдущего шага (здесь критерии могут отличаться) (сложность O (N))
Если обратный путь найден, используйте альтернативу и при необходимости сбросьте все уже заполненные слова, которые могут нуждаться в сбросе (снова пометьте их как незаполненные) (сложность O (N))
Если обратный путь не найден, решение не может быть найдено (по крайней мере, с этой конфигурацией, начальным начальным значением и т. Д.)
В противном случае, когда все словари заполнены, у вас есть одно решение
Этот алгоритм выполняет случайное последовательное обход дерева решений проблемы. Если в какой-то момент возникает тупик, он возвращается к предыдущему узлу и следует по другому маршруту. Пока не будет найдено решение или количество кандидатов для различных узлов не будет исчерпано.
Часть согласованности гарантирует, что найденное решение действительно является решением, а случайная часть позволяет создавать разные решения в разных исполнениях, а также в среднем иметь лучшую производительность.
PS. все это (и другие) было реализовано на чистом JavaScript (с параллельной обработкой и WYSIWYG).
PS2. Алгоритм можно легко распараллелить, чтобы получить более одного (разных) решений одновременно.
Надеюсь это поможет
источник
Почему бы просто не использовать для начала случайный вероятностный подход. Начните со слова, а затем несколько раз выберите случайное слово и попытайтесь вписать его в текущее состояние головоломки, не нарушая ограничений на размер и т. Д. Если вы потерпите неудачу, просто начните все сначала.
Вы будете удивлены, как часто подобный подход Монте-Карло работает.
источник
Вот код JavaScript, основанный на ответе никфа и коде Python Брайана. Просто разместите его на случай, если кому-то это понадобится в js.
источник
Я бы получил два числа: длину и оценку скрэббла. Предположим, что низкий балл по Scrabble означает, что присоединиться к нему легче (низкие баллы = много общих букв). Отсортируйте список по убыванию длины и возрастанию баллов Scrabble.
Далее просто пройдите вниз по списку. Если слово не пересекается с существующим словом (проверьте каждое слово по его длине и баллу Scrabble соответственно), поместите его в очередь и проверьте следующее слово.
Промойте и повторите, и это должен создать кроссворд.
Конечно, я почти уверен, что это О (н!), И это не гарантирует, что вы решите кроссворд за вас, но, возможно, кто-то сможет его улучшить.
источник
Я думал об этой проблеме. Я считаю, что для создания действительно сложного кроссворда нельзя надеяться, что вашего ограниченного списка слов будет достаточно. Следовательно, вы можете взять словарь и поместить его в структуру данных «trie». Это позволит вам легко находить слова, заполняющие оставшиеся пробелы. В некотором роде довольно эффективно реализовать обход, который, скажем, дает вам все слова формы «c? T».
Итак, мое общее мнение таково: создайте своего рода подход относительно грубой силы, как некоторые описывают здесь, чтобы создать крест с низкой плотностью, и заполните пробелы словарными словами.
Если кто-то еще воспользовался этим подходом, дайте мне знать.
источник
Я играл с двигателем генератора кроссвордов, и я нашел это самым важным:
0.
!/usr/bin/python
а.
allwords.sort(key=len, reverse=True)
б. создайте какой-нибудь элемент / объект, например курсор, который будет перемещаться по матрице для облегчения ориентации, если вы не хотите повторять случайный выбор позже.
первый, возьмите первую пару и разместите их поперек и вниз от 0,0; сохранить первый из них как «лидер» нашего текущего кроссворда.
перемещать курсор по диагонали по порядку или случайным образом с большей вероятностью диагонали в следующую пустую ячейку
перебирать слова вроде и использовать длину свободного пространства для определения максимальной длины слова:
temp=[] for w_size in range( len( w_space ), 2, -1 ) : # t for w in [ word for word in allwords if len(word) == w_size ] : # if w not in temp and putTheWord( w, w_space ) : # temp.append( w )
чтобы сравнить слово со свободным пространством, я использовал, например:
после каждого удачно употребленного слова меняйте направление. Цикл, пока все ячейки заполнены ИЛИ у вас закончились слова ИЛИ на лимит итераций, тогда:
# CHANGE ALL WORDS LIST inexOf1stWord = allwords.index( leading_w ) allwords = allwords[:inexOf1stWord+1][:] + allwords[inexOf1stWord+1:][:]
... и повторить заново новый кроссворд.
Составьте систему оценок по легкости заполнения и некоторым оценочным расчетам. Поставьте оценку за текущий кроссворд и сузьте последующий выбор, добавив его в список созданных кроссвордов, если оценка соответствует вашей системе подсчета очков.
После первого сеанса итерации повторите итерацию из списка составленных кроссвордов, чтобы завершить задание.
Используя больше параметров, скорость можно значительно улучшить.
источник
Я бы получил указатель каждой буквы, используемой в каждом слове, чтобы знать возможные кресты. Затем я выбирал самое большое слово и использовал его как основу. Выберите следующий большой и пересеките его. Промыть и повторить. Вероятно, это проблема NP.
Еще одна идея - создать генетический алгоритм, в котором показатель силы - это количество слов, которые вы можете поместить в сетку.
Самая сложная часть, которую я нахожу, - это когда знать, что определенный список невозможно перечеркнуть.
источник
Он появляется как проект в курсе AI CS50 из Гарварда. Идея состоит в том, чтобы сформулировать проблему генерации кроссворда как проблему удовлетворения ограничений и решить ее с помощью обратного отслеживания с различными эвристиками, чтобы уменьшить пространство поиска.
Для начала нам понадобится пара входных файлов:
`
`
Входной словарь (список слов / словарь), из которого будут выбраны слова-кандидаты (как показано ниже).
a abandon ability able abortion about above abroad absence absolute absolutely ...
Теперь CSP определен и должен быть решен следующим образом:
Ниже показан результат, который был получен с использованием реализации алгоритма решения CSP:
`
Следующая анимация показывает шаги возврата:
Вот еще одно слово со списком слов на языке бангла (бенгали):
источник
Я написал решение этой проблемы на JavaScript / jQuery:
Пример демонстрации: http://www.earthfluent.com/crossword-puzzle-demo.html
Исходный код: https://github.com/HoldOffHunger/jquery-crossword-puzzle-generator
Цель алгоритма, который я использовал:
Опишу используемый мной алгоритм:
Сгруппируйте слова вместе по тем, которые имеют общую букву.
Из этих групп постройте наборы новой структуры данных («блоки слов»), которые представляют собой первичное слово (которое проходит через все другие слова), а затем другие слова (которые проходят через первичное слово).
Начните разгадывать кроссворд с самого первого из этих блоков слов в самом верхнем левом положении кроссворда.
Для остальных блоков слов, начиная с самого правого нижнего положения кроссворда, двигайтесь вверх и влево, пока не останется свободных мест для заполнения. Если вверху больше пустых столбцов, чем влево, двигайтесь вверх и наоборот.
источник
var crosswords = generateCrosswordBlockSources(puzzlewords);
. Просто запишите это значение в консоль. Не забывайте, что в игре есть «чит-режим», где вы можете просто нажать «Показать ответ», чтобы сразу получить значение.