I'm trying to make an algorithm to fill a list of given words in a square matrix where letters amount is equal to matrix size.
The trick here is that you should be able to connect each word (each letter with the letter after him in the same word) and at the end of connection the board should be cleared. (each word is independent - doesn't connect with other words).
You can connect a word: if its letters are neighbors - (neighbor can be: left, right, top, bottom, top-left, top-right, bottom-left, bottom-right). you should connect letters by order and can't skip letters. (like drawing a line on paper without removing the pencil) and you cant go above other letters from another words while connecting a word.
When a word is connected it's removed from the board - and every letter above its letters will fall down to take it's place (like: letters can't fly). each will fall above the other and not at the same position in the matrix.
Words doesn't have to be all connected by the first look at the board - so: they should be connectable while other words are connected - then its letters will be neighbors.
This is an example of how the board should look like:
The Board in the image was generated by the algorithm I wrote, it generates a 5X5 board within 1-10 seconds witch it's too much for a computer. the problem I have is that a 7X7 and larger boards will take "infinite" time to be generated, yet I couldn't generate any 7X7 board.
Another note: a board should not follow a pattern that repeats on all boards, and its preferred not to follow patterns.
I have searched for days on the internet and couldn't find articles solving such problem. My CPU usage when launching the code is about 1.1%. I don't know why it takes a lot of time.
I'm using a recursive algorithm, and this is the main function that controls the generations:
public void Build()
{
// Sort words from The longest to the shortest
sortWords();
//convert list of words to string
string words = ListToString(this.words);
// Get The Result of the generation function.
bool result = Generate(words, null);
}
private Random random = new Random();
private bool Generate(string words, Word word)
{
// If [words = null], Then The function failed to generate a board from no words.
if (words == null)
return false;
// If got to the end of the words, Then succedd to fill all words in the board
if (words.Length == 0)
return true;
// If Got [" "] blank letter, Then should switch to the next word.
if (words[0].ToString() == " ")
{
board.changedWord(); // Delegate: Update UI
return Generate(words.Substring(1, words.Length - 1), null);
}
// If [word = null], Then we are creating a new word
if (word == null)
word = new Word(board);
// Check If there is a group of letters that can't connect with other letters
// and they cann't contain any word in them.
if (board.isLocked(minInString(words)))
return false;
// Store all available legal neighbours to the previus added letter
List<Location> neighbours = new List<Location>();
if (word.Length == 0) { // This is a new word -> Any Cell would be legal
neighbours = board.FreeLocations();
}
else { // This word is in progress. Neighbours rules should be applied
neighbours = board.Neighbours(word.Letters.Last().Location);
}
if (neighbours.Count == 0) { // If found no neighbours, Then cant continue with the current word
return false;
}
int index = 0; // Shoiuld hold letter index in word - has nothing to do right now. initail value [0].
while (neighbours.Count > 0)
{ // Try each one of the suggested neighbours
// Get a random neighbour from available legal neighbours
int randLocationIndex = random.Next(neighbours.Count);
Location location = neighbours[randLocationIndex];
// If word wasn't added to the words, add it!
if (!board.Words.Contains(word))
board.Words.Add(word);
// Add the current letter to the related word in board
board.Add(new Letter(word, location, words[0].ToString(), index), word);
if (!word.isValid()) {
// Check if current word can be connected,
//Its own letters doesn't make any problem to each other.
board.Remove(word.Letter(word.Length - 1));
neighbours.RemoveAt(randLocationIndex);
continue;
}
if (!board.Solved()) {
// Check if the board is solvable [Gravity cases]
// -> Check each word that devides the connection between current word, that its connectable
board.Remove(word.Letter(word.Length - 1));
neighbours.RemoveAt(randLocationIndex);
continue;
}
// Try the letters after me.
bool result = Generate(words.Substring(1, words.Length - 1), word);
// If all words after this, succeded, then me and sons succeded, return true.
if (result == true)
return true;
else { // Remove added point from word's path, Remove it from available neighbours
board.Remove(word.Letter(word.Length - 1));
neighbours.RemoveAt(randLocationIndex);
}
}
// If Current Word has added no letters to board: then remove it from board
// we dont need any empty useless word in the board.
if (word.Length == 0) {
//board.CancelWord(); Delegate: Update Board UI
board.Words.Remove(word);
}
// Tryed all sugested neighbours for current letter, all of them has failed
// retuen false - Thats a fail :(
return false;
}
I can read / write c#, C++, C, Java, Swift, and Objective-C.