Ejemplo n.º 1
0
 // Copy constructor
 // m_WordPositionsList contains the same references as tho copied layout
 // m_Squares contains new copies of copied layout squares
 // m_WordsList is a new copy of original list
 internal WordPositionLayout(WordPositionLayout copy)
 {
     m_WordPositionList.AddRange(copy.m_WordPositionList);
     using var e = copy.m_Squares.GetEnumerator();
     while (e.MoveNext())
     {
         m_Squares.Add(e.Current.Key, new Square(e.Current.Value));
     }
 }
Ejemplo n.º 2
0
        /// <summary>Core placement function, adds a list of words to current layout</summary>
        /// <param name="wordsToAddList">List of words to place</param>
        /// <param name="withLayoutBackup">If true, current layout is backed up, and restored if placement of all words failed</param>
        /// <returns>Returns a list of WordPosition for placed words in case of success, or false if placement failed, current layout is preserved in this case</returns>
        public IEnumerable <WordPosition> PlaceWordsList(IEnumerable <string> wordsToAddList, bool withLayoutBackup)
        {
            if (wordsToAddList == null)
            {
                throw new ArgumentNullException(nameof(wordsToAddList));
            }

            // Keep a copy of current layout to restore if placement fails at some point
            WordPositionLayout backupLayout = null;

            if (withLayoutBackup)
            {
                backupLayout = new WordPositionLayout(Layout);
            }

            string checkMessage = CheckWordsList(wordsToAddList);

            if (!string.IsNullOrEmpty(checkMessage))
            {
                throw new BonzaException(checkMessage);
            }

            List <string>       shuffledList           = new List <string>(wordsToAddList).Shuffle();
            List <WordPosition> placedWordPositionList = new List <WordPosition>();

            while (shuffledList.Count > 0)
            {
                List <string> placedWords = new List <string>();
                foreach (string word in shuffledList)
                {
                    WordPosition wordPosition = PlaceWord(word);
                    if (wordPosition != null)
                    {
                        placedWords.Add(word);
                        placedWordPositionList.Add(wordPosition);
                        //Debug.WriteLine($"Placed {placedWordPositionList.Count}/{wordsToAddList.Count}: {wordPosition.Word}");
                    }
                }
                // If at the end of this loop no canonizedWord has been placed, we have a problem...
                if (placedWords.Count == 0)
                {
                    if (withLayoutBackup)
                    {
                        Layout = backupLayout;                        // Restore initial layout
                    }
                    return(null);
                }
                // On the other hand, if pass was successful, remove all placed words and go for a new pass
                foreach (string placedWord in placedWords)
                {
                    shuffledList.Remove(placedWord);
                }
            }

            return(placedWordPositionList);
        }
Ejemplo n.º 3
0
        /// <summary>Shuffle words after reinitializing layout.</summary>
        /// <returns>Returns true if new placement is successful, or false if placement failed (current layout is preserved in this case)</returns>
        public bool PlaceWordsAgain()
        {
            // AddWordsList keeps a backup of Layout and restore it if placement failed...
            // but since we call it after reinitializing the layout, it won't work for us
            WordPositionLayout backupLayout = new WordPositionLayout(Layout);
            var wordsList = Layout.WordPositionList.Select(wordPosition => wordPosition.OriginalWord).ToList();

            NewLayout();
            if (PlaceWordsList(wordsList, false) == null)
            {
                Layout = backupLayout;
                return(false);
            }
            return(true);
        }
Ejemplo n.º 4
0
 /// <summary>Complete reinitialization of layout, WordPosition and Words</summary>
 public void NewLayout()
 {
     Layout = new WordPositionLayout();
 }
Ejemplo n.º 5
0
        private IList <WordPosition> FindWordPossiblePlacements(string originalWord, PlaceWordOptimization optimization)
        {
            string canonizedWord = CanonizeWord(originalWord);

            // If it's the first canonizedWord of the layout, chose random orientation and place it at position (0, 0)
            if (Layout.WordPositionList.Count == 0)
            {
                WordPosition wordPosition = new WordPosition(canonizedWord, originalWord, new PositionOrientation(0, 0, rnd.NextDouble() > 0.5));
                return(new List <WordPosition> {
                    wordPosition
                });
            }

            // Get current layout since we'll prefer placements that minimize layout extension to keep words grouped
            BoundingRectangle r = Layout.Bounds;
            int surface         = ComputeAdjustedSurface(r.Max.Column - r.Min.Column + 1, r.Max.Row - r.Min.Row + 1);

            // Find first all positions where the canonizedWord can be added to current layout;
            List <WordPosition> possibleWordPositions = new List <WordPosition>();
            List <WordPosition> possibleWordPositionsBelowThreshold = new List <WordPosition>();
            int minSurface = int.MaxValue;

            foreach (WordPosition wordPosition in Layout.WordPositionList)
            {
                foreach (WordPosition placedWordPosition in TryPlace(canonizedWord, originalWord, wordPosition))
                {
                    BoundingRectangle newR = WordPositionLayout.ExtendBounds(r, placedWordPosition);
                    if (newR.Equals(r))
                    {
                        if (optimization == PlaceWordOptimization.Aggressive)
                        {
                            return new List <WordPosition> {
                                       placedWordPosition
                            }
                        }
                        ;
                        if (optimization == PlaceWordOptimization.High)
                        {
                            possibleWordPositionsBelowThreshold.Add(placedWordPosition);
                        }
                    }
                    int newSurface = ComputeAdjustedSurface(newR.Max.Column - newR.Min.Column + 1, newR.Max.Row - newR.Min.Row + 1);
                    possibleWordPositions.Add(placedWordPosition);
                    switch (optimization)
                    {
                    case PlaceWordOptimization.Aggressive:
                    case PlaceWordOptimization.High:
                        if (possibleWordPositions.Count > 0 && minSurface > newSurface)
                        {
                            possibleWordPositions.RemoveAt(0);
                            minSurface = newSurface;
                        }
                        if (possibleWordPositions.Count == 0)
                        {
                            possibleWordPositions.Add(placedWordPosition);
                        }
                        break;

                    case PlaceWordOptimization.Standard:
                        if (newSurface < surface * 1.15)
                        {
                            possibleWordPositionsBelowThreshold.Add(placedWordPosition);
                        }
                        possibleWordPositions.Add(placedWordPosition);
                        break;

                    default:
                        possibleWordPositions.Add(placedWordPosition);
                        break;
                    }
                }
            }

            if (possibleWordPositionsBelowThreshold.Count > 0)
            {
                return(possibleWordPositionsBelowThreshold);
            }
            return(possibleWordPositions);
        }