0

I'm a beginner to the STL and I used it to make a simple hangman project. Full code here: https://github.com/SamtheSaint/Hangman.

I needed to detect multiple occurrences of letters in a vector but I could not and ended up working around it to finish the program. Is there a simpler way to do this?

iter = find(gameWord.begin(), gameWord.end(), playGuess);
if (iter == gameWord.end()) {
  guesses--;
}
while (iter != gameWord.end()) {
  iter = find(gameWord.begin(), gameWord.end(), playGuess);
  if (iter != gameWord.end()) {
    int index = distance(gameWord.begin(), iter);
    hiddenWord[index] = playGuess;
    *iter = '0'; // so program can find the next one
  }
}

I end up destroying gameWord vector so I have to make a copy(which I call checkWord) at the beginning of the loop it's in so I can compare it later to hiddenWord.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • what do you mean with "detect"? remove the duplicates? return `true` if at least one duplicate was found? the code doesn't really speak for itself. – Stack Danny Jul 16 '19 at 12:57
  • *I needed to detect multiple occurrences of letters in a vector* -- I don't quite understand. You mean the vector that has the answer already filled in? If so, then why wait until the middle of the game to detect if there are duplicates? You should have set up the proper structure beforehand to tell you where the duplicates are. For example, a `std::unordered_map>` already initialized with the letter(s) and positions they are found. – PaulMcKenzie Jul 16 '19 at 13:00
  • 1
    Please provide [mcve] and an example of the desired behaviour. Are you perhaps looking for `std::replace_if`? – Quimby Jul 16 '19 at 13:00
  • Honestly, I think a `unordered_map>`, where the char is the letter, and the vector denotes the positions where the letter is located is a better structure than just a vector for a program like this. When the user guesses a correct letter, then it becomes very easy to know what positions to fill in since that information is in the map. No need to search. – PaulMcKenzie Jul 16 '19 at 13:05
  • [See this simple example using a map](http://coliru.stacked-crooked.com/a/f4010f9d2c12a713). The only thing that is done is to search for the letter in the map. If found, grab all of the positions and fill those slots in the output vector. I know you say you're new to STL, but this is mostly about thinking about what type of data structure fits the best -- you don't need to know STL for that. – PaulMcKenzie Jul 16 '19 at 13:19
  • yeah, the unordered map is perfect for what I'm doing. –  Jul 16 '19 at 13:21
  • Why `std::map`? He writes simple game [hangman](https://en.wikipedia.org/wiki/Hangman_(game)), so map here is just overkill. Everybody get to focused on providing universal solution. – Marek R Jul 16 '19 at 13:27
  • .@MarekR -- Compare your answer with the code at the link. What is easier is totally a matter of opinion. It took just a few lines to fill in the guessed string with all the missing leters without a search. So what is overkill here? Longer code or shorter code that gets to the point? Also instead of implying he "doesn't need map", it is more professional to state that you have another solution. – PaulMcKenzie Jul 16 '19 at 20:03

1 Answers1

0

You do not need std::map.
You just need two std::string (one which is expression to guess, the other one is the pattern shown to the player) which will be kept in synchronization. This mean you should enclose them in class.

Do not make thing more complicated then it is necessary. This is quite simple:

class Hangman {
public:
    constexpr SecretChar = '_';

    Hangman(const std::string& secret)
       : mSecret(secret)
    {
       provideMask();
    }

    bool guess(char ch) {
       auto index = mSecret.find(ch);
       if (index == std::string::npos) return false;
       if (already_guessed(index)) return false;
       updateMaskWith(ch);
       return true;
    }

    std::string mask() const {
       return mMask;
    }

private:
    void provideMask() {
        mask = mSecret;
        std::replace_if(mMask.begin(), mMask.end(), std::isalpha, SecretChar);
    }

    bool already_guessed(int index) {
        return mMask[index] != SecretChar;
    }

    void updateMaskWith(char ch) {
        auto index = mSecret.find(ch);
        while (index == std::string::npos) {
            mMask[index] = ch;
            index = mSecret.find(ch, index + 1);
        }
    }

private:
    std::string mSecret;
    std::string mMask;
};

Now write seperate code which will use this and keep score and you are almost done.

Marek R
  • 32,568
  • 6
  • 55
  • 140