Create a method to list the words available within a given hand

From TRCCompSci - AQA Computer Science
Revision as of 10:05, 20 November 2017 by Charley (talk | contribs) (Method 1)
Jump to: navigation, search

Listing Words Method

The option "See available words with this hand." is added to the player's options in GetChoice().

private static string GetChoice() {
    string Choice;
    Console.WriteLine();
    Console.WriteLine("Either:");
    Console.WriteLine("     enter the word you would like to play OR");
    Console.WriteLine("     press 1 to display the letter values OR");
    Console.WriteLine("     press 4 to view the tile queue OR");
    Console.WriteLine("     press 7 to view your tiles again OR");
    Console.WriteLine("     press 0 to fill hand and stop the game.");
    Console.WriteLine("     press 3 to see available words with this hand.");
    Console.Write("> ");
    Choice = Console.ReadLine();
    Console.WriteLine();
    Choice = Choice.ToUpper();
    return Choice;
    }

The following code is added to the choices in Have Turn:

// ... Some stuff was here

else if (Choice == "3") {
    for (int i = 0; i < AllowedWords.Count; i++) {
        bool wordintiles = CheckWordIsInTiles(AllowedWords[i], PlayerTiles);

        if (wordintiles == true) {
            Console.WriteLine(AllowedWords[i]);
        }
    }
}

// ... Some stuff is here

This goes through the list of allowed words in alphabetical order and checks if the word can be made from the player's current tiles. If it can be, the word is outputted.

One problem is that you can make quite a lot of words from any given hand (even if it doesn't seem like it), so this outputs so many words that by the time it's done you can no longer see the top of the list.

Print in Alphabetical Order

// ... Some stuff was here

else if (Choice == "3") {
    String[] sortedAllowedWords = AllowedWords.ToArray();
    Array.Sort(sortedAllowedWords); // Sort allowed words

    for (int i = 0; i < sortedAllowedWords.Length; i++) {
        bool wordintiles = CheckWordIsInTiles(sortedAllowedWords[i], PlayerTiles);

        if (wordintiles == true) {
            Console.WriteLine(AllowedWords[i]);
        }
    }
}

// ... Some stuff is here

In this method we print all available words in chronological order. To do so, we cast the allowed words to an array (note it could be kept as a list, but seeing as we have no intention to change the size of it I felt turning it to an array would be far more appropriate). After that everything else is quite assimilair to the previous method.

Print by Word Length

Method 1

I have added a for loop around the above code which will count down from 20 to 1. This is used to also check the length of the word found in the tiles before it is printed. The first for loop will stop when it gets down to 1 or if a word has been found, this way it will give you the longest words.

// ... Some stuff was here

else if (Choice == "3") {
    bool found = false;
    
    for (int w = 20; w > 1; w--)
    {
        for (int i = 0; i < AllowedWords.Length; i++) {
            bool wordintiles = CheckWordIsInTiles(AllowedWords[i], PlayerTiles);

            if (wordintiles && (AllowedWords[i].Length == w)) {
                Console.WriteLine(AllowedWords[i]);
                found=true;
            }
        if (found)
            break;
    }

    if (!found)
        Console.WriteLine("No words found in your tiles");
}

// ... Some stuff is here

The above version finds whether a word is valid and then checks whether the length is right. The one below checks the length of the word before it checks for validity, which I think might make it work quicker.

// something here...
else if (Choice == "3")
                {
                    bool found = false;
                    for (int w = 20; w > 1; w--)
                    {
                        for (int i = 0; i < AllowedWords.Count; i++)
                        {
                            if (AllowedWords[i].Length == w)
                            {
                                bool wordintiles = CheckWordIsInTiles(AllowedWords[i], PlayerTiles);
                                if (wordintiles == true)
                                {
                                    Console.WriteLine(AllowedWords[i]);
                                    found = true;
                                }
                            } 
                        }
                        if (found)
                        {
                            break;
                        }
                    }
                    if (!found)
                    {
                        Console.WriteLine("No words found.");
                    }
                }
// something here...

Method 2

// ... Some stuff was here

else if (Choice == "3") {
    String playerTiles = PlayerTiles; // Store locally to pass within linq query, BECAUSE REF VARS CAN'T BE PASSED
    String[] wordsInTiles = (from X in AllowedWords where CheckWordIsInTiles(X, playerTiles) select X).ToArray();

    Array.Sort(wordsInTiles, (wordA, wordB) => {
        if   (wordA.Length >= wordB.Length) return +1;
        else                                return -1;
    });

    foreach (String word in wordsInTiles) {
        Console.WriteLine(word);
    }
}

// ... Some stuff is here

This method sorts and then prints all words within the players tiles in descending order. Before I go on to explain the intricacies of the sort method, let me firstly explain how I got the wordsInTiles array in the above method which represents all the words which exists within the players tiles. For those who are unfamilliar with the common LINQ query, think of SQL but to manipulate variables and enumerables collections within CSharp. They are fundamentally in-differentiable from SQL, except the select query comes at the end of the queryable (counter to SQL where it comes at the beginning). For those who're still unaware, those two lines are functionally the same as this:

List<String> _wordsInTiles = new List<String>();

foreach (String word in AllowedWords) {
    if (CheckWordIsInTiles(word, PlayerTiles))
        _wordsInTiles.Add(word);
}

String[] wordsInTiles = _wordsInTiles.ToArray();

Now that we've cleared up that whole chunk. The remainder of the above method is quite self explanatory apart from the Array.Sort partition. Array.Sort cycles through the array and then uses an anonymous method (passed as the second argument) to determine whether one item is greater than another or not and then push it further down in the array. If the argument method returns a 1 the value will be pushed to the end of the array and if it's -1 the method will pull the value to the start of the array (I believe 0 just keeps it in the same place).

Print by Word Score

// ... Some stuff was here

else if (Choice == "3") {
    String playerTiles = PlayerTiles; // Store locally to pass within linq query
    String[] wordsInTiles = (from X in AllowedWords where CheckWordIsInTiles(X, playerTiles) select X).ToArray();

    Array.Sort(wordsInTiles, (wordA, wordB) => {
        int wordAScore = GetScoreForWord(wordA, TileDictionary);
        int wordBScore = GetScoreForWord(wordB, TileDictionary);

        if   (wordAScore >= wordBScore) return +1;
        else                            return -1;
    });

    foreach (String word in wordsInTiles) {
        Console.WriteLine(String.Format("{0} - {1}", word, GetScoreForWord(word, TileDictionary)));
    }
}

// ... Some stuff is here

This method is practically identicle to the one for print by word length, I feel no reason to reiterate what it does.