/// <summary>
    /// Requires that the words in the list have a category entry and that categories have some multiple of four words in each of them.
    ///
    /// Shuffles into lists of 12 words appended without delineation to the return list.
    /// </summary>
    /// <returns>The shuffled list of words.</returns>
    /// <param name="rng">Rng.</param>
    /// <param name="list">List.</param>
    /// <param name="lengthOfEachList">Length of each list.</param>
    protected IronPython.Runtime.List CategoryShuffle(System.Random rng, IronPython.Runtime.List list, int lengthOfEachList)
    {
        if (lengthOfEachList != 12)
        {
            throw new UnityException("Currently only lists of 12 words are supported by CatFR.");
        }

        /////////////in order to select words from appropriate categories, build a dict with categories as keys and a list of words as values
        Dictionary <string, IronPython.Runtime.List> categoriesToWords = BuildCategoryToWordDict(rng, list);

        /////////////we will append words to this in the proper order and then return it
        IronPython.Runtime.List returnList = new IronPython.Runtime.List();

        bool finished   = false;
        int  iterations = 0;

        do
        {
            iterations++;
            if (iterations > 1000)
            {
                finished = true;
                throw new UnityException("Error while shuffle catFR list");
            }

            ////////////if there are less than three categories remaining, we are on the last list and can't complete it validly
            ////////////this is currently handled by simply trying the whole process again
            if (categoriesToWords.Count < 3)
            {
                //start over
                categoriesToWords = BuildCategoryToWordDict(rng, list);
                returnList        = new IronPython.Runtime.List();
                continue;
            }

            List <string> keyList = new List <string>(categoriesToWords.Keys);

            //////////find three random unique categories
            string randomCategoryA = keyList[rng.Next(keyList.Count)];
            string randomCategoryB;
            do
            {
                randomCategoryB = keyList[rng.Next(keyList.Count)];
            }while (randomCategoryB.Equals(randomCategoryA));
            string randomCategoryC;
            do
            {
                randomCategoryC = keyList[rng.Next(keyList.Count)];
            }while (randomCategoryC.Equals(randomCategoryA) | randomCategoryC.Equals(randomCategoryB));

            //////////get four words from each of these categories
            IronPython.Runtime.List groupA = new IronPython.Runtime.List();
            IronPython.Runtime.List groupB = new IronPython.Runtime.List();
            IronPython.Runtime.List groupC = new IronPython.Runtime.List();

            for (int i = 0; i < 4; i++)
            {
                groupA.Add(categoriesToWords[randomCategoryA].pop());
            }
            for (int i = 0; i < 4; i++)
            {
                groupB.Add(categoriesToWords[randomCategoryB].pop());
            }
            for (int i = 0; i < 4; i++)
            {
                groupC.Add(categoriesToWords[randomCategoryC].pop());
            }

            //////////remove categories from dict if all 12 words have been used
            if (categoriesToWords[randomCategoryA].Count == 0)
            {
                categoriesToWords.Remove(randomCategoryA);
            }
            if (categoriesToWords[randomCategoryB].Count == 0)
            {
                categoriesToWords.Remove(randomCategoryB);
            }
            if (categoriesToWords[randomCategoryC].Count == 0)
            {
                categoriesToWords.Remove(randomCategoryC);
            }

            //////////integers 0, 1, 2, 0, 1, 2 representing the order in which to present pairs of words from categories (A == 1, B == 2, etc.)
            //////////make sure to fulfill the requirement that both halves have ABC and the end of the first half is not the beginning of the second
            IronPython.Runtime.List groups = new IronPython.Runtime.List();
            for (int i = 0; i < 3; i++)
            {
                groups.Add(i);
            }
            groups = Shuffled(rng, groups);
            int index = 0;
            int first_half_last_item = 0;
            foreach (int item in groups)
            {
                if (index == 2)
                {
                    first_half_last_item = item;
                }
                index++;
            }

            IronPython.Runtime.List secondHalf = new IronPython.Runtime.List();
            for (int i = 0; i < 3; i++)
            {
                secondHalf.Add(i);
            }
            secondHalf.Remove(first_half_last_item);
            secondHalf = Shuffled(rng, secondHalf);
            bool insertAtEnd = rng.Next(2) == 0;
            if (insertAtEnd)
            {
                secondHalf.Insert(secondHalf.Count, first_half_last_item);
            }
            else
            {
                secondHalf.Insert(secondHalf.Count - 1, first_half_last_item);
            }
            foreach (int item in secondHalf)
            {
                groups.append(item);
            }

            //////////append words to the final list according to the integers gotten above
            foreach (int groupNo in groups)
            {
                if (groupNo == 0)
                {
                    returnList.append(groupA.pop());
                    returnList.append(groupA.pop());
                }
                if (groupNo == 1)
                {
                    returnList.append(groupB.pop());
                    returnList.append(groupB.pop());
                }
                if (groupNo == 2)
                {
                    returnList.append(groupC.pop());
                    returnList.append(groupC.pop());
                }
            }

            //////////if there are no more categories left, we're done
            if (categoriesToWords.Count == 0)
            {
                finished = true;
            }
        }while (!finished);

        return(returnList);
    }