Hey there! I’m relatively a newbie at coding, but I still took some time to add some additional features regarding managing scores and usage improvements. I also tuned the environment to give it a significantly vibrant appearance with some comfortable colors. Usually I’d tinker those a lot because I’ve mainly practiced heavily on art and design before.
One significant thing I recognized was that UE4 would crash when guesses are longer than the hidden word. I patched that up on the lambda of the GetBullCows function by adding a condition to keep the GuessIndex lower than the Guess from scanning past the HiddenIndex. It doesn’t break the gameplay loop nor the game itself, so that’s a plus.
My Code:
Main
// Fill out your copyright notice in the Description page of Project Settings.
#include "BullCowCartridge.h"
#include "HiddenWordList.h"
void UBullCowCartridge::BeginPlay() // When the game starts
{
Super::BeginPlay();
PrintLine(TEXT("|INPUTS| Instructions: needhelp | Score Screen: needscore |"));
SetupGame();
//PrintLine(TEXT("The number of possible words is %i."), Words.Num());
//PrintLine(TEXT("The number of valid words is %i."), GetValidWords(Words).Num());
}
void UBullCowCartridge::OnInput(const FString& PlayerInput) // When the player hits enter
{
if (bGameOver) // If game is over, reset
{
ClearScreen();
SetupGame();
}
else // If game is not over, continue playing
{
ProcessGuess(PlayerInput);
}
}
void UBullCowCartridge::SetupGame()
{
PrintLine(TEXT("Welcome to Bull Cows, pardner!"));
Isograms = GetValidWords(Words, Wins + 4); // Takes words from our HiddenWordList header file
HiddenWord = Isograms[FMath::RandRange(0,Isograms.Num() - 1)];
if (RewardConvert(Lives) != 0)
{
PrintLine(TEXT("+%i BONUS LIVES!"), RewardConvert(Lives));
}
Lives = RewardConvert(Lives) + HiddenWord.Len() * 2;
bGameOver = false;
PrintLine(TEXT("ROUND: %i - Guess the %i letter word in %i lives!"), Wins + 1, HiddenWord.Len(), Lives);
PrintLine(TEXT("Press tab to type and enter to input."));
PrintLine(TEXT("[DBG]The HiddenWord %s is %i characters."), *HiddenWord, HiddenWord.Len()); //Debug Line
}
int32 UBullCowCartridge::RewardConvert(const int32& Performance) const
{
if (Performance >= 9)
{
return 6;
}
if (Performance >= 6)
{
return 3;
}return 0;
}
void UBullCowCartridge::EndGame()
{
bGameOver = true;
return;
}
int32 UBullCowCartridge::EndResult(const int32& Outcome)
{
if (Outcome == 1)
{
Wins++;
}
if (Outcome == 2)
{
if (BestWins < Wins)
{
BestWins = Wins;
}
PrintLine(TEXT("GG! You've got %i wins.\nYour highest winstreak was %i"), Wins, BestWins);
Wins = 0;
}
return Wins;
}
void UBullCowCartridge::ProcessGuess(const FString& Guess)
{
if (Guess == TEXT("needhelp"))
{
HelpScreen(true);
return;
}
if (Guess == TEXT("needscore"))
{
ScoreScreen(true);
return;
}
FBullCowCount Scope = GetBullCows(Guess); // Returns FBullCowCount, updated Bull Cows of guess.
PrintLine(TEXT("You have %i Bulls and %i Cows"), Scope.Bulls, Scope.Cows);
if (Guess == HiddenWord)
{
PrintLine(TEXT("Gratz! Press Enter to continue. WINS: %i"), Wins + 1);
if (Lives >= 6)
{
PrintLine(TEXT("%i lives remained. +%i bonus lives!"), Lives, RewardConvert(Lives));
}
EndResult(1);
EndGame();
return;
}
PrintLine(TEXT("Nope! %i lives remain."), --Lives); // Remove Life and show new lives
if (Lives <= 0) // Check if lives > 0
{
PrintLine(TEXT("\nGame Over!"));
PrintLine(TEXT("The Hidden Word was %s"), *HiddenWord);
EndResult(2);
EndGame();
return;
}
if (Guess.Len() != HiddenWord.Len()) // Check right num of char and print
{
PrintLine(TEXT("Remember, it must be %i characters."), HiddenWord.Len());
}
if (!IsIsogram(Guess)) // Invoker for checking if guess is Isogram. Takes Guess.
{
PrintLine(TEXT("Not an Isogram. Letter repeats found!"));
return;
}
}
bool UBullCowCartridge::IsIsogram(const FString& Word) const // Function for checking if guess is Isogram
{
for (int32 Index = 0; Index < Word.Len(); 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>& WordsList, const int32 WinsCount) const // Wordlist chooses based on difficulty
{
TArray<FString> ValidWords;
for (FString EachWord : WordsList) // For WordList's each named EachWord
{
if (WinsCount > 9)
{
if (EachWord.Len() >= 7 && EachWord.Len() <= 9 && IsIsogram(EachWord))
{
ValidWords.Emplace(EachWord);
}
}
else
{
if (EachWord.Len() == WinsCount && IsIsogram(EachWord))
{
ValidWords.Emplace(EachWord);
}
}
}
return ValidWords;
}
FBullCowCount UBullCowCartridge::GetBullCows(const FString& Guess) const
{
FBullCowCount Count;
for (int32 GuessIndex = 0; GuessIndex < Guess.Len() && GuessIndex < HiddenWord.Len(); GuessIndex++) // Checks how many characters are right in the guess. Bulls are position.
{ // Failsafe past AND stops Guess Index from going past HiddenWord Array max.
if (Guess[GuessIndex] == HiddenWord[GuessIndex]) // If Guess char is == Hiddenword Char Bull +1. Goes position to position.
{
Count.Bulls++;
continue;
}
for (int32 HiddenIndex = 0; HiddenIndex < HiddenWord.Len(); HiddenIndex++) // Checks how many characters match up from the hidden word's view and length. Cows are char.
{ // If 1 bull, then character and position is correct!
if (Guess[GuessIndex] == HiddenWord[HiddenIndex]) // Chosen GuessIndex spans across entire HiddenWord to see what words are right.
{
Count.Cows++;
break;
}
}
} return Count;
}
void UBullCowCartridge::HelpScreen(const bool& bHelpNeeded) const
{
if (bHelpNeeded)
{
PrintLine(TEXT("In Bull Cows, you need to find the hidden word!\nYou get hints from Bulls and Cows!"));
PrintLine(TEXT("Bulls are letters in the right spot.\nCows are letters in the word in the wrong spot."));
PrintLine(TEXT("Lives are 2x the wordlength with added bonuses.\nWinning with +9 Lives reward 6 next round. +6 rewards 3."));
}
}
void UBullCowCartridge::ScoreScreen(const bool& bScoreNeeded) const
{
if (bScoreNeeded)
{
PrintLine(TEXT("SCORE- Wins: %i Highest Win Streak: %i"), Wins, BestWins);
}
}
Header
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Console/Cartridge.h"
#include "BullCowCartridge.generated.h"
struct FBullCowCount
{
int32 Bulls = 0;
int32 Cows = 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;
void SetupGame();
void EndGame();
void ProcessGuess(const FString& Guess);
bool IsIsogram(const FString& Word) const;
TArray<FString> GetValidWords(const TArray<FString>& WordsList, const int32 WinsCount) const;
FBullCowCount GetBullCows(const FString& Guess) const;
int32 EndResult(const int32& bOutcome);
int32 RewardConvert(const int32& Performance) const;
void HelpScreen(const bool& bHelpNeeded) const;
void ScoreScreen(const bool& bScoreNeeded) const;
// Your global member declarations go below!
private:
FString HiddenWord;
int32 Lives;
bool bGameOver;
TArray<FString> Isograms;
int32 Wins = 0;
int32 BestWins = 0;
};
A nice course so far! It’s good to start with it on C++ after 2 months of Python. Hoping to master using both art and programming together.