public static (int, int) TranslatePosition(int row, int column, OrdinalDirection ordinalDirection)
 {
     return(ordinalDirection switch
     {
         OrdinalDirection.North => (row - 1, column),
         OrdinalDirection.NorthEast => (row - 1, column + 1),
         OrdinalDirection.East => (row, column + 1),
         OrdinalDirection.SouthEast => (row + 1, column + 1),
         OrdinalDirection.South => (row + 1, column),
         OrdinalDirection.SouthWest => (row + 1, column - 1),
         OrdinalDirection.West => (row, column - 1),
         OrdinalDirection.NorthWest => (row - 1, column - 1),
         _ => throw new ArgumentException("Invalid OrdinalDirection enum value"),
     });
Exemple #2
0
        /// <summary>
        /// Try to generate a random wordsearch from the given words. If this runs into a situation where there is no valid cells
        /// to put a word, then it will restart. It will do this for the number of times given in the <see cref="attemptLimit"/> before it gives up.
        /// </summary>
        /// <param name="words">Words to put in the wordsearch</param>
        /// <param name="wordsearch">The produced wordsearch</param>
        /// <param name="attemptLimit">The number of attempts allowed before giving up</param>
        /// <returns>Whether the wordsearch was completed successfully within the number of attempts allowed</returns>
        public static bool TryGenerateRandom(IEnumerable <string> words, out Wordsearch wordsearch, int attemptLimit = 1000)
        {
            wordsearch = new Wordsearch
            {
                // Process the strings into words
                Words = words.Select(i => i.Trim())
                        .Where(i => i.Length != 0)
                        .Select(i => new Word()
                {
                    Text = i
                })
                        .ToList()
            };

            // Confirm that maximum word length is not exceeded
            if (wordsearch.Words.Where(i => i.Text.RemoveWhitespace().Length > 20).Any())
            {
                return(false);
            }


            Random random = new Random();



            // Limit the attempt number. With many words (expecially long ones) it may struggle to fit them

            int  attempt  = 0;
            bool complete = false;

            while (attempt < attemptLimit && !complete) // max attempts will take around 1 second
            {
                attempt++;

                // Generate an empty matrix
                CustomMatrix matrix = new CustomMatrix(20, 20);

                // if the end of this loop is reached without encountering the break
                // then the wordsearch generation is complete
                complete = true;
                foreach (Word word in wordsearch.Words)
                {
                    var validCells = new List <RowAndCol>();

                    // Get a random ordinal direction
                    OrdinalDirection direction = (OrdinalDirection)random.Next(0, 8);

                    string wordWithoutWhitespace = word.Text.RemoveWhitespace();
                    int    wlen = wordWithoutWhitespace.Length;

                    // Initialise the cells for consideration as the whole matrix
                    int rowstart = 0;
                    int rowend   = matrix.Rows;
                    int colstart = 0;
                    int colend   = matrix.Columns;

                    // Remove cells around the edge from consideration based on the length and direction of the word
                    switch (direction)
                    {
                    case OrdinalDirection.North:
                        rowstart = rowstart + wlen - 1;
                        break;

                    case OrdinalDirection.NorthEast:
                        rowstart = rowstart + wlen - 1;
                        colend   = colend - wlen + 1;
                        break;

                    case OrdinalDirection.East:
                        colend = colend - wlen + 1;
                        break;

                    case OrdinalDirection.SouthEast:
                        rowend = rowend - wlen + 1;
                        colend = colend - wlen + 1;
                        break;

                    case OrdinalDirection.South:
                        rowend = rowend - wlen + 1;
                        break;

                    case OrdinalDirection.SouthWest:
                        rowend   = rowend - wlen + 1;
                        colstart = colstart + wlen - 1;
                        break;

                    case OrdinalDirection.West:
                        colstart = colstart + wlen - 1;
                        break;

                    case OrdinalDirection.NorthWest:
                        rowstart = rowstart + wlen - 1;
                        colstart = colstart + wlen - 1;
                        break;
                    }

                    // using the adjusted strart and end row and column, check if that each cell is valid
                    for (int i = rowstart; i < rowend; i++)
                    {
                        for (int j = colstart; j < colend; j++)
                        {
                            int  row      = i;
                            int  col      = j;
                            bool occupied = false;
                            // using the words direction, for each letter in the word, check if the cell it would be in is availiable
                            // the cell is also valid if they are the same letter
                            for (int c = 0; c < wlen; c++)
                            {
                                if (matrix.PositionIsOccupied(row, col) && wordWithoutWhitespace[c] != matrix.GetValueAt(row, col))
                                {
                                    occupied = true;
                                    break;
                                }
                                ;
                                (row, col) = CustomMatrix.TranslatePosition(row, col, direction);
                            }
                            if (!occupied)
                            {
                                validCells.Add(new RowAndCol(i, j));
                            }
                        }
                    }

                    // if there is no valid position found for the word
                    // break from the loop with an incomplete marker
                    // which will begin a new attempt
                    if (validCells.Count < 1)
                    {
                        complete = false;
                        break;
                    }

                    #region idea prob never use
                    // pick a random segment to avoid bias towards parallel close together words

                    /*
                     * int randomSegmentRowStart = random.Next(0, 15);
                     * int randomSegmentColStart = random.Next(0, 15);
                     *
                     * List<int[]> segmentValidCells = validCells.Where
                     * (i =>
                     *  i[0] >= randomSegmentRowStart &&
                     *  i[0] < randomSegmentRowStart + 5 &&
                     *  i[0] >= randomSegmentColStart &&
                     *  i[0] < randomSegmentColStart + 5
                     * ).ToList();
                     *
                     * if (segmentValidCells.Count > 0)
                     * {
                     *  validCells = segmentValidCells;
                     * }
                     */
                    #endregion

                    // Choose a random cell from all of the valid options
                    RowAndCol cell = validCells[random.Next(0, validCells.Count)];

                    word.Direction   = direction;
                    word.StartRow    = cell.Row;
                    word.StartColumn = cell.Col;

                    // Input the word into the matrix at the chosen position
                    int rw = word.StartRow;
                    int cl = word.StartColumn;
                    foreach (char chr in word.Text.RemoveWhitespace())
                    {
                        matrix.SetValueAt(rw, cl, chr);
                        (rw, cl) = CustomMatrix.TranslatePosition(rw, cl, word.Direction);
                    }
                }
            }

            // if complete == false here that means the attempt limit was reached without success
            if (!complete)
            {
                return(false);
            }
            return(true);
        }