Added Location Aware Bulls and Cows to the Game

The New Feature

Figured I’d give a try at adding a new feature in, so I made it so the Bulls and Cows displayed also what letter in the word they related to by displaying an array like string to the terminal where each letter of the guess corresponded to either a “B” for a bull a “C” for a cow or an “N” for no relation to the word.

Implementation

To keep it simple for myself I just changed up the struct we already made to leverage a TArray and assigned integers 0, 1, and 2 to the constants NONE, COW, and BULL.

struct FBullCowCount
{
	// Array of either Bull or Cow on each Index of your guess. 
	const int32 BULL = 2;
	const int32 COW = 1;
	const int32 NONE = 0;
	TArray<int32> BullCows;
};

Then, I changed up how the GetBullCows Function worked to instead Emplace either a BULL or a COW to the array, or otherwise fill in the space in the array with a NONE.

FBullCowCount UBullCowCartridge::GetBullCows(const FString& Guess) const {

    FBullCowCount Counts;

    for (int32 GuessIndex = 0; GuessIndex < Guess.Len(); GuessIndex++)
    {
        if (Guess[GuessIndex] == HiddenWord[GuessIndex]) {
            Counts.BullCows.Emplace(Counts.BULL); // Add a Bull at the location of the letter in the counts array.
            continue;
        }
        
        for (int32 HiddenWordIndex = 0; HiddenWordIndex < HiddenWord.Len(); HiddenWordIndex++)
        {
            if (HiddenWordIndex == GuessIndex) { continue; }
            else if (Guess[GuessIndex] == HiddenWord[HiddenWordIndex])
            {
                Counts.BullCows.Emplace(Counts.COW); // Add a Cow at the location of the letter in the counts array.
                break;
            }
            
        }

        /* If the space for the current letter is not filled
            (computed by whether the size of the counts array is equal
            to GuessIndex, indicating the current portion of the Guess being
            parsed is the still larger than the counts array is.)
            We fill in the counts array with a NONE instead. 
        */
        if (Counts.BullCows.Num() <= GuessIndex) {
            Counts.BullCows.Emplace(Counts.NONE);
        }
        
    }

Finally I made the end of ProcessGuess if the method didn’t return early parse and print the array by concatenating to a string, in the process converting the constants to letters that made it a little more readable.

    FBullCowCount Counts =  GetBullCows(Guess);
    FString BullsCowsInPlace = TEXT(""); // Declare and instantiate an empty string to add to.

    // Concatenate on each element of the array as a readable letter instead.
    for (int32 each : Counts.BullCows) {
        BullsCowsInPlace += TEXT("[");
        if (each == Counts.BULL) {
            BullsCowsInPlace += TEXT("B");
        }
        else if (each == Counts.COW)
        {
            BullsCowsInPlace += TEXT("C");
        }
        else
        {
            BullsCowsInPlace += TEXT("N");
        }
        BullsCowsInPlace += TEXT("]");
    }

    PrintLine(TEXT("Your Bulls and Cows\n %s"), *BullsCowsInPlace); // Print Bulls and Cows
}

It was a little slapdash to put together but it definitely made making guesses much more manageable and sped up the game a little bit.

Think I named some of the variables a bit differently but You’re welcome to look at my source from an SVN repo I propped up for myself here.

Thanks for the helpful lesson on some of the basics of working within the Unreal libraries guys!

This is amazing work! I bet you learned so much by creating a new feature.

Privacy & Terms