So for the extra credit portion I decided add in the ability to choose the length of the word that you want go guess. I got hung up trying to figure out why a few things weren’t working but in the end got it figured all out.
BullCowCartridge.cpp
#include "BullCowCartridge.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "Misc/Char.h"
#include "Misc/CString.h"
void UBullCowCartridge::BeginPlay() // When the game starts
{
Super::BeginPlay();
const FString WordListPath = FPaths::ProjectContentDir() / TEXT("WordLists/HiddenWordList.txt");
FFileHelper::LoadFileToStringArrayWithPredicate(Isograms, *WordListPath, [](const FString& Word)
{
return Word.Len() >= 4 && Word.Len() <= 8 && IsIsogram(Word);
});
SetupGame();
}
void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter
{
if (bGameOver)
{
ClearScreen();
SetupGame();
}
else if (!bLengthSet)
{
RequestLength(Input);
if (bLengthSet)
{
InitializeGame();
}
}
else
{
ProcessGuess(Input);
}
}
void UBullCowCartridge::SetupGame()
{
bGameOver = false;
bLengthSet = false;
bIsInitialized = false;
FWordLength WordLength = ProcessLength();
WordMin = WordLength.Min;
WordMax = WordLength.Max;
PrintLine(TEXT("Welcome to Bull Cows!\n"));
PrintLine(TEXT("The goal is to guess an isogram of the\nlength of your choice.\n"));
PrintLine(TEXT("The shortest word is %i long."), WordMin);
PrintLine(TEXT("The longest word is %i long.\n"), WordMax);
PrintLine(TEXT("Please enter the length of a word you\nwould like to guess and hit enter."));
}
//Builds the array of words of the length that you chose, sets lives, sets HiddenWord
void UBullCowCartridge::InitializeGame()
{
IsogramsLength = LengthListBuild(Isograms);
HiddenWord = IsogramsLength[FMath::RandRange(0, IsogramsLength.Num() - 1)];
Lives = (HiddenWord.Len()) * 2;
bIsInitialized = true;
PrintLine(TEXT("Guess the %i letter word."), HiddenWord.Len());
PrintLine(TEXT("You have %i lives."), Lives);
PrintLine(TEXT("\nType in your guess and press enter to \ncontinue...")); // Prompt player for guess
}
void UBullCowCartridge::EndGame()
{
bGameOver = true;
PrintLine(TEXT("\nPress enter to play again..."));
}
void UBullCowCartridge::ProcessGuess(const FString& PlayerGuess)
{
//Check for correct guess.
if (PlayerGuess == HiddenWord)
{
ClearScreen();
PrintLine(TEXT("\nYou guessed correctly!"));
EndGame();
return;
}
//Check if guess is the correct number of characters.
if (PlayerGuess.Len() != HiddenWord.Len())
{
PrintLine(TEXT("The word is %i characters long!\nPlease enter a word with the correct\namount of characters...\n"), HiddenWord.Len());
return;
}
//Check if the guess is an isogram.
if (!IsIsogram(PlayerGuess))
{
PrintLine(TEXT("\nThe word you have entered is not an\nisogram..."));
PrintLine(TEXT("\nPlease guess again...\n"));
return;
}
PrintLine(TEXT("You did not guess correctly..."));
PrintLine(TEXT("You have %i lives left...\n "), --Lives);
//check for remaining lives.
if (Lives <= 0)
{
ClearScreen();
PrintLine(TEXT("You are out of lives!"));
PrintLine(TEXT("The word was... %s"), *HiddenWord);
PrintLine(TEXT("Better luck next time..."));
EndGame();
return;
}
//Show player the bulls and the cows
FBullCowCount BCCount = GetBullCows(PlayerGuess);
PrintLine(TEXT("You have %i Bulls and %i Cows"), BCCount.Bulls, BCCount.Cows);
}
// Checks that a word is an isogram.
bool UBullCowCartridge::IsIsogram(const FString& Word)
{
for (int32 Index = 0; Index < Word.Len() - 1; Index++)
{
for (int32 Comparison = Index + 1; Comparison < Word.Len(); Comparison++)
{
if (Word[Index] == Word[Comparison])
{
return false;
}
}
}
return true;
}
TArray<FString> UBullCowCartridge::GetValidWords(const TArray<FString>& WordList) const
{
TArray<FString> ValidWords;
for (FString WordInList : WordList)
{
if (WordInList.Len() >= 4 && WordInList.Len() <= 8 && IsIsogram(WordInList))
{
ValidWords.Emplace(WordInList);
}
}
return ValidWords;
}
//Returns the amount of Bulls and Cows in the guess made by the player
FBullCowCount UBullCowCartridge::GetBullCows(const FString& Guess) const
{
FBullCowCount Count;
for (int32 GuessIndex = 0; GuessIndex < Guess.Len(); GuessIndex++)
{
if (Guess[GuessIndex] == HiddenWord[GuessIndex])
{
Count.Bulls++;
continue;
}
for (int32 CowIndex = 0; CowIndex < Guess.Len(); CowIndex++)
{
if (Guess[GuessIndex] == HiddenWord[CowIndex])
{
Count.Cows++;
break;
}
}
}
return Count;
}
//Will check and return length of the shortest and longest word in the list
FWordLength UBullCowCartridge::ProcessLength() const
{
FWordLength Length;
//Checks for the longest word
for (int32 Index = 0; Index < Isograms.Num(); Index++)
{
if (Isograms[Index].Len() > Length.Max)
{
Length.Max = Isograms[Index].Len();
}
}
Length.Min = Length.Max;
//Checks for the shortest word
for (int32 Index = 0; Index < Isograms.Num(); Index++)
{
if (Isograms[Index].Len() <= Length.Min)
{
Length.Min = Isograms[Index].Len();
}
}
return Length;
}
//Checks that the length requested by the player is an integer and that it is within the valid range
void UBullCowCartridge::RequestLength(FString Input)
{
ChoiceInt = 0;
//Verifies that the input is an integer
for (int32 Index = 0; Index < Input.Len(); Index++)
{
if (isdigit(Input[Index]) == false)
{
bIsValidInt = false;
PrintLine(TEXT("You have not entered an integer..."));
return;
}
else
{
bIsValidInt = true;
}
}
//Atoi is only used after the input has been confirmed to be an integer as it does not return any errors.
ChoiceInt = FCString::Atoi(*Input);
//Verifies that the integer is within the Min and Max lenth of words.
if (ChoiceInt > WordMax || ChoiceInt < WordMin)
{
ClearScreen();
PrintLine(TEXT("The number you have entered is not within the valid range.\n"));
PrintLine(TEXT("The range is %i - %i"), WordMin, WordMax);
bIsValidInt = false;
return;
}
//PrintLine(TEXT("The number entered: %i"), ChoiceInt);
bLengthSet = true;
ClearScreen();
return;
}
// Returns the words that match the requested length from the list of all isograms
TArray<FString> UBullCowCartridge::LengthListBuild(const TArray<FString>& IsogramsList) const
{
TArray<FString> ValidWords;
for (int32 Index = 0; Index < IsogramsList.Num(); Index++)
{
if (IsogramsList[Index].Len() == ChoiceInt)
{
ValidWords.Emplace(IsogramsList[Index]);
}
}
return ValidWords;
}
BullCowCartridge.h
#pragma once
#include "CoreMinimal.h"
#include "Console/Cartridge.h"
#include "BullCowCartridge.generated.h"
struct FBullCowCount
{
int32 Bulls = 0;
int32 Cows = 0;
};
struct FWordLength
{
int32 Min = 0;
int32 Max = 0;
};
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BULLCOWGAME_API UBullCowCartridge : public UCartridge
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void OnInput(const FString& Input) override;
FWordLength ProcessLength() const;
void RequestLength(FString Input);
void ProcessGuess(const FString& PlayerGuess);
void SetupGame();
void EndGame();
void InitializeGame();
static bool IsIsogram(const FString& Word);
TArray <FString> GetValidWords(const TArray<FString>& WordList) const;
TArray <FString> LengthListBuild(const TArray<FString>& IsogramList) const;
FBullCowCount GetBullCows(const FString& Guess) const;
// Your declarations go below!
private:
int32 Lives;
int32 WordMin = 0;
int32 WordMax = 0;
int32 ChoiceInt;
FString HiddenWord;
bool bIsValidInt;
bool bLengthSet;
bool bGameOver;
bool bIsInitialized;
TArray<FString> Words;
TArray<FString> Isograms;
TArray<FString> IsogramsLength;
};