My code so far

Having got to the end of the updated Bulls and Cows module, as is currently available, I decided to have a go today and try and finish the original outline for the game despite the course not having quite got that far yet.

I’ve completed adding checks for ISOGRAM conformance, calculating the Bull and Cow counts, all the associated messages to the user and I’ve implemented a simple string array to hold ten words which the program uses to randomly choose, one at a time. I default the Lives to 4 but increase those on any word lengths of 4 or over to the length + 1. So, for example a 7 letter word will get 8 lives. Restarting the game and exiting have been catered for too.

Functionally I think I’ve been successful, it’s probably not very elegant but it appears to work. Thanks Michael for your work on this so far, I have found it interesting and it’s been a fun project to work on.

I will go on to look at the original course version of this as I may pick up further useful knowledge.

OK, so for what it is worth here is my code in it’s entirety:

BullCowCartridge.h

#pragma once

#include "CoreMinimal.h"
#include "Console/Cartridge.h"
#include "BullCowCartridge.generated.h"

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;

	// Your declarations go below!
	private:
		FString HiddenWord;
		FString CurrentWordGuess;
		bool bHelpCalled;
		bool bNewWord;
		int32 WordLength;
		bool bHasGuessed;
		bool bStartGame;
		bool bContinuePlay;
		int32 LivesLeft;
		TArray<FString> WordArray;

		void DisplayWelcome();
		void DisplayHelp();
		void InitGame();
		void PopulateHiddenWordArray();
		FString GetRandomWord();
		void ProcessUserInput(const FString& Input);
		void DisplayInstruction();
		void DisplayGuess(const FString& Guess);
		void DisplayLivesRemaining(int32 Lives);
		void DisplayContinueGamePrompt();
};

and BullCowCartridge.cpp

#include "BullCowCartridge.h"

void UBullCowCartridge::BeginPlay() // Called by Unreal Engine when the game starts
{
	Super::BeginPlay();
	InitGame();
}

void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter
{
	ClearScreen();
	ProcessUserInput(Input);
}

void UBullCowCartridge::InitGame()
{
	// Initialise variables
	bHelpCalled = false;		// Flag to indicate if DisplayHelp had previously been called
	bNewWord = false;			// Flag to indicate its a new word	
	bHasGuessed = false;		// Flag to indicate the user has provided a guess
	bStartGame = false;			// Flag to indicate start of a new game
	bContinuePlay = true;		// Flag to indicate play should continue
	LivesLeft = 4;				// Defaults to a minimum of 4 lives

	// Seed the random number generator
	srand(FDateTime::Now().GetMillisecond());

	// Build a string array of words
	PopulateHiddenWordArray();
	
	// Get a random hidden word from the string array
	HiddenWord = GetRandomWord();

	//PrintLine(HiddenWord);  // For debug purposes, comment out for release build
	
	WordLength = HiddenWord.Len();

	// Increase the lives if the word length is greater than 4
	if (WordLength > 3)
	{
		LivesLeft = WordLength + 1;
	}

	DisplayWelcome();
}

void UBullCowCartridge::PopulateHiddenWordArray()
{
	WordArray.Emplace(TEXT("tin"));  // Always encose literal strings in a TEXT macro to ensure native Unicode encoding.
	WordArray.Emplace(TEXT("world"));
	WordArray.Emplace(TEXT("melt"));
	WordArray.Emplace(TEXT("window"));
	WordArray.Emplace(TEXT("plate"));
	WordArray.Emplace(TEXT("biscuit"));
	WordArray.Emplace(TEXT("man"));
	WordArray.Emplace(TEXT("metal"));
	WordArray.Emplace(TEXT("sun"));
	WordArray.Emplace(TEXT("rain"));
}

FString UBullCowCartridge::GetRandomWord()
{
	int32 RandomArrayIndex;

	// Get a random number between 0 up to the number of elements in the array
	RandomArrayIndex = (rand() % WordArray.Num());

	return HiddenWord = WordArray[RandomArrayIndex];
}

void UBullCowCartridge::ProcessUserInput(const FString& Input)
{
	int32 NumOfBulls = 0;
	int32 NumOfCows = 0;
	FString UCGuessedWord;
	FString UCHiddenWord;
	
	// Start of game so just display Instruction and ignore any other input
	if (!bStartGame)
	{
		bStartGame = true;
		DisplayInstruction();
		return;
	}
	
	// Handle the ContinueGamePrompt user input
	if (!bContinuePlay)
	{
		if (Input == TEXT("r"))
		{
			InitGame();
			bContinuePlay = true;
			return;
		}
		else if (Input == TEXT("q"))
		{
			// Quit game
			GIsRequestingExit = true;
		}
		else
		{
			// Non valid input from user so just display prompt again
			DisplayContinueGamePrompt();
			return;
		}
	}
	
	DisplayInstruction();

	// If user previously called help then display the previously stored word guess
	if (bHelpCalled)
	{
		if (CurrentWordGuess != "")
		{
			DisplayGuess(CurrentWordGuess);
			DisplayLivesRemaining(LivesLeft);
		}

		// Reset our help called flag
		bHelpCalled = false;

		return;
	}

	// So long as something has been typed
	if (Input != "")
	{
		// If user requested help
		if (Input == TEXT("help"))
		{
			DisplayHelp();

			// Set our help called flag 
			bHelpCalled = true;
		}
		else
		{
			// Store the current word guess incase the user subsequently requests help or just hits enter and we need to restore the guess
			CurrentWordGuess = Input;
			bHasGuessed = true;

			DisplayGuess(Input);
			
			// Test to see if the guess is correct or not
			if (Input == HiddenWord)
			{
				// Display the users latest guess
				PrintLine(TEXT("Correct.  You Win!"));
				DisplayContinueGamePrompt();
				bContinuePlay = false;
				CurrentWordGuess = "";
				bNewWord = true;
				bHasGuessed = false;
			}
			else
			{
				// Is the length correct
				if (Input.Len() != WordLength)
				{
					PrintLine(TEXT("Incorrect.  The word has %i characters"), WordLength);
					PrintLine(TEXT("Please try again."));
					return;
				}

				// Convert and store both words converted to Upper Case so we can do effective character comparisons
				UCGuessedWord = Input.ToUpper();
				UCHiddenWord = HiddenWord.ToUpper();

				// Check the word is an ISOGRAM (no repeated characters in the word)
				for (int32 i = 0; i < WordLength; i++)
				{
					for (int32 n = 0; n < WordLength; n++)
					{
						// Avoid checking the same position for a matching character
						if (n == i) continue;

						if (UCGuessedWord.Mid(i, 1) == UCGuessedWord.Mid(n, 1))
						{
							PrintLine(TEXT("Incorrect.  The word is not an ISOGRAM"));
							PrintLine(TEXT("Please try again."));
							return;
						}
					}
				}

				// Decrement the number of lives left
				--LivesLeft;

				// Check for bulls and cows
				for (int32 i = 0; i < WordLength; i++)
				{
					// If characters match in the same position in the strings then increment the Bulls count
					if (UCGuessedWord.Mid(i, 1) == UCHiddenWord.Mid(i, 1))
					{
						++NumOfBulls;
					}
					else
					{
						// If characters match in a different position in the strings then increment the Cows count
						for (int32 n = 0; n < WordLength; n++)
						{
							// Avoid checking the same position as we know already they don't match
							if (n == i) continue;
							
							if (UCGuessedWord.Mid(i, 1) == UCHiddenWord.Mid(n, 1))
							{
								NumOfCows++;
							}
						}
					}
				}

				// Display the results
				PrintLine(TEXT("Incorrect.  You lose a life"));
				PrintLine(TEXT("You scored Bulls: %i, Cows: %i"), NumOfBulls, NumOfCows);
				DisplayLivesRemaining(LivesLeft);
				PrintLine(TEXT("Please try again"));		

				// Handle user out of lives
				if (LivesLeft == 0)
				{
					PrintLine(TEXT("You have no lives left"));
					DisplayContinueGamePrompt();
					bContinuePlay = false;
				}
			}
		}
	}
	else if (bHasGuessed)
	{
		// If the user has previously guessed but has just pressed Enter then print previous guess
		DisplayGuess(CurrentWordGuess);
		DisplayLivesRemaining(LivesLeft);
	}
}
	
void UBullCowCartridge::DisplayWelcome()
{
	PrintLine(TEXT("Welcome to the Bulls and Cows game\n"));
	PrintLine(TEXT("Press Enter to continue"));
}

void UBullCowCartridge::DisplayHelp()
{
	ClearScreen();
	PrintLine(TEXT("The game is a guess the hidden word game."));
	PrintLine(TEXT("The hidden word will always be an ISOGRAM,"));
	PrintLine(TEXT("that is a word with no repeating letters."));
	PrintLine(TEXT("Any correct letters in the right position"));
	PrintLine(TEXT("will score you BULLS, any correct letters"));
	PrintLine(TEXT("in the wrong position will score you COWS"));
	PrintLine(TEXT("and any wrong letters score nothing."));
	PrintLine(TEXT("You will have so many tries in order to "));
	PrintLine(TEXT("guess the word correctly and win the game."));
	PrintLine(TEXT("Press Enter to return to the game."));
}

void UBullCowCartridge::DisplayInstruction()
{
	PrintLine(TEXT("Type help and press Enter for a basic"));
	PrintLine(TEXT("description of the game and rules.\n"));
	PrintLine(TEXT("Otherwise guess the %i letter word ...\n"), WordLength);
}

void UBullCowCartridge::DisplayGuess(const FString& Guess)
{
	PrintLine("You guessed: " + Guess);
}

void UBullCowCartridge::DisplayLivesRemaining(int32 Lives)
{
	PrintLine(TEXT("You have %i lives remaining"), LivesLeft);
}

void UBullCowCartridge::DisplayContinueGamePrompt()
{
	PrintLine(TEXT("To restart type 'r' and Enter"));
	PrintLine(TEXT("To quit type 'q' and Enter"));
}
1 Like

1 Like

Awesome work! :smiley:

Decided to do some tweaking to improve the grammar of the game. Spent 30 mins on this but it was worth it

 else // Checking Player Guess
    {
        if (Input == HiddenWord)
        {
            PrintLine (TEXT("You Win!")); // Winning Message
            EndGame();
        }
        else
        {   --Lives;
            PrintLine(TEXT("Wrong guess. You have lost a life."));

            if (Lives > 1)
            {   
                if (Input.Len() != HiddenWord.Len())
                {
                    PrintLine(TEXT("Try guessing again! \nYou have %i lives remaining."), Lives);    
                }
            }           
            else 
            {   
                if (Lives == 1)
                {
                     PrintLine(TEXT("Try guessing again! \nYou have only 1 life remaining."));
                }
                
                if (Lives == 0)
                {
                     PrintLine(TEXT("You have no lives left. Game Over!"));
                     EndGame();
                }
            }       
        }
    }

Privacy & Terms