Пример #1
0
        /*
         * 1. Choosing which pattern to fill (i.e. which variable to solve for).
         * 2. Picking a suitable word (i.e. which value to select).
         * 3. Choosing where to backtrack to when we reach an impasse.
         */

        public IEnumerable <ICrossBoard> Generate()
        {
            var          history       = new List <int>();
            var          historyTrans  = new List <List <CrossTransformation> >();
            var          matchingWords = new List <string>();
            var          usedWords     = new HashSet <string>();
            CrossPattern patt          = _board.GetMostConstrainedPattern(_dict);

            while (true)
            {
                DoCommands();
                if (patt != null)
                {
                    matchingWords.Clear();
                    _dict.GetMatch(patt.Pattern, matchingWords);
                    var succTrans = new List <CrossTransformation>();
                    foreach (string t in matchingWords)
                    {
                        if (usedWords.Contains(t))
                        {
                            continue;
                        }
                        var trans = patt.TryFill(t, t.AsSpan(), _dict);
                        if (trans != null)
                        {
                            succTrans.Add(trans);
                            trans.Pattern = patt;
                        }
                    }
                    if (succTrans.Count > 0)
                    {
                        succTrans.Sort(new CrossTransformationComparer());
                        var trans = succTrans[0];
                        usedWords.Add(trans.Word);
                        trans.Transform(patt);
                        historyTrans.Add(succTrans);
                        history.Add(0);
                        patt = _board.GetMostConstrainedPattern(_dict);
                    }
                    else
                    {
                        patt = BackTrack(history, historyTrans, usedWords);
                        if (patt == null)
                        {
                            yield break;
                        }
                    }
                }
                else
                {
                    yield return(_board.Clone());

                    patt = BackTrack(history, historyTrans, usedWords);
                    if (patt == null)
                    {
                        yield break;
                    }
                }
            }
        }
Пример #2
0
        public IEnumerable <ICrossBoard> GetAllPossiblePlacements(ICrossDictionary dictionary)
        {
            var puzzle = NormalizePuzzle(_puzzle).AsMemory();
            var board  = _board.Clone();

            board.Preprocess(dictionary);
            var patterns = new List <CrossPattern>();

            for (int i = 0; i < board.GetPatternCount(); i++)
            {
                patterns.Add(board.GetCrossPattern(i));
            }
            patterns.Sort((a, b) => - 1 * a.Length.CompareTo(b.Length));
            if (patterns.Count == 0)
            {
                yield break;
            }

            var restPuzzleLength       = puzzle.Length;
            var stack                  = new List <int>();
            var appliedTransformations = new List <CrossTransformation>();
            int idx = 0;

            while (true)
            {
continueOuterLoop:
                for (; idx < patterns.Count; idx++)
                {
                    var pattern = patterns[idx];
                    if (restPuzzleLength < pattern.Length)
                    {
                        continue;
                    }
                    if (restPuzzleLength - pattern.Length == 1)
                    {
                        continue;
                    }
                    var trans = pattern.TryFillPuzzle(puzzle.Slice(puzzle.Length - restPuzzleLength,
                                                                   pattern.Length).Span, dictionary);
                    if (trans != null)
                    {
                        trans.Transform(pattern);
                        if (restPuzzleLength == pattern.Length)
                        {
                            var cloned = board.Clone();
                            trans.Undo(pattern);
                            yield return(cloned);

                            continue;
                        }

                        stack.Add(idx + 1);
                        trans.Pattern = pattern;
                        appliedTransformations.Add(trans);
                        restPuzzleLength -= pattern.Length;
                        idx = 0;
                        goto continueOuterLoop;
                    }
                }

                if (stack.Count == 0)
                {
                    break;
                }
                idx = stack.Back();
                stack.Pop();
                var appTr = appliedTransformations.Back();
                appliedTransformations.Pop();
                appTr.Undo(appTr.Pattern);
                restPuzzleLength += appTr.Pattern.Length;
            }
        }
Пример #3
0
        public IEnumerable <ICrossBoard> GetAllPossiblePlacements(ICrossDictionary dictionary)
        {
            var puzzle = NormalizePuzzle(_puzzle); // used to be .AsSpan() but throwing exception: Instance of type 'ReadOnlySpan<char>' cannot be used inside a nested function, query expression, iterator block or async method
            var board  = _board.Clone();

            board.Preprocess(dictionary);

            var patterns = new List <CrossPattern>();

            for (int i = 0; i < board.GetPatternCount(); i++)
            {
                patterns.Add(board.GetCrossPattern(i));
            }

            // sort by word length
            patterns.Sort((a, b) => - 1 * a.Length.CompareTo(b.Length));
            if (patterns.Count == 0)
            {
                yield break;
            }

            var restPuzzleLength       = puzzle.Length;
            var stack                  = new List <int>();
            var appliedTransformations = new List <CrossTransformation>();

            int idx = 0;

            while (true)
            {
continueOuterLoop:

                for (; idx < patterns.Count; idx++)
                {
                    var pattern = patterns[idx];

                    if (restPuzzleLength < pattern.Length)
                    {
                        continue;
                    }
                    if (restPuzzleLength - pattern.Length == 1)
                    {
                        break; // PIN: this was a continue statement - which seems like a bug
                    }

                    var trans = pattern.TryFillPuzzle(puzzle.AsSpan(puzzle.Length - restPuzzleLength, pattern.Length),
                                                      dictionary);
                    if (trans != null)
                    {
                        trans.Transform(pattern);
                        if (restPuzzleLength == pattern.Length)
                        {
                            // ensure only one pattern is marked as a puzzle
                            patterns.All(c => { c.IsPuzzle = false; return(true); });

                            // set the current pattern as puzzle
                            pattern.IsPuzzle = true;

                            var cloned = (ICrossBoard)board.Clone(); // clone before we revert the puzzle pattern
                            trans.Undo(pattern);

                            yield return(cloned);

                            continue;
                        }

                        stack.Add(idx + 1);
                        trans.Pattern = pattern;
                        appliedTransformations.Add(trans);
                        restPuzzleLength -= pattern.Length;
                        idx = 0;
                        goto continueOuterLoop;
                    }
                }

                if (stack.Count == 0)
                {
                    break;
                }

                idx = stack.Back();
                stack.Pop();
                var appTr = appliedTransformations.Back();
                appliedTransformations.Pop();
                appTr.Undo(appTr.Pattern);
                restPuzzleLength += appTr.Pattern.Length;
            }
            yield break;
        }
Пример #4
0
        /*
         * 1. Choosing which pattern to fill (i.e. which variable to solve for).
         * 2. Picking a suitable word (i.e. which value to select).
         * 3. Choosing where to backtrack to when we reach an impasse.
         */

        public IEnumerable <ICrossBoard> Generate()
        {
            var          history       = new List <int>();
            var          historyTrans  = new List <List <CrossTransformation> >();
            var          matchingWords = new List <string>();
            var          usedWords     = new HashSet <string>();
            CrossPattern pattern       = _board.GetMostConstrainedPattern(_dict);

            Random rnd = new Random();

            while (true)
            {
                DoCommands();
                if (pattern != null)
                {
                    matchingWords.Clear();
                    _dict.GetMatch(pattern.Pattern, matchingWords);
                    var succTrans = new List <CrossTransformation>();
                    foreach (string t in matchingWords)
                    {
                        if (usedWords.Count > 0 && usedWords.Contains(t))
                        {
                            continue;
                        }

                        // checking if there exist words in the dictionary matching each of the adjacent patterns
                        var trans = pattern.TryFill(t, t.AsSpan(), _dict);
                        if (trans != null)
                        {
                            succTrans.Add(trans);
                            trans.Pattern = pattern;
                        }
                    }

                    if (succTrans.Count > 0)
                    {
                        succTrans.Sort(new CrossTransformationComparer()); // using the successfull transform with most ?!

                        // always use the first index (i.e. the one with the most possible adjacent hits)
                        var trans = succTrans[0];
                        history.Add(0);

                        // don't always use the "best" match to randomize the crossword better
                        // var lowestIndexToUse = 0;
                        // var highestIndexToUse = succTrans.Count > 10 ? 10 : succTrans.Count;
                        // int index = rnd.Next(lowestIndexToUse, highestIndexToUse);
                        // var trans = succTrans[index];
                        // history.Add(index);

                        usedWords.Add(trans.Word);
                        trans.Transform(pattern);
                        historyTrans.Add(succTrans);

                        pattern = _board.GetMostConstrainedPattern(_dict);
                    }
                    else
                    {
                        pattern = BackTrack(history, historyTrans, usedWords);
                        if (pattern == null)
                        {
                            yield break;
                        }
                    }
                }
                else
                {
                    yield return(_board.Clone());

                    pattern = BackTrack(history, historyTrans, usedWords);
                    if (pattern == null)
                    {
                        yield break;
                    }
                }
            }
        }