Last active
January 27, 2017 00:40
-
-
Save telmotrooper/4508023e7f9ffae7c613c61cac30d7ed to your computer and use it in GitHub Desktop.
BullCowGame with difficulty settings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is the implementation of the FBullCowGame header. | |
*/ | |
#pragma once | |
#include "FBullCowGame.h" | |
#include <map> | |
#define TMap std::map | |
FBullCowGame::FBullCowGame() {Reset();} | |
int32 FBullCowGame::getCurrentTry() const { return myCurrentTry;} | |
int32 FBullCowGame::getHiddenWordLength() const {return static_cast<int>(myHiddenWord.length());} | |
void FBullCowGame::setHiddenWordBasedOnLength(int32 length) { | |
switch(length) { | |
case 3: myHiddenWord = "bat"; break; | |
case 4: myHiddenWord = "lane"; break; | |
case 5: myHiddenWord = "ocean"; break; | |
case 6: myHiddenWord = "planet"; break; | |
case 7: myHiddenWord = "panther"; break; | |
} | |
} | |
bool FBullCowGame::isGameWon() const {return bGameIsWon;} | |
int32 FBullCowGame::getMaxTries() const { | |
TMap<int32, int32> wordLengthToMaxTries{{3,4}, {4,7}, {5,10}, {6,15}, {7,20}}; | |
return static_cast<int>(wordLengthToMaxTries[myHiddenWord.length()]); | |
} | |
void FBullCowGame::Reset() { | |
myCurrentTry = 1; | |
bGameIsWon = false; | |
} | |
bool FBullCowGame::isIsogram(FString guess) const { | |
if (guess.length() <= 1) {return true;} | |
TMap<char, bool> letterSeen; | |
for (auto letter : guess) { | |
letter = tolower(letter); | |
if (letterSeen[letter]) { // if the letter has been seen before, the guess is not an isogram | |
return false; | |
} else { | |
letterSeen[letter] = true; | |
} | |
} | |
return true; | |
} | |
bool FBullCowGame::isLowercase(FString guess) const { | |
for (auto letter : guess) { | |
if (!islower(letter)) {return false;} | |
} | |
return true; | |
} | |
EGuessStatus FBullCowGame::checkGuessValidity(FString guess) const { | |
if(!isIsogram(guess)) { | |
return EGuessStatus::NOT_ISOGRAM; | |
} else if (!isLowercase(guess)) { | |
return EGuessStatus::NOT_LOWERCASE; | |
} else if (guess.length() != getHiddenWordLength()) { | |
return EGuessStatus::WRONG_LENGTH; | |
} else { | |
return EGuessStatus::OK; | |
} | |
} | |
// receives a valid guess, increments turn and returns count | |
FBullCowCount FBullCowGame::submitValidGuess(FString guess) { | |
myCurrentTry++; | |
FBullCowCount bullCowCount; | |
int32 hiddenWordLength = getHiddenWordLength(); | |
for (int32 i = 0; i < guess.length(); i++) { | |
for(int32 j = 0; j < hiddenWordLength; j++) { | |
if(guess[i] == myHiddenWord[j]) { | |
if (i == j) { | |
bullCowCount.Bulls++; | |
} else { | |
bullCowCount.Cows++; | |
} | |
} | |
} | |
} | |
if(bullCowCount.Bulls == hiddenWordLength) {bGameIsWon = true;} | |
return bullCowCount; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This acts as the model in a MVC pattern and is responsible | |
for managing data, logic and rules of the application. | |
*/ | |
#pragma once | |
#include <string> | |
using FString = std::string; | |
using int32 = int; | |
// all values initialized to zero | |
struct FBullCowCount { | |
int32 Bulls = 0; | |
int32 Cows = 0; | |
}; | |
enum class EGuessStatus { | |
INVALID_STATUS, | |
OK, | |
NOT_ISOGRAM, | |
WRONG_LENGTH, | |
NOT_LOWERCASE | |
}; | |
class FBullCowGame { | |
public: | |
FBullCowGame(); | |
int32 getMaxTries() const; | |
int32 getCurrentTry() const; | |
int32 getHiddenWordLength() const; | |
void setHiddenWordBasedOnLength(int32); | |
bool isGameWon() const; | |
void Reset(); | |
EGuessStatus checkGuessValidity(FString) const; | |
// provide a method for counting bulls and cows, and incrementing try number | |
// count bulls & cows and increase try number, assuming a valid guess | |
FBullCowCount submitValidGuess(FString); | |
// ^^ Please try and ignore this and focus on the interface above ^^ | |
private: | |
int32 myCurrentTry; | |
FString myHiddenWord; | |
bool bGameIsWon; | |
bool isIsogram(FString) const; | |
bool isLowercase(FString) const; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is the console executable that makes use of the BullCow class. | |
This acts as the view in a MVC pattern and is responsible for all | |
user interaction. For game logic see the FBullCowGame class. | |
*/ | |
#pragma once | |
#include <iostream> | |
#include <string> | |
#include "FBullCowGame.h" | |
#define cout std::cout | |
#define cin std::cin | |
#define endl std::endl | |
// to make syntax Unreal friendly | |
using FText = std::string; | |
using int32 = int; | |
void printIntro(); | |
void setDifficulty(); | |
void playGame(); | |
void printGameSummary(); | |
FText getValidGuess(); | |
bool askToPlayAgain(); | |
FBullCowGame BCGame; | |
bool bPlayAgain = false; | |
int main() { | |
do { | |
printIntro(); | |
setDifficulty(); | |
playGame(); | |
bPlayAgain = askToPlayAgain(); | |
} while (bPlayAgain); | |
return 0; | |
} | |
void printIntro() { | |
cout << "Welcome to Bulls and Cows, a fun word game.\n\n"; | |
cout << " } { ___ " << endl; | |
cout << " (o o) (o o) " << endl; | |
cout << " /-------\\ / \\ /-------\\ " << endl; | |
cout << " / | BULL |O O| COW | \\ " << endl; | |
cout << " * |-,--- | |------| * " << endl; | |
cout << " ^ ^ ^ ^ " << "\n\n"; | |
} | |
void setDifficulty() { | |
FText difficultyInput = "0"; | |
int32 difficultyValue = 0; | |
bool loop = true; | |
do { | |
cout << "Choose the number of letters of the isogram (between 3 and 7): "; | |
getline(cin, difficultyInput); | |
cout << endl; | |
try { | |
difficultyValue = stoi(difficultyInput); // try to convert input to integer | |
if (difficultyValue < 3 || difficultyValue > 7) { | |
cout << "\"" << difficultyInput << "\"" << " is not between 3 and 7.\n\n"; | |
} else { | |
loop = false; // exit loop | |
} | |
} catch(std::invalid_argument&) { // if a non-numeric value is entered | |
cout << "\"" << difficultyInput << "\"" << " is not a number.\n\n"; | |
} | |
} while (loop); | |
BCGame.setHiddenWordBasedOnLength(difficultyValue); | |
cout << "Can you guess the " << BCGame.getHiddenWordLength(); | |
cout << " letter isogram I'm thinking of?\n\n"; | |
} | |
void playGame() { | |
BCGame.Reset(); | |
int32 maxTries = BCGame.getMaxTries(); | |
// loop for the number of turns asking for guesses | |
while(!BCGame.isGameWon() && BCGame.getCurrentTry() <= maxTries) { | |
//for (int32 count = 1; count <= maxTries; count++) { | |
FText guess = getValidGuess(); | |
// submit valid guess to the game and receive count | |
FBullCowCount bullCowCount = BCGame.submitValidGuess(guess); | |
cout << "Bulls: " << bullCowCount.Bulls; | |
cout << " Cows: " << bullCowCount.Cows << "\n\n"; | |
} | |
printGameSummary(); | |
} | |
void printGameSummary() { | |
if (BCGame.isGameWon()) { | |
cout << "You won!\n\n"; | |
} else { | |
cout << "Bad luck!\n\n"; | |
} | |
} | |
FText getValidGuess() { | |
EGuessStatus status = EGuessStatus::INVALID_STATUS; | |
FText guess = ""; | |
do { | |
int32 currentTry = BCGame.getCurrentTry(); | |
cout << "Try " << currentTry << " of " << BCGame.getMaxTries(); | |
cout << ". Enter your guess: "; | |
getline(cin, guess); | |
status = BCGame.checkGuessValidity(guess); | |
switch (status) { | |
case EGuessStatus::WRONG_LENGTH: | |
cout << "Please enter a " << BCGame.getHiddenWordLength() << " letter word.\n\n"; | |
break; | |
case EGuessStatus::NOT_ISOGRAM: | |
cout << "Please enter a word without repeating letters.\n\n"; | |
break; | |
case EGuessStatus::NOT_LOWERCASE: | |
cout << "Please enter all lowercase letters.\n\n"; | |
break; | |
} | |
} while(status != EGuessStatus::OK); | |
return guess; | |
} | |
bool askToPlayAgain() { | |
cout << "Do you wanna play again (y/n)? "; | |
FText response = ""; | |
getline(cin, response); | |
cout << endl; | |
return (response[0] == 'y' || response[0] == 'Y'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment