fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <utility>
  4. #include <vector>
  5. #include <functional>
  6.  
  7. using namespace std;
  8.  
  9. class Guess
  10. {
  11. public:
  12. const std::string& GetGuess() const
  13. {
  14. return(m_guess);
  15. }
  16.  
  17. static Guess TakeGuess()
  18. {
  19. Guess g;
  20. std::cin >> g.m_guess;
  21. return(std::move(g));
  22. }
  23.  
  24. private:
  25. std::string m_guess;
  26. };
  27.  
  28. template<char L>
  29. class Letter
  30. {
  31. public:
  32. Letter():
  33. m_char(L)
  34. {
  35. }
  36.  
  37. char GetChar() const
  38. {
  39. return(m_char);
  40. }
  41.  
  42. bool operator==(const Letter<L>& other) const
  43. {
  44. return(other.m_char == m_char);
  45. }
  46.  
  47. protected:
  48. const char m_char;
  49. };
  50.  
  51. class MutableLetter: public Letter<0>
  52. {
  53. public:
  54. MutableLetter():
  55. Letter()
  56. {
  57. }
  58.  
  59. void SetChar(char c)
  60. {
  61. const_cast<char&>(m_char) = c;
  62. }
  63. };
  64.  
  65. class Word
  66. {
  67. public:
  68. Word()
  69. {
  70. }
  71.  
  72. template<char L>
  73. void AppendLetter(const Letter<L>& letter)
  74. {
  75. m_letters.emplace_back();
  76. reinterpret_cast<MutableLetter&>(m_letters.back()).SetChar(letter.GetChar());
  77. }
  78.  
  79. template<char L>
  80. std::vector<size_t> HasLetter(const Letter<L>& letter) const
  81. {
  82. std::vector<size_t> indices;
  83. for(size_t i = 0; i < m_letters.size(); ++i)
  84. {
  85. if(m_letters[i] == static_cast<const Letter<0>&>(letter))
  86. {
  87. indices.emplace_back(i);
  88. }
  89. }
  90. return(indices);
  91. }
  92.  
  93. size_t Count() const
  94. {
  95. return(m_letters.size());
  96. }
  97.  
  98. template<char L>
  99. void SetLetter(size_t index, const Letter<L>& letter)
  100. {
  101. static_cast<MutableLetter&>(m_letters[index]).SetChar(letter.GetChar());
  102. }
  103.  
  104. bool MissingLetter(size_t index) const
  105. {
  106. return(m_letters[index].GetChar() == '_');
  107. }
  108.  
  109. private:
  110. std::vector<Letter<0>> m_letters;
  111.  
  112. friend class WordPrinter;
  113. };
  114.  
  115. class WordPrinter
  116. {
  117. public:
  118. WordPrinter(const Word& word):
  119. m_word(word)
  120. {
  121. }
  122.  
  123. void PrintWord() const
  124. {
  125. for(const Letter<0>& letter : m_word.m_letters)
  126. {
  127. // const correctness!
  128. const char temp[2] = { letter.GetChar(), '\0' };
  129. cout << temp;
  130. }
  131. cout << endl;
  132. }
  133.  
  134. private:
  135. const Word& m_word;
  136. };
  137.  
  138. class GuessTracker
  139. {
  140. public:
  141. GuessTracker(size_t numGuesses):
  142. m_numGuesses(numGuesses)
  143. {
  144. }
  145.  
  146. bool RunGuessLoop(std::function<bool()> guessFn)
  147. {
  148. bool result = true;
  149. if(m_numGuesses > 0)
  150. {
  151. while(m_numGuesses --> 0)
  152. {
  153. result = guessFn();
  154. if(result || m_numGuesses == 0)
  155. {
  156. break;
  157. }
  158. }
  159. }
  160. return(result);
  161. }
  162.  
  163. private:
  164. size_t m_numGuesses;
  165. };
  166.  
  167. class HangmanGame
  168. {
  169. public:
  170. HangmanGame(size_t numGuesses, std::string secret):
  171. m_guessTracker(numGuesses),
  172. m_secret()
  173. {
  174. for(char c : secret)
  175. {
  176. Letter<0> letter;
  177. reinterpret_cast<MutableLetter&>(letter).SetChar(c);
  178. m_secret.AppendLetter(letter);
  179.  
  180. // Reuse letter for efficiency
  181. reinterpret_cast<MutableLetter&>(letter).SetChar('_');
  182. m_answer.AppendLetter(letter);
  183. }
  184. }
  185.  
  186. int Run()
  187. {
  188. WordPrinter printer(m_answer);
  189. size_t lettersRemaining = m_secret.Count();
  190. const bool result = m_guessTracker.RunGuessLoop([&]()
  191. {
  192. cout << "Enter a letter. ";
  193. printer.PrintWord();
  194. const Guess guess = Guess::TakeGuess();
  195. MutableLetter guessLetter;
  196. guessLetter.SetChar(guess.GetGuess().front());
  197.  
  198. size_t occurrences = 0;
  199. const auto indices = m_secret.HasLetter(guessLetter);
  200.  
  201. for (size_t ind : indices)
  202. {
  203. if(m_answer.MissingLetter(ind))
  204. {
  205. m_answer.SetLetter(ind, guessLetter);
  206. occurrences += 1;
  207. }
  208. }
  209. if (occurrences == 0)
  210. {
  211. // bummer
  212. cout << "Letter not found, try again" << endl;
  213. }
  214.  
  215. lettersRemaining -= occurrences;
  216. if (lettersRemaining == 0)
  217. {
  218. return(true);
  219. }
  220.  
  221. return(false);
  222. });
  223. if(result)
  224. {
  225. cout << "Winner" << endl;
  226. }
  227. else
  228. {
  229. cout << "Loser" << endl;
  230. }
  231.  
  232. WordPrinter secretPrinter(m_secret);
  233. cout << "The word was ";
  234. secretPrinter.PrintWord();
  235. return(0);
  236. }
  237.  
  238. private:
  239. GuessTracker m_guessTracker;
  240. Word m_secret;
  241. Word m_answer;
  242. };
  243.  
  244. int main()
  245. {
  246. HangmanGame game(7, "hi");
  247. return(game.Run());
  248. }
  249.  
Success #stdin #stdout 0s 3476KB
stdin
e
g
h
j
k
i
stdout
Enter a letter. __
Letter not found, try again
Enter a letter. __
Letter not found, try again
Enter a letter. __
Enter a letter. h_
Letter not found, try again
Enter a letter. h_
Letter not found, try again
Enter a letter. h_
Winner
The word was hi