'How can I manage duplicate letters in Wordle Game (JavaFx)?

In my algorithm to compare the secret word with the guessed word, I need to manage the duplicated letters. For example,
if the secret word is newly and the guessed word is newer, the output of this should be "GGGWW" (G = green(Correct Place), W = White(The Letter isn't in the secret word)),
but instead my algorithm down below outputs "GGGYW" (Y = Yellow(Letter is in the word but not the right place)).

        for (int i = 0; i < 5; i++) {
            if (secret.charAt(i) == prop.charAt(i)) {
                status[i] = LetterStatus.IN;
            } else if (secret.contains(Character.toString(prop.charAt(i)))) {
                status[i] = LetterStatus.OK;
            } else {
                status[i] = LetterStatus.NOTIN;
            }
        }
        return status;

secret = secretword, the array status is an enum of (IN, OK, NOTIN), so the letter and prop status is the guessed word.

Any ideas on how to modify this code to solve my problem



Solution 1:[1]

You have to take the number of occurrences into account. So, process the exact matches first, recording the letters not found so far. For each other occurrence in the guess, remove the letter from the recorded letters, so that you will not match it again. E.g.

ArrayList<Character> missing = new ArrayList<>();
for(int i = 0; i < 5; i++) {
    if(secret.charAt(i) == prop.charAt(i)) {
        status[i] = LetterStatus.IN;
    }
    else missing.add(secret.charAt(i));
}
if(!missing.isEmpty()) {
  for(int i = 0; i < 5; i++) {
      if(secret.charAt(i) != prop.charAt(i)) {
        Object ch = prop.charAt(i); // ensure to use remove(Object) not remove(int)
        status[i] = missing.remove(ch)? LetterStatus.OK: LetterStatus.NOTIN;
      }
  }
}

For large data, you’d use something like a Map<Character,Integer> to record the number of occurrences for each element, but since we have at most five elements here, using an ArrayList is simpler while providing reasonable performance. It’s just important to keep in mind that this approach would not scale to other problems.

Solution 2:[2]

The simplest seems to be just to override matched letter in a secret every time secret character matches prop character and then check for the letters whether they're in or not in the word

 for (int i = 0; i < 5; i++) {
     if (secret.charAt(i) == prop.charAt(i)) {
         status[i] = LetterStatus.IN;
         secret = secret.substring(0, i) + "-" + secret.substring(i+1); // or any other invalid character that will not be provided by user
     }
 }

 for (int i = 0; i < 5; i++) {
     if(status[i] == null) {
        if (secret.contains(Character.toString(prop.charAt(i)))) {
            status[i] = LetterStatus.OK;
        } else {
            status[i] = LetterStatus.NOTIN;
        }
     }
  }

  return status;

There is additional question how would you like to treat repeating characters that are yellow (let's say the user provided newee - should both e be yellow or only one) and maybe you'd need to tune up a little bit this code

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Holger
Solution 2 m.antkowicz