Resolved Hi guys, currently making a guessing game and need some help with my code..

sock1992

Well-known member
Joined
May 20, 2020
Messages
107
Programming Experience
Beginner
At the moment the program will only reveal a letter if the users input matches the specified letter within the iteration.

What I would like to do is reveal a letter despite what iteration the user is on...e.g. if the user inputs "P" on the first iteration I want the program to reveal all the Ps" in happy.

Thanks!


C#:
 {
           
            string[] secret = { "h", "a", "p", "p", "y" };
            string[] hidden = { "_", "_", "_", "_", "_" };
            string letter = "";

            Console.WriteLine("Welcome to guess a word game");

            for (int i = 0; i < secret.Length; i++)
            {            
                Console.WriteLine("Guess a letter: ");
                letter = Console.ReadLine();

                //revealing letters
                if (secret[i]  == letter)
                {
                    hidden[i] = letter;
                }
                //displaying the word to the user after each guess
                foreach (string k in hidden)
                {
                    Console.Write(k.ToString());                  
                }
                Console.WriteLine();
            }
            Console.WriteLine();
         
            // once broken out of the for loop it will inform the user if they have guessed the word correctly.
            if(secret == hidden)
            {
                Console.WriteLine("You have guessed the correct word!");
            }
            else
            {
                Console.WriteLine("unfortunately you have not gussed the correct word");
            }
            Console.ReadLine();
        }
    }
}
 
Solution
I have made some changes to your code. I added the following variables :
C#:
            int DuplicateCount = secret.GroupBy(value => value).Where(value => value.Count() > 1).Sum(value => value.Count());
            string letter = "";
            int Loop = 0;
DuplicateCount gives you the count of Duplicate letters.

I also added an infinite loop which will exit when the loop variable equals the length of your secret.
C#:
            Console.WriteLine("Welcome to guess a word game");
            while (true)
            {
                Loop++;
                Console.WriteLine("Guess a letter: ");
                letter = Console.ReadLine();
                Console.WriteLine();
                if (DuplicateCount <= 1 &&...
Maybe it can be solution:
C#:
for(int i=0;i<secret.Length;i++)
{
    //TODO:
}

//Just take out foreach block from th loop
//displaying the word to the user after each guess
foreach (string k in hidden)
{
Console.Write(k.ToString());                 
}
Console.WriteLine();

//TODO:
 
How? Please explain your solution.

And why are you calling to string on an object which is already a string? That's redundant code...
 
How? Please explain your solution.

And why are you calling to string on an object which is already a string? That's redundant code...
**And why are you calling to string on an object which is already a string? That's redundant code...** - My mistake, I've now altered that in my program.

I've already answered that above, if the user enters a letter that is in the secret word "Happy", I would like my program to reveal that letter despite what iteration the for loop is on.

e.g. if I'm on the first iteration of the for loop and I enter a "P", I would then like the program to display "_ _PP_".

I don't want to have to wait until the 3rd and 4th iteration to reveal both of those letters.

apologies, I am a complete beginner
 
Last edited:
The issue is that you are tying the guess number with the letter index? If you structure your code to the following pseudo code, you would have an easier time:
C#:
For each letter in secret
    Add maskedLetter to mask

For guessNumber = 1 to secret.Length
{
    Get guess
    For each letter in secret
        If letter matched guess
            Unmask the letter in the mask
    For each maskedLetter in mask
        Display maskedLetter
}
 
The issue is that you are tying the guess number with the letter index? If you structure your code to the following pseudo code, you would have an easier time:
C#:
For each letter in secret
    Add maskedLetter to mask

For guessNumber = 1 to secret.Length
{
    Get guess
    For each letter in secret
        If letter matched guess
            Unmask the letter in the mask
    For each maskedLetter in mask
        Display maskedLetter
}
Thank you! :D
 
I have made some changes to your code. I added the following variables :
C#:
            int DuplicateCount = secret.GroupBy(value => value).Where(value => value.Count() > 1).Sum(value => value.Count());
            string letter = "";
            int Loop = 0;
DuplicateCount gives you the count of Duplicate letters.

I also added an infinite loop which will exit when the loop variable equals the length of your secret.
C#:
            Console.WriteLine("Welcome to guess a word game");
            while (true)
            {
                Loop++;
                Console.WriteLine("Guess a letter: ");
                letter = Console.ReadLine();
                Console.WriteLine();
                if (DuplicateCount <= 1 && secret.Contains(letter))
                {
                    int position = Array.IndexOf(secret, letter);
                    if (position >= 0)
                    {
                        hidden[position] = letter;
                        Console.WriteLine($"Uncovering Secret Word : { string.Join(" ", hidden[0], hidden[1], hidden[2], hidden[3], hidden[4]) }");
                    }
                    if (Loop == secret.Length)
                    {
                        break;
                    }
                }
                else if (DuplicateCount >= 1 && secret.Distinct().Count() < secret.Length && secret.Contains(letter))
                {
                    /* This gives you an IGrouping interface carrying the key of the duplicate letter. This is not needed. I just added it in case you wanted to use it.  */
                    IGrouping<string, string>[] DuplicateValues = secret.GroupBy(value => value).Where(value => value.Count() > 1).ToArray();
                    for (int i = 0; i < secret.Length; i++)
                    {
                        if (secret[i] == letter)
                        {
                            hidden[i] = letter;
                        }
                    }
                    Console.WriteLine($"Uncovering Secret Word : { string.Join(" ", hidden[0], hidden[1], hidden[2], hidden[3], hidden[4]) }");
                }
                if (!hidden.Contains("_"))
                    break;
            }
            Console.WriteLine();
Previously this was how you were comparing your string arrays :
C#:
            // once broken out of the for loop it will inform the user if they have guessed the word correctly.
            if(secret == hidden)
What you should have used is Enumerable.SequenceEqual - Enumerable.SequenceEqual Method (System.Linq) yes these can be used on arrays :
C#:
            // once broken out of the for loop it will inform the user if they have guessed the word correctly.
            // I have made this change to properly compare two arrays. The way you were doing it was not appropriate. Use Enumerable.SequenceEqual instead.
            if (Enumerable.SequenceEqual(secret, hidden))
            {
                Console.WriteLine("You have guessed the correct word!");
            }
            else
            {
                Console.WriteLine("unfortunately you have not gussed the correct word");
            }
            Console.ReadLine();
Here is a screenshot of the application in action :

Screenshot_32.jpg

The finished code :
Finished Code:
        static void Main(string[] args)
        {
            string[] secret = { "h", "a", "p", "p", "y" };
            string[] hidden = { "_", "_", "_", "_", "_" };
            /* This gives you the count of Duplicate letters. */
            int DuplicateCount = secret.GroupBy(value => value).Where(value => value.Count() > 1).Sum(value => value.Count());
            string letter = "";
            int Loop = 0;
            Console.WriteLine("Welcome to guess a word game");
            while (true)
            {
                Loop++;
                Console.WriteLine("Guess a letter: ");
                letter = Console.ReadLine();
                if (DuplicateCount <= 1 && secret.Contains(letter))
                {
                    int position = Array.IndexOf(secret, letter);
                    if (position >= 0)
                    {
                        hidden[position] = letter;
                        Console.WriteLine($"Uncovering Secret Word : { string.Join(" ", hidden[0], hidden[1], hidden[2], hidden[3], hidden[4]) }");
                    }
                    if (Loop == secret.Length)
                    {
                        break;
                    }
                }
                else if (DuplicateCount >= 1 && secret.Distinct().Count() < secret.Length && secret.Contains(letter))
                {
                    /* This gives you an IGrouping interface carrying the key of the duplicate letter. This is not needed. I just added it in case you wanted to use it.  */
                    IGrouping<string, string>[] DuplicateValues = secret.GroupBy(value => value).Where(value => value.Count() > 1).ToArray();
                    for (int i = 0; i < secret.Length; i++)
                    {
                        if (secret[i] == letter)
                        {
                            hidden[i] = letter;
                        }
                    }
                    Console.WriteLine($"Uncovering Secret Word : { string.Join(" ", hidden[0], hidden[1], hidden[2], hidden[3], hidden[4]) }");
                }
                if (!hidden.Contains("_"))
                    break;
            }
            Console.WriteLine();

            // once broken out of the for loop it will inform the user if they have guessed the word correctly.
            // I have made this change to properly compare two arrays. The way you were doing it was not appropriate. Use Enumerable.SequenceEqual instead.
            if (Enumerable.SequenceEqual(secret, hidden))
            {
                Console.WriteLine("You have guessed the correct word!");
            }
            else
            {
                Console.WriteLine("unfortunately you have not gussed the correct word");
            }
            Console.ReadLine();
        }
There is lots of room for additional checking and housework. But it does what you want, and works well.

Of course, it can also be simplified with some minor adjustments. Happy programming.
 
Solution
With the code in post #7, the only way to break out of the infinite loop is if the user guesses the word correctly. Given that, then there is no need to check if the two array values are equal after the infinite loop. Just declare that the user has guessed the word correctly.

Now, on the other hand, if the user has a limited number of guesses, then an infinite loop is not the appropriate looping structure, and you'll need to retain the code that checks if the two array values are equal and declare whether the user has correctly guessed the word or not.

Personally, I think things would be simplified if a more appropriate data structure rather than an array of strings is used, but it's likely the OP is still on the learning curve with his school classes and they have not yet covered alternatives.
 
Given that, then there is no need to check if the two array values are equal after the infinite loop.
It wasn't my code to start with. And It's not my house keeping to do. It was what I used to make the example work as it was without making to many changes to the OP's source code.
Now, on the other hand, if the user has a limited number of guesses, then an infinite loop is not the appropriate looping structure
I didn't write it to be perfect, not would I ever try to. It's always best to give the OP a working piece that requires them to do their own edits and their own housekeeping. Reading the original request it never said anything about having X amount of tries. And it should be effortless to break out of a loop by implementing that into their code should that be something they want to do.

The OP was previously comparing arrays inappropriately with : if(secret == hidden) which is why I left that check in place for the purpose of the example, to show them how they should compare them instead.

And I don't always have the time to sit here and explain every piffling section in great detail.
 
Back
Top Bottom