public CrossedWord(CrossedWord previous) { this.Word = previous.Word; this.Clue = previous.Clue; this.WordDirection = previous.WordDirection; this.StartingPosition = new Tile(previous.StartingPosition.X, previous.StartingPosition.Y); }
// An array wich gave us for each letter of c (e.g. array[0] for the first letter) the tiles on which the current instance has the same letter public List <Tile>[] SimilarLetterTiles(CrossedWord c) { List <Tile>[] tilesForEachLetter = new List <Tile> [c.Size]; for (int i = 0; i < c.Size; i++) { List <Tile> TilesForCurrentLetter = new List <Tile>(); for (int j = 0; j < this.Size; j++) { if (c.Word[i] == this.Word[j]) { TilesForCurrentLetter.Add(this.TileAtWordPosition(j)); } } tilesForEachLetter[i] = TilesForCurrentLetter; } return(tilesForEachLetter); }
public int CompareTo(object obj) { if (obj == null) { return(1); } CrossedWord otherCrossWord = obj as CrossedWord; if (otherCrossWord != null) { return(this.Size.CompareTo(otherCrossWord.Size)); } else { throw new ArgumentException("Object is not a CrossedWord"); } }
// Tells if instance can accept the crossword (no superposition...) public int CanAccept(CrossedWord c) { // BOTH HORIZONTAL if (this.WordDirection == Direction.Horizontal && c.WordDirection == Direction.Horizontal) { // Having more than 1 line between them if (Math.Abs(c.StartingPosition.Y - this.StartingPosition.Y) > 1) { return(0); } } // Having less than 1 line between them but not touching nor supersposing if (Math.Abs(c.StartingPosition.Y - this.StartingPosition.Y) <= 1 && (this.StartingPosition.X > c.StartingPosition.X + c.Size || this.StartingPosition.X + this.Size < c.StartingPosition.X)) { return(2); } // BOTH VERTICAL if (this.WordDirection == Direction.Vertical && c.WordDirection == Direction.Vertical) { // Having more than 1 row between them if (Math.Abs(c.StartingPosition.X - this.StartingPosition.X) > 1) { return(0); } } // Having less than 1 row between them but not touching nor supersposing if (Math.Abs(c.StartingPosition.X - this.StartingPosition.X) <= 1 && (this.StartingPosition.Y > c.StartingPosition.Y + c.Size || this.StartingPosition.Y + this.Size < c.StartingPosition.Y)) { return(2); } // INSTANCE HORIZONTAL AND OTHER VERTICAL if (this.WordDirection == Direction.Horizontal && c.WordDirection == Direction.Vertical) { Tile potentialIntersection = new Tile(c.StartingPosition.X, this.StartingPosition.Y); char instanceChar = this.LetterOnTile(potentialIntersection); char otherChar = c.LetterOnTile(potentialIntersection); // IF CROSSING ON THE SAME LETTER --> TRUE if (this.isWordOverTile(potentialIntersection) && c.isWordOverTile(potentialIntersection) && instanceChar == otherChar) { if (instanceChar != '0') { return(1); } else { return(0); } } else if (instanceChar == '0' && (potentialIntersection.X < this.StartingPosition.X - 1 || potentialIntersection.X > this.StartingPosition.X + this.Size)) { return(0); } } // INSTANCE VERTICAL AND OTHER HORIZONTAL if (this.WordDirection == Direction.Vertical && c.WordDirection == Direction.Horizontal) { Tile potentialIntersection = new Tile(this.StartingPosition.X, c.StartingPosition.Y); char instanceChar = this.LetterOnTile(potentialIntersection); char otherChar = c.LetterOnTile(potentialIntersection); // IF CROSSING ON THE SAME LETTER --> TRUE if (this.isWordOverTile(potentialIntersection) && c.isWordOverTile(potentialIntersection) && instanceChar == otherChar) { if (instanceChar != '0') { return(1); } else { return(0); } } else if (instanceChar == '0' && (potentialIntersection.Y < this.StartingPosition.Y - 1 || potentialIntersection.Y > this.StartingPosition.Y + this.Size)) { return(0); } } return(-1); }
public void GenerateCrossWords() { List <CrossedWord> fixedwordsList = new List <CrossedWord>(); //string[] words = System.IO.File.ReadAllLines("crossword.txt"); //foreach (string line in words) //{ // fixedwordsList.Add(new CrossedWord(line.Trim(), "")); //} //int lineno = New.instace.RemainingList[New.NumberOfPragrency]; print("---->>" + New.instace.RemainingList[New.NumberOfPragrency]); string pragnencyword = New.instace.PrgencyList[New.instace.RemainingList[New.NumberOfPragrency]].Trim(); char[] myChars = pragnencyword.ToCharArray(); string char1 = myChars[UnityEngine.Random.Range(0, pragnencyword.Length - 1)].ToString(); string char2 = myChars[UnityEngine.Random.Range(0, pragnencyword.Length - 1)].ToString(); fixedwordsList.Add(new CrossedWord(pragnencyword, "")); New.NumberOfPragrency++; for (int i = 0; i < New.instace.CommonList.Count; i++) { if (New.instace.CommonList[i].Contains(char1)) { string commonword1 = New.instace.CommonList[i].Trim(); fixedwordsList.Add(new CrossedWord(commonword1, "")); New.NumberOfCommon++; New.instace.CommonList.Remove(New.instace.CommonList[i]); break; } } for (int i = 0; i < New.instace.CommonList.Count; i++) { if (New.instace.CommonList[i].Contains(char2)) { string commonword2 = New.instace.CommonList[i].Trim(); fixedwordsList.Add(new CrossedWord(commonword2, "")); New.NumberOfCommon++; New.instace.CommonList.Remove(New.instace.CommonList[i]); break; } } //string commonword2 = New.instace.CommonList[New.NumberOfCommon].Trim(); //fixedwordsList.Add(new CrossedWord(commonword2, "")); //New.NumberOfCommon++; // 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); print("--CrossWordsToKeep.Count----->>>" + CrossWordsToKeep.Count); for (int r = 0; r < 3; r++) { CrossWordsToKeep[r].StartingPosition.X -= crosswordMinX; CrossWordsToKeep[r].StartingPosition.Y = -CrossWordsToKeep[r].StartingPosition.Y + crosswordMinY; } CrToShow = CrossWordsToKeep; }