Bizarre runtime error

Hi, I keep getting this error when putting together the ValidWords:

Assertion failed: IsValidIndex(Index) [File:C:\Program Files\Epic Games\UE_4.22\Engine\Source\Runtime\Core\Public\Containers/UnrealString.h] [Line: 201] String index out of bounds: Index 7 from a string with a length of 7

UE4Editor_Core
UE4Editor_Core
UE4Editor_Core
UE4Editor_Core
UE4Editor_BullCowGame_2760!DispatchCheckVerify<void,<lambda_b0dad749953a646e2fc9f897f6ac5f2d> >() [C:\Program Files\Epic Games\UE_4.22\Engine\Source\Runtime\Core\Public\Misc\AssertionMacros.h:162]
UE4Editor_BullCowGame_2760!UBullCowCartridge::IsIsogram() [E:\CPlusPlusUnreal\BullAndCows\00Sources\BullCowGame-starter-kit\Source\BullCowGame\BullCowCartridge.cpp:121]
UE4Editor_BullCowGame_2760!UBullCowCartridge::GetValidWords() [E:\CPlusPlusUnreal\BullAndCows\00Sources\BullCowGame-starter-kit\Source\BullCowGame\BullCowCartridge.cpp:147]
UE4Editor_BullCowGame_2760!UBullCowCartridge::BeginPlay() [E:\CPlusPlusUnreal\BullAndCows\00Sources\BullCowGame-starter-kit\Source\BullCowGame\BullCowCartridge.cpp:10]
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor
UE4Editor
UE4Editor
UE4Editor
UE4Editor
kernel32
ntdll

BullCowCartridge.cpp

// Fill out your copyright notice in the Description page of Project Settings.
#include "BullCowCartridge.h"
#include "Containers/UnrealString.h"
#include "HiddenWordList.h"

void UBullCowCartridge::BeginPlay() // When the game starts
{
    Super::BeginPlay();

    TArray<FString> CheckWords = GetValidWords(Words);
    
    PrintLine(TEXT("The number of possible words are: %i."), CheckWords.Num());

    SetupGame();//Setting up game
    //debug only
    /* PrintLine(TEXT("The Hidden Word is: %s."), *HiddenWord);// debug line
    PrintLine(TEXT("\nIts length is: %i"), HiddenWord.Len());// debug line */
 
}

void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter
{
    //Main loop on entry by Player   
    if (bGameOver)//is Game Over?
    {
        ClearScreen();
        SetupGame();
    } else if(!bGameOver)//checking guess
    {
        ProcessGuess(Input);
    }
}

void UBullCowCartridge::SetupGame()
{
     //Initialize Member Variable(s)
    HiddenWord = TEXT("ounces"); 
    Lives = HiddenWord.Len();
    bGameOver = false;

    //Welcome message
    PrintLine(TEXT("Welcome Player to Bull Cows!"));
    PrintLine(TEXT("Guess the %i letter magic word..."), HiddenWord.Len());
    PrintLine(TEXT("You have %i Lives to guess the word..."), Lives);
    PrintLine(TEXT("Type in your guess and\nPress <ENTER> to continue..."));
    
   /*  const TCHAR HW[] = TEXT("peaches");
    //const TCHAR HW = {TEXT('o'), TEXT('u'), TEXT('n'), TEXT('c'), TEXT('e'), TEXT('s'), TEXT('\0')};
    PrintLine(TEXT("Character 1 of the hidden word is: %c"), HiddenWord[0]);//should print first char of the word "o"
    PrintLine(TEXT("Character 4 of HW array is: %c"), HW[3]); */
}

void UBullCowCartridge::EndGame()
{
     bGameOver = true;
     PrintLine(TEXT("\nThe Game is Over\nPress <ENTER> to play again..."));
}

void UBullCowCartridge::ProcessGuess(FString Guess)
{
    if (Guess == HiddenWord)
    {
        PrintLine(TEXT("You Won!"));
        EndGame();
        return;
    }

   //Check length of guess to length of Hidden Word
   if (Guess.Len() != HiddenWord.Len())
    {
        PrintLine(TEXT("The HiddenWord is  %i letters long"), HiddenWord.Len());
        PrintLine(TEXT("Sorry, guess not same length as word\nYou have %i lives left..."), Lives);
        return;
    }

    //Check if it's an isogram 
    if (!IsIsogram(Guess)) 
    {
        
        IsIsogram(Guess);
        //IsIsogram return a bool on whether it's an Isogram or not, if not
        PrintLine(TEXT("No repeating letters allowed,\nYou have lost a life\nGuess again!\nYou have %i lives left."), Lives);
        //remove Life 
        --Lives;
        return;
    } 

    //Remove a Life
    PrintLine(TEXT("You have lost a life...\nYou have %i lives left."), Lives);
    --Lives;

    //check if any Lives left
    if (Lives <= 0)
    {
        ClearScreen();
        PrintLine(TEXT("You have no lives left, the cows rejoice"));
        PrintLine(TEXT("The Hidden Word was %s.\nGood job for doing as well as you did..."), *HiddenWord);
        EndGame();
        return;
    } 

    //Show player the Bulls and Cows
    PrintLine(TEXT("Guess again, you have %i Lives left..."), Lives);

}//end ProcessGuess

bool UBullCowCartridge::IsIsogram(FString Word) const 
{
    //get length of Guess, so we know our outer bounds
    int32 GuessLength = Word.Len();
    int32 Comparison = 0;
    
    while (GuessLength!=0)
    {
        
        //Guess
        for (int32 Index = 0; Index < GuessLength; Index++)
        {           
            Comparison = Index+1;
            //outer loop starts with Index
            if (Word[Index] == Word[Comparison])
            {
                //Inner loops starts with Comparison, steps through remaining chars
                for (; Comparison < GuessLength; Comparison++)
                {
                   if (Word[Index] == Word[Comparison])
                   {
                       return false;
                   }
                }
                return false;
            }//end if
        }//end for
        GuessLength--;
    }
    return true;
}


TArray<FString> UBullCowCartridge::GetValidWords(TArray<FString> WordList) const
{
    TArray<FString> ValidWords;
    //step through all of Words
    for (int32 Index = 0; Index < WordList.Num(); Index++)
    {
        // Check for Isograms between 4 and 8 Characters long
        if (WordList[Index].Len() >= 4 && WordList[Index].Len() <= 8 && IsIsogram(WordList[Index])) 
        {
            ValidWords.Emplace(WordList[Index]);
        }
    }
    return ValidWords;
}//end ISIsogram



/*
int32 Comparison = 0;
        //IsIsogram check of the letters in the word
        for (int32 Index = 0; Index < Words[Index].Len(); Index++)
        {           
            Comparison = Index+1;
            //outer loop starts with Index
            if (Words[Index] == Words[Comparison])
            {
                //Inner loops starts with Comparison, steps through remaining chars
                for (; Comparison < Words[Index].Len(); Comparison++)
                {   
                    //Check if letters identical
                    if (Words[Index] == Words[Comparison])
                    {
                        //end the comparison loop with first positive
                            break;   
                    }else// otherwise carry on
                    {   
                        //if not add to array of ValidWords
                        ValidWords.Emplace(Words[Index]);
                    }
                }
            }//end if
        }//end for
    }//end outer if


*/

BullCowCartridge.h

// 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"

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(FString Guess);
	bool IsIsogram(FString Word) const;
	TArray<FString> GetValidWords(TArray<FString>) const;

	// Member Variables
	private:
	FString HiddenWord; // HiddenWord container
	int32 Lives; //init Lives for game
	bool bGameOver; //init game over
	bool bIsIsogram;//init IsIsogram
	//TArray<FString> ValidWords;
};

That is an incorrect implementation of IsIsogram for 2 reasons.

  1. You go out of bounds of the string
  2. You don’t compare each letter with each other.

For the word “ability” you do the following comparisons

a == b
b == i
i == l
l == i
i == t
t == y
y == ???? # go out of bounds here

And you would do that 7 times and the function would return true which is incorrect as that word is not an isogram.

On a side note, you do not use Comparison outside of the for loop so you shouldn’t define it at the start of the function. You should define variables in the smallest possible scope.

Thanks, Dan. Sometimes hard to see the code for the trees…lol
Here’s how it should have looked:

bool UBullCowCartridge::IsIsogram(FString Word) const 
{
    //get length of Guess, so we know our outer bounds
    int32 GuessLength = Word.Len();
    
    //Guess
    for (int32 Index = 0; Index < GuessLength; Index++)
    {  
          //Inner loops starts with Comparison, steps through remaining chars
            for (int32 Comparison = Index+1; Comparison < GuessLength; Comparison++)
            {
                if (Word[Index] == Word[Comparison])
                {
                    return false;
                }
            }
    }//end for
    return true;        
}

This works great now. Perfectly actually…

Thanks again, Dan

You can find out how to do this (properly, ahem) in Checking Characters Part 2, fyi

How it should look…

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms