// Return how many words of length UP TO 'lenght' are in/out of the language
        public static Tuple <int, int> getMinWordInAndOut(ContextFreeGrammar grammar, int length, int minAcc, int minRej)
        {
            int acc = 0, rej = 0;
            var literals = grammar.GetNonVariableSymbols();
            HashSet <string> wordsOfEqualLength = new HashSet <string>();

            for (int i = 0; i <= length; i++)
            {
                if (wordsOfEqualLength.Count == 0)
                {
                    wordsOfEqualLength.Add("");
                }
                else
                {
                    var cur = new HashSet <string>();
                    foreach (string word in wordsOfEqualLength)
                    {
                        foreach (GrammarSymbol literal in literals)
                        {
                            cur.Add(word + literal.ToString());
                        }
                    }
                    wordsOfEqualLength = cur;
                }
                // Checking for each word of a particular length if it is accepted by the language
                foreach (string word in wordsOfEqualLength)
                {
                    if (isWordInGrammar(grammar, word))
                    {
                        acc++;
                    }
                    else
                    {
                        rej++;
                    }
                }

                if (acc >= minAcc && rej >= minRej)
                {
                    break;
                }
            }

            return(new Tuple <int, int>(acc, rej));
        }
        public static Tuple <int, IEnumerable <String> > gradeWordsInGrammar(ContextFreeGrammar grammar, IEnumerable <String> wordsIn, IEnumerable <String> wordsOut, int maxGrade)
        {
            int    cases     = 0;
            double correct   = 0;
            var    terminals = new List <char>();

            foreach (GrammarSymbol s in grammar.GetNonVariableSymbols())
            {
                terminals.Add(s.ToString()[0]);
            }
            List <String> feedback = new List <String>();

            HashSet <String> done = new HashSet <String>(); //for duplicate checking

            foreach (String w in wordsIn)
            {
                cases++;
                //handle duplicates
                if (done.Contains(w))
                {
                    feedback.Add(String.Format("The word \"{0}\" was used more than once!", w));
                    continue;
                }
                else
                {
                    done.Add(w);
                }

                int prefixLength = GrammarUtilities.longestPrefixLength(grammar, w);

                if (prefixLength < 0)
                {
                    correct++;                   //correct
                }
                else //wrong
                {
                    feedback.Add(String.Format("The word \"{0}\" isn't in the language of the grammar! (hint: the word '{1}' is still possible prefix)", w, w.Substring(0, prefixLength)));
                }
            }
            foreach (String w in wordsOut)
            {
                cases++;
                //handle duplicates
                if (done.Contains(w))
                {
                    feedback.Add(String.Format("The word \"{0}\" was used more than once!", w));
                    continue;
                }
                else
                {
                    done.Add(w);
                }

                if (!GrammarUtilities.isWordInGrammar(grammar, w)) //correct
                {
                    //only useful terminals?
                    bool allUsefull = true;
                    char problem    = 'a';
                    foreach (char c in w)
                    {
                        if (!terminals.Contains(c))
                        {
                            allUsefull = false;
                            problem    = c;
                            break;
                        }
                    }

                    if (allUsefull)
                    {
                        correct += 1;             //full points
                    }
                    else //only half the points
                    {
                        correct += 0.5;
                        feedback.Add(String.Format("The word \"{0}\" uses the symbol '{1}' that is not part of the alphabet...", w, problem));
                    }
                }
                else   //wrong
                {
                    feedback.Add(String.Format("The word \"{0}\" is in the language of the grammar!", w));
                }
            }

            int grade = (int)Math.Floor(correct * maxGrade / (double)cases);

            //all correct?
            if (grade == maxGrade)
            {
                feedback.Add("Correct!");
            }

            return(Tuple.Create(grade, (IEnumerable <String>)feedback));
        }