The IsIsogram code which Mike showed in the course has nested for loops. Two nested for loops make the algorithm an O(n^2) algorithm. Here is my proposed alternative which is a O(n) algorithm. It makes use of the STL container bit-set. Perhaps it was too early to introduce STL containers, but for those who are familiar with STL containers here is my implementation with only one for loop. Though for small strings an O(n^2) algorithm is not perceptibly slower than an O(n) algorithm if the IsIsogram function is going to be called on the entire Webster dictionary the difference will be quite noticeable.
bool UBullCowCartridge::IsIsogram(FString Word)
{
std::bitset<26> AlphabetUsed;
for (int32 WordIndex = 0; WordIndex < Word.Len(); WordIndex++)
{
char C = Word[WordIndex];
PrintLine(TEXT(“checking for %c”),C);
if (AlphabetUsed.test(C - ‘a’))
{
PrintLine(TEXT("%c is repeated"),C);
return false;
}
else
{
AlphabetUsed.set(C - ‘a’);
PrintLine(TEXT(“setting bit number %i”),C - ‘a’);
}
}
return true;
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "BullCowCartridge.h"
void UBullCowCartridge::BeginPlay() // When the game starts
{
Super::BeginPlay();
// PrintLine(TEXT("Begin.")); // Debug line
// PrintLine(TEXT("The hidden word is: %s.\nIt is %i characters long."), *HiddenWord, HiddenWord.Len()); // Debug line
SetupGame(); // setting up a first game - word, lives, points, instructions for player and asking for word
}
void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter
{
if (bGameOver) // if (true), the player guess was correct, set up a new word
{
ClearScreen();
SetupGame(); // set up a new game
}
else // Comparing answer
{
ProcessGuess(Input);
}
}
void UBullCowCartridge::SetupGame()
{
//PrintLine(TEXT("The hidden word is: %s.\nIt is %i characters long."), *HiddenWord, HiddenWord.Len()); // Debug line
HiddenWord = TEXT("above");
Lives = HiddenWord.Len();
// Points = 0;
bGameOver = false;
// Welcome player, explaining rules
PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
PrintLine(TEXT(""));
PrintLine(TEXT("This is a Bull Cows game."));
PrintLine(TEXT("Letter in the right place = Bull."));
PrintLine(TEXT("Letter in the wrong place = Cow."));
PrintLine(TEXT(""));
// Asking player for guess, show lives, letters, points
PrintLine(TEXT("Guess the %i letter isogram and press ENTER"), HiddenWord.Len());
PrintLine(TEXT(""));
}
void UBullCowCartridge::EndGame()
{
bGameOver = true;
PrintLine(TEXT(""));
PrintLine(TEXT("Press Enter to play agin."));
}
void UBullCowCartridge::ProcessGuess(FString Guess)
{
if (Lives == 1) // player dont have lives
{
--Lives; // this is for showing player that its 0 lives
ClearScreen();
PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
PrintLine(TEXT(""));
PrintLine(TEXT(""));
PrintLine(TEXT("Wrong answer. All lives lost!"));
PrintLine(TEXT("The hidden word was: %s"), *HiddenWord);
Points = 0;
EndGame();
return;
}
// if (!Isogram()) // when the word is not an isogram
// {
// --Lives; // decreasing lives for wrong answer
// ClearScreen();
// PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
// PrintLine(TEXT(""));
// PrintLine(TEXT(""));
// PrintLine(TEXT("This is not an isogram. You lost 1 life."));
// PrintLine(TEXT("No repeating letters!"));
// PrintLine(TEXT("Type your guess agin."));
// PrintLine(TEXT(""));
// return;
// }
if (HiddenWord.Len() != Guess.Len()) // when player inputs incorrect word length
{
--Lives; // decreasing lives for wrong answer
ClearScreen();
PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
PrintLine(TEXT(""));
PrintLine(TEXT(""));
PrintLine(TEXT("Incorrect word length. You lost 1 life."));
PrintLine(TEXT("Type your guess agin."));
PrintLine(TEXT(""));
return;
}
if (Guess != HiddenWord) // when word dont match
{
--Lives; // decreasing lives for wrong answer
ClearScreen();
PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
PrintLine(TEXT("Bulls = X. Cows = X")); // show bulls and cows
PrintLine(TEXT(""));
PrintLine(TEXT("Wrong asnwer. You lost 1 life."));
PrintLine(TEXT("Type your guess agin."));
PrintLine(TEXT(""));
return;
}
// if the answer is correct
ClearScreen();
++Points; // awarded for correct answer
PrintLine(TEXT("Lives = %i. Points = %i"), Lives, Points); // show lives and points
PrintLine(TEXT(""));
PrintLine(TEXT(""));
PrintLine(TEXT("That is 100% correct!"));
PrintLine(TEXT("You get 1 point."));
EndGame();
}
Hello. I used both early returns and nested if statement to retain readability of code:
void UBullCowCartridge::ProcessGusess(FString Guess)
{
if (Guess == HiddenWord)
{
PrintLine(TEXT("You've won!"));
EndGame();
return;
}
PrintLine(TEXT("You have %i guesses left."), --Lives);
// Check if Isogram if not then prompt to Guess again
if (Lives>0)
{
if (HiddenWord.Len()!=Guess.Len())
{
PrintLine(TEXT("Wrong!\nHidden word is %i characters long."),HiddenWord.Len());
}
PrintLine(TEXT("Try again."));
return;
}
PrintLine(TEXT("It was a last, but wrong try."));
PrintLine(TEXT("\nThe hidden word was:%s"), *HiddenWord);
EndGame();
}
with the EndGame() lik this:
void UBullCowCartridge::EndGame()
{
bGameOver = true;
PrintLine(TEXT("Press ENTER to play again.."));
}