Justin Day
Justin Day

Reputation: 119

How to get index of all matching chars in char array?

I am working on a simple hangman program. I have most of the code working, but I am having trouble figuring out how to get the index of multiple matching chars in a char array. For example, I have a word "sushi" converted to a char array. If the user guesses an "s" then all "s" in the char array should be shown. The way that my code is, I actually have two char arrays of the same length. The first array holds the chars of the word to guess, while the second array holds question marks. My code should iterate through the first array and return the index of each element in the array that matches the user guess. Then, the code inserts the user guess at each specified index and displays the second array for the user. Unfortunately, only the first occurrence is changed in the second array, so only the first index is returned from the match query. The problematic code is as follows:

            //check if char array contains the user input
            if (guessThis.Contains(Convert.ToChar(textBox1.Text)))
            {
                //save user input as char
                char userGuess = Convert.ToChar(textBox1.Text);
                //iterate through first char array
                for (int i = 0; i < guessThis.Length - 1; i++ )
                {
                    //check each element in the array
                    //probably don't need both for and foreach loops
                    foreach (char c in guessThis)
                    {
                        //get index of any element that contains the userinput
                        var getIndex = Array.IndexOf(guessThis, c);
                        //check if the element matches the user guess
                        if (c == userGuess)
                        {
                            //insert the userguess into the index
                            displayAnswer[getIndex] = userGuess;

                        }
                    }

                }
                //update the display label
                answerLabel.Text = new string(displayAnswer);

SOLVED: Working off of the example in the selected answer, I updated my code as:

                //check if char array contains the user input
            if (guessThis.Contains(Convert.ToChar(textBox1.Text)))
            {
                //save user input as char
                char userGuess = Convert.ToChar(textBox1.Text);
                string maybeThis = textBox1.Text;
                string tryThis = new string(guessThis);
                foreach (Match m in Regex.Matches(tryThis, maybeThis))
                {
                    displayAnswer[m.Index] = userGuess;
                }
                answerLabel.Text = new string(displayAnswer);
            }

Upvotes: 1

Views: 9880

Answers (5)

MelnikovI
MelnikovI

Reputation: 1045

Try Regex.Matches to build regex expression and find all matches and their positions.

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = "a*";
      string input = "abaabb";

      foreach (Match m in Regex.Matches(input, pattern)) 
         Console.WriteLine("'{0}' found at index {1}.", 
                           m.Value, m.Index);
   }
}
// The example displays the following output:
//       'a' found at index 0.
//       '' found at index 1.
//       'aa' found at index 2.
//       '' found at index 4.
//       '' found at index 5.
//       '' found at index 6.`

http://msdn.microsoft.com/en-gb/library/system.text.regularexpressions.regex.matches(v=vs.110).aspx

Upvotes: 1

dbc
dbc

Reputation: 116826

You could do something like this (made generic for clarity):

    public static IEnumerable<int> AllIndexesOfAny<T>(this IList<T> list, IEnumerable<T> ofAny)
    {
        return Enumerable.Range(0, list.Count).Where(i => ofAny.Contains(list[i]));
    }

If performance becomes an issue, you could replace the IEnumerable<T> ofAny with a HashSet.

Update

Just read your code more closely and realized you are indexing through guessThis, and for each character in guessThis, finding its index in guessThis and checking whether it matches thisGuess. This is unnecessary. The simplest non-generic way to find all character indices in guessThis matching userGuess is probably:

var matches = Enumerable.Range(0, guessThis.Length).Where(i => guessThis[i] == userGuess);

Additional note

By the way, it probably doesn't matter for your application, but some non-ASCII Unicode characters in .Net are actually represented by surrogate pairs of chars. (There are also diacritical combining characters that modify the preceding character.) In an "internationalized" hangman game you might want to handle surrogate pairs by converting them to UTF32 code points:

    public static IEnumerable<KeyValuePair<int, int>> Utf32IndexedCodePoints(this string s, int index)
    {
        for (int length = s.Length; index < length; index++)
        {
            yield return new KeyValuePair<int, int>(index, char.ConvertToUtf32(s, index));
            if (char.IsSurrogatePair(s, index))
                index++;
        }
    }

Upvotes: 0

anefeletos
anefeletos

Reputation: 702

Try Something like this:

        char userGuess = Convert.ToChar(textBox1.Text);
        char[] displayAnswer = answerLabel.Text.ToCharArray();

        for (int n = 0; n < displayAnswer.Length; n++)
        {
            if (guessThis[n] == userGuess)
            {
                displayAnswer[n] = userGuess;
                }
        }
        answerLabel.Text = new string(displayAnswer);

A simple approach

Upvotes: 0

Shimi Ezra
Shimi Ezra

Reputation: 127

I think the problem is with the method: var getIndex = Array.IndexOf(guessThis, c); because it return the first location. You can just use the index you have in the for loop

Upvotes: 1

Tianyun Ling
Tianyun Ling

Reputation: 1097

Because your:

var getIndex = Array.IndexOf(guessThis, c);

always return the first occurance of character.

Your second for loop and the getIndex is useless, a clearer code could be:

        for (int i = 0; i < guessThis.Length - 1; i++ )
        {
            //check if the element matches the user guess
            if (c == userGuess[i])
            {
                //insert the userguess into the index
                displayAnswer[i] = userGuess;
            }
        }

Also, your code allows user to input multiple characters into the textBox1. I think in this kind of game, only one character should be guessed each time. So I suggest your confine your input.

Upvotes: 1

Related Questions