#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <functional>
using namespace std;
class Guess
{
public:
const std::string& GetGuess() const
{
return(m_guess);
}
static Guess TakeGuess()
{
Guess g;
std::cin >> g.m_guess;
return(std::move(g));
}
private:
std::string m_guess;
};
template<char L>
class Letter
{
public:
Letter():
m_char(L)
{
}
char GetChar() const
{
return(m_char);
}
bool operator==(const Letter<L>& other) const
{
return(other.m_char == m_char);
}
protected:
const char m_char;
};
class MutableLetter: public Letter<0>
{
public:
MutableLetter():
Letter()
{
}
void SetChar(char c)
{
const_cast<char&>(m_char) = c;
}
};
class Word
{
public:
Word()
{
}
template<char L>
void AppendLetter(const Letter<L>& letter)
{
m_letters.emplace_back();
reinterpret_cast<MutableLetter&>(m_letters.back()).SetChar(letter.GetChar());
}
template<char L>
std::vector<size_t> HasLetter(const Letter<L>& letter) const
{
std::vector<size_t> indices;
for(size_t i = 0; i < m_letters.size(); ++i)
{
if(m_letters[i] == static_cast<const Letter<0>&>(letter))
{
indices.emplace_back(i);
}
}
return(indices);
}
size_t Count() const
{
return(m_letters.size());
}
template<char L>
void SetLetter(size_t index, const Letter<L>& letter)
{
static_cast<MutableLetter&>(m_letters[index]).SetChar(letter.GetChar());
}
bool MissingLetter(size_t index) const
{
return(m_letters[index].GetChar() == '_');
}
private:
std::vector<Letter<0>> m_letters;
friend class WordPrinter;
};
class WordPrinter
{
public:
WordPrinter(const Word& word):
m_word(word)
{
}
void PrintWord() const
{
for(const Letter<0>& letter : m_word.m_letters)
{
// const correctness!
const char temp[2] = { letter.GetChar(), '\0' };
cout << temp;
}
cout << endl;
}
private:
const Word& m_word;
};
class GuessTracker
{
public:
GuessTracker(size_t numGuesses):
m_numGuesses(numGuesses)
{
}
bool RunGuessLoop(std::function<bool()> guessFn)
{
bool result = true;
if(m_numGuesses > 0)
{
while(m_numGuesses --> 0)
{
result = guessFn();
if(result || m_numGuesses == 0)
{
break;
}
}
}
return(result);
}
private:
size_t m_numGuesses;
};
class HangmanGame
{
public:
HangmanGame(size_t numGuesses, std::string secret):
m_guessTracker(numGuesses),
m_secret()
{
for(char c : secret)
{
Letter<0> letter;
reinterpret_cast<MutableLetter&>(letter).SetChar(c);
m_secret.AppendLetter(letter);
// Reuse letter for efficiency
reinterpret_cast<MutableLetter&>(letter).SetChar('_');
m_answer.AppendLetter(letter);
}
}
int Run()
{
WordPrinter printer(m_answer);
size_t lettersRemaining = m_secret.Count();
const bool result = m_guessTracker.RunGuessLoop([&]()
{
cout << "Enter a letter. ";
printer.PrintWord();
const Guess guess = Guess::TakeGuess();
MutableLetter guessLetter;
guessLetter.SetChar(guess.GetGuess().front());
size_t occurrences = 0;
const auto indices = m_secret.HasLetter(guessLetter);
for (size_t ind : indices)
{
if(m_answer.MissingLetter(ind))
{
m_answer.SetLetter(ind, guessLetter);
occurrences += 1;
}
}
if (occurrences == 0)
{
// bummer
cout << "Letter not found, try again" << endl;
}
lettersRemaining -= occurrences;
if (lettersRemaining == 0)
{
return(true);
}
return(false);
});
if(result)
{
cout << "Winner" << endl;
}
else
{
cout << "Loser" << endl;
}
WordPrinter secretPrinter(m_secret);
cout << "The word was ";
secretPrinter.PrintWord();
return(0);
}
private:
GuessTracker m_guessTracker;
Word m_secret;
Word m_answer;
};
int main()
{
HangmanGame game(7, "hi");
return(game.Run());
}