public void GenerateCrossWords()
{
List<CrossedWord> fixedwordsList = new List<CrossedWord>();
string[] words = System.IO.File.ReadAllLines("crossword.txt");
foreach(string line in words)
{
string[] wordAndClue = line.Split(\'/\');
fixedwordsList.Add(new CrossedWord(wordAndClue[0].Trim() , wordAndClue[1]));
}
// The very final crosswords
List<CrossedWord> CrossWordsToKeep = new List<CrossedWord>();
float crosswordLength = float.MaxValue;
int WordsPlaced = 0;
int crosswordMinX = 0, crosswordMinY = 0;
// Looping to choose the best grid (looping arbitrary "the number of words" time)
for(int gen = 0 ; gen < fixedwordsList.Count ; gen++)
{
// Not Touching the initial List
List <CrossedWord> allWords = new List<CrossedWord>(fixedwordsList);
if(gen % 2 == 1)
{
// Shuffling the words half the tries because sometimes not starting with the longer word can be a good option too
for(int j = allWords.Count - 1 ; j > 0; j--)
{
int r = UnityEngine.Random.Range(0, j+1);
CrossedWord tmp = allWords[r];
allWords[r] = allWords[j];
allWords[j] = tmp;
}
}
else
{
allWords.Sort();
allWords.Reverse();
}
// The final crosswords for this loop only
List<CrossedWord> finalWords = new List<CrossedWord>();
// Adding the first word we found
finalWords.Add(new CrossedWord(allWords[0]));
// Removing this word from the list
allWords.RemoveAt(0);
// Initial size knowing the fact that the first word is Horizontal
int minX = 0, maxX = finalWords[0].Size - 1, minY = 0, maxY = 0;
// Loop on all the words we want in the crossword
int maxLoop = Mathf.FloorToInt(allWords.Count*allWords.Count );
int z = 0;
int i = 0;
for(; 0 != allWords.Count && z < maxLoop ;z++)
{
// The current word we want to place
CrossedWord currentWordToPlace = new CrossedWord(allWords[i]);
// Will tell us if we succeed placing it
bool bIsPlaced = false;
// Will always be the best position we find, initialise here with arbitrary values
Tile BestStartingPosition = new Tile(0,0);
CrossedWord.Direction BestDirection = CrossedWord.Direction.Horizontal;
// Will be a score to tell us which position is "conceptually" the best
float score = float.MaxValue;
// Loop on all the existing words in the crossword
for(int j = 0; j< finalWords.Count; j++)
{
// The current already placed word that we will used to try to place the new word
CrossedWord currentWordPlaced = finalWords[j];
// If we must placed the new one according to the existing one, the new one will be the other direction
currentWordToPlace.WordDirection = currentWordPlaced.WordDirection == CrossedWord.Direction.Horizontal ? CrossedWord.Direction.Vertical : CrossedWord.Direction.Horizontal;
// An array wich gave us for each letter (e.g. array[0] for the first letter) the tiles on which the current placed word has the same letter
List<Tile>[] intersectionForEachLetter = currentWordPlaced.SimilarLetterTiles(currentWordToPlace);
// Loop on all the letters
for(int k = 0; k < intersectionForEachLetter.Length;k++)
{
// Looking for each given tile for one letter
for(int l = 0; l < intersectionForEachLetter[k].Count; l++)
{
// Getting the tile
Tile currentCommonTile = intersectionForEachLetter[k][l];
// Given the direction of the placed word and the intersection tile we calculate the new word potential starting position
if( currentWordPlaced.WordDirection == CrossedWord.Direction.Horizontal )
{
currentWordToPlace.StartingPosition = new Tile(currentCommonTile.X, currentCommonTile.Y - k);
}
else
{
currentWordToPlace.StartingPosition = new Tile(currentCommonTile.X -k , currentCommonTile.Y);
}
// Loop on all the words in the crossword to check if the place we want the new word isn\'t in conflict with the existings words
// the int to tell us how many correct intersection we have
int iCanBePlaced = 0;
// the boolean to tell us a conflict
bool bCanBePlaced = true;
for(int m = 0; m < finalWords.Count && bCanBePlaced; m++)
{
// ca = 0 means no conflict, -1 means a conflict, 1 means a good intersection
int ca = finalWords[m].CanAccept(currentWordToPlace);
if(ca > 0)
iCanBePlaced += ca;
if(ca == -1)
bCanBePlaced = false;
}
// The place is OK and have minimum one good intersection
if(bCanBePlaced && iCanBePlaced > 0)
{
// Calculate a score to find the best place
// how much intersection but the opposite value
int crossedNumber = (0 - iCanBePlaced);
// a conceptual score that should be the less the better
float tmpScore = UnityEngine.Random.Range(0,10) + crossedNumber *100;
// if this score si better than a previous one we keep this position and tell that we succeed placing at least one time this word
if( tmpScore < score)
{
bIsPlaced = true;
// Updating the new best score
score = tmpScore;
BestStartingPosition = currentWordToPlace.StartingPosition;
BestDirection = currentWordToPlace.WordDirection;
}
}
}
}
}
// We have at least one position to place this new word
if(bIsPlaced)
{
// getting this saved position
currentWordToPlace.StartingPosition = BestStartingPosition;
currentWordToPlace.WordDirection = BestDirection;
// adding this word to the crossword
finalWords.Add(currentWordToPlace);
// Shuffling the crossword array to have more random factor on the grid creation (doesn\'t really matters but linear operation so it\'s ok)
for(int j = finalWords.Count - 1 ; j > 0; j--)
{
int r = UnityEngine.Random.Range(0, j+1);
CrossedWord tmp = finalWords[r];
finalWords[r] = finalWords[j];
finalWords[j] = tmp;
}
// Updating the grid Rectangle if necessary
minX = Mathf.Min(minX, currentWordToPlace.StartingPosition.X);
minY = Mathf.Min(minY, currentWordToPlace.StartingPosition.Y);
maxX = Mathf.Max(maxX, currentWordToPlace.WordDirection == CrossedWord.Direction.Horizontal ? currentWordToPlace.StartingPosition.X + currentWordToPlace.Size - 1 : currentWordToPlace.StartingPosition.X);
maxY = Mathf.Max(maxY, currentWordToPlace.WordDirection == CrossedWord.Direction.Vertical ? currentWordToPlace.StartingPosition.Y + currentWordToPlace.Size - 1 : currentWordToPlace.StartingPosition.Y);
allWords.RemoveAt(i);
if(allWords.Count > 0)
i = i % allWords.Count;
}
else
{
i = (i+1) % allWords.Count;
}
}
// Final new length of the grid
float newLength = Mathf.Sqrt((maxX - minX)*(maxX - minX) + (maxY - minY)*(maxY - minY));
// Final new number of word we succeed to put on the grid
int currentWordsPlaced = finalWords.Count;
// if it\'s a better grid (smaller and more words). Indeed, we allow a bigger crossword proportionally to how much more words it contains
if(newLength - (currentWordsPlaced - WordsPlaced)*4 < crosswordLength && WordsPlaced < currentWordsPlaced)
{
// Keeping this grid in memory
CrossWordsToKeep = finalWords;
// Updating best grid values
crosswordLength = newLength;
WordsPlaced = currentWordsPlaced;
crosswordMinX = minX;
crosswordMinY = minY;
}
}
Debug.Log(CrossWordsToKeep.Count+"/"+fixedwordsList.Count+" size: "+crosswordLength);
for(int r = 0; r < CrossWordsToKeep.Count; r++)
{
CrossWordsToKeep[r].StartingPosition.X -= crosswordMinX;
CrossWordsToKeep[r].StartingPosition.Y = -CrossWordsToKeep[r].StartingPosition.Y + crosswordMinY;
}
CrToShow = CrossWordsToKeep;
}