I can not think of an algorithm. We have a list of words, no matter how long. It is necessary to build a field for a crossword puzzle with the participation of these words. This task is in the book "Programming Etudes".

At the moment, my reasoning is:

  1. sort words by number of letters

  2. Represent this field as a two-dimensional char array

  3. put the longest word in the center of the field and start working on it

  4. words should be read strictly left to right and top to bottom

How exactly to insert the words, so that one word could not just intersect with another, but with several?

UPD

I looked at crosswords and realized that the number of vertical and horizontal words is always proportional, plus / minus one or two. So, it is necessary to implement two functions - one for horizontal, the other for vertical. And call them one after another through recursion until all the words are used.

UPD (I apologize for the quality of the image, I drew in the gimp quickly)

enter image description here

It is necessary to introduce such a thing as a red zone, so that there is no "sticking together" of words.

UPD

I found the article http://habrahabr.ru/post/166471/ , reading the source code gave nothing.

UPD

Another clue found. Book: Mozgovoy M.V. "C ++ Master Class 85 non-trivial projects, solutions and tasks." There is a way to implement the construction of a crossword puzzle, only it is based on the fact that we already have a certain grid and a sufficiently large list of words, which will not be used all.

2 answers 2

I have some idea of ​​the algorithm, but most likely it is not the most optimal.

  1. We sort the base of words so that the longest are located at the beginning;
  2. We create a two-dimensional character array of N x N dimension, where N can be taken 1.5 - 2 times more than the longest word from the list;
  3. Along the horizon, we put the longest word in the middle of the array;
  4. Choose the next word in length, in which at least 1 letter coincides with the first, and place it in the right place vertically;
  5. Next, we implement the cycle until we select all the words from our database, or the possible positions for adding words are completed:

    • Alternately, choose whether we add a new word vertically, or horizontally;
    • Passing in rows or columns of an array, through 1 (so we ensure no words sticking together, if we add horizontally, move in rows, otherwise - in columns), look for drains / columns with single characters framed by empty cells, save these the characters and the size of the spaces between them in an element of a certain list, for example, from a combination of lines:

      .гиппопотам. . . . .пароход. . .комод. 

      It would be possible to make the following list of elements: г-3-п-1-к , п-3-р-1-м , о-3-х-1-д , о-3-д , etc. (How exactly to form such elements of the list so that it would be convenient to analyze them later? A separate question, you can form a regular expression, or it may even be better not to transfer the letters themselves from the array, but to add to the list a structure like

       { направление(гориз./верт.); количество букв; номер строки начала; номер столбца начала; } 

      And match letters from an array according to a given position in this structure) with words.
      The list is formed by descending number of letters in the formed elements.

    • We go through the base of words, choosing alternately starting from the longest, and matching them with the elements in the list until we find the word, the letters and their position in which they coincide with the element from the list we formed at the previous step.
    • We place the found word in the required position in the array, if its size allows it and it does not overlap any other word in the same line (otherwise, we continue to pass through the base), exclude it from the base, return to the beginning of the cycle.
    • If there are no words left, or not a single match was found (even with 1 letter), either with a vertical addition or with a horizontal one, then everything we could have built, we exit the cycle.

UPD:
An example for adding a word intersecting with two vertically:

 ......... ..г...ф.. ..р...а.. ..а...в.. ..ф...н.. 

Moving through the lines through one, we can compose the list elements p-3-a, f-3-n for these two words, if we use the above structure as a list element, then for line number 3 we get:
direction - horizontal
number of letters - 2
Start line number - 2 (if we take into account the usual countdown in the array with 0)
start column number - 2

Passing through the database, we found that under the first element of the list fits the word "tube", we know the offset of the first matching letter in the array - (line 2, column 2), which means we can calculate the position of the first letter of the word we found, and put it in array (row 2, column 1).

  • Again, it is not clear how to make the intersection of say with two vertical words horizontally. - ParanoidPanda
  • Why is it incomprehensible? It is the same way to move through one line by line, adding various options such as “the word contains the letter 'е' and 3 letters from it, the letter 'd'” into the list elements, then in the base of words find the one that matches one of the options in the list . Updated the answer. - margosh

Read these articles:

  1. " The algorithm for the formation of crosswords ",
  2. " Building crosswords using the Wolfram Language (Mathematica) ."

In short, making crosswords is not a trivial task requiring a large word base. At the same time there are no guarantees that all the words will be put in the grid.

Added . The red zone is easily implemented by adding spaces to the beginning and end of each word.

  • The second article fits my goals. Since I do not have the need to do a complex block crossword. By the way, I found the answer to another question. Make a "red zone" so that the words do not stand straight in one line, and between them was a separator. - ParanoidPanda