Help comparing randomly chosen 2-dimensional array strings

Hi,

While waiting for the rest of the remaster I’m currently trying to make an anagram finding game as a kind of follow up to Triple X, it’s started out fairly well but I’ve run into 1 little snag that I am struggling to find an answer to by googling as it seems to be a very specific question I need to ask…

Basically I’ve created a 2 dimensional array to hold the anagrams, I’m then using rand() with time.h (time) in order to randomly choose 1 of the arrays depending on the level selected. That all works fine the issue comes when I want to come the response given with the list of anagrams, as I can’t just specify which elements to compare it with as it’s chosen randomly, so I need a way to get the address of the randomly chosen element. My first thought was to use pointers and get the address that way but currently that is also proving problematic.

Is there an easier way to do this that I’m missing? am I just using pointers entirely wrong? or should I just not be using .compare for this? I’ve included what I have so far for reference, currently it always compares the word with art, but even putting that in has no effect on the outcome.

/*	HeadPounder
	Author Ben Barnes 06/01/2020
	Version 0.1
*/


#include <iostream>
#include <string>
#include <cstdlib>
#include <time.h>
#include <stdio.h>

void Log(const char*);

int main()
{
	srand (time(NULL));

	std::string Anagram;
	std::string* ThreePointer;

	std::string ThreeLetterAnagrams[8][3]{
	{ "art", "rat", "tar" },
	{ "apt", "pat", "tap" },
	{ "arm", "mar", "ram" },
	{ "are", "ear", "era" },
	{ "asp", "sap", "spa" },
	{ "ate", "eat", "tea" },
	{ "now", "own", "won" },
	{ "opt", "pot", "top" }
	};

	ThreePointer = ThreeLetterAnagrams[0];

	void PrintIntroduction();
	{
		Log("Welcome to HeadPounder a quick game of anagrams!");
		Log("You will be given a word from a selection and your goal is to find all the anagrams of that word.");
		Log("You will need to use every letter and don't worry I'll let you know when you've got them all.");
		Log("Good luck and don't feel too bad if you don't get them all, you can always try again.");
		Log("");
	}

	void SelectDifficulty();
	{
		int LevelDifficulty;

		Log("Ok first choose your difficulty level, this will determine the number of letters in your word.");
		Log("Just enter a digit between 3 and 10, trust me anagrams of 2 letter words aren't fun...");
		
	label1:
		std::cin >> LevelDifficulty;

		switch (LevelDifficulty)
		{
		default: Log("I said between 3 and 10... lets try this again, enter a digit between 3 and 10 to choose your difficulty.");
				std::cin.clear();
				std::cin.ignore(1000, '\n');
				goto label1;

		case 3: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 4: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 5: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 6: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 7: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 8: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level; "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 9: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				Log("");
				printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				Log("Lets get on with the game!");
				Log("");

			break;

		case 10: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
				 Log("");
				 printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
				 Log("Lets get on with the game!");
				 Log("");

			break;
		}

	}

	void PlayGame();
	{		
		std::string Response;

		std::cin.ignore(1000, '\n');
		std::cout << "Ok your first word to find anagrams for is: " << Anagram << std::endl;
		Log("Enter your guesses below.");
		getline(std::cin, Response);
		Response.compare(&ThreePointer[rand() % 7 + 0][0]);
		if (!Response.compare(&ThreePointer[rand() % 7 + 0][1, 2]))
		{
			Log("You got one right!!");
		}
		else
		{
			Log("That's not right dumbass!");
		}
	}
}

void Log(const char* message)
{
	std::cout << message << std::endl;
	
}



1 Like

When dealing with non-address lookup and you have something like two separate holders that you need the matching info from there’s different ways to go so there’s not really one answer.

The point you need to get with this idea I suppose is that you need to have the matching info to be used the same. So if NormalGreetings has “hello” at [0][0] then ProgrammerTalk needs to have “world” also at [0][0] when you want to say “hello world”. If you can’t do that then it will not match unless you do some trickery and make it overly complex.

If its all in the same holder then you need an identifying way to get to the matching info. Here, If you put Age 22 with Age 23 instead of Name Noel then this will fail because age and name were never matched properly up front.

The thing is you can’t random one thing when there’s matching info in another without being able to match the lookup in some way.

Another way and perhaps best would be to use a DB. In this case you can put in “hello” then attach “world” to that up front. That way when random gets “hello” you just check “hello” in the DB and it gives back “world”. Or if the user picks “ice” you can check DB for “ice” and get back “cold”.

You can also use separate classes and holders, map, sort, create code that matches stuff, pair, and more.

Perhaps it’s a bit too early to start tackling 2D arrays and pointers.

You have a couple of more beginner orientated issues in the code you posted.
First you have code like this inside main

void PrintIntroduction();
{
    //code
}

This does not do what you perhaps think it does. You have declared a function inside a function and have never defined it. The code would be exactly the same if you had removed all of them i.e.

int main()
{
    srand(time(NULL));

	std::string Anagram;
	std::string* ThreePointer;

	std::string ThreeLetterAnagrams[8][3]{
	{ "art", "rat", "tar" },
	{ "apt", "pat", "tap" },
	{ "arm", "mar", "ram" },
	{ "are", "ear", "era" },
	{ "asp", "sap", "spa" },
	{ "ate", "eat", "tea" },
	{ "now", "own", "won" },
	{ "opt", "pot", "top" }
	};

	ThreePointer = ThreeLetterAnagrams[0];

	Log("Welcome to HeadPounder a quick game of anagrams!");
	Log("You will be given a word from a selection and your goal is to find all the anagrams of that word.");
	Log("You will need to use every letter and don't worry I'll let you know when you've got them all.");
	Log("Good luck and don't feel too bad if you don't get them all, you can always try again.");
	Log("");

	int LevelDifficulty;

	Log("Ok first choose your difficulty level, this will determine the number of letters in your word.");
	Log("Just enter a digit between 3 and 10, trust me anagrams of 2 letter words aren't fun...");

label1:
	std::cin >> LevelDifficulty;

	switch (LevelDifficulty)
	{
	default: Log("I said between 3 and 10... lets try this again, enter a digit between 3 and 10 to choose your difficulty.");
		std::cin.clear();
		std::cin.ignore(1000, '\n');
		goto label1;

	case 3: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 4: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 5: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 6: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 7: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 8: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level; "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 9: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;

	case 10: Anagram = ThreeLetterAnagrams[rand() % 7 + 0][0];
		Log("");
		printf("Great! you've selected difficulty level: "), std::cout << LevelDifficulty, Log("");
		Log("Lets get on with the game!");
		Log("");

		break;
	}


	std::string Response;

	std::cin.ignore(1000, '\n');
	std::cout << "Ok your first word to find anagrams for is: " << Anagram << std::endl;
	Log("Enter your guesses below.");
	getline(std::cin, Response);
	Response.compare(&ThreePointer[rand() % 7 + 0][0]);
	if (!Response.compare(&ThreePointer[rand() % 7 + 0][1, 2]))
	{
		Log("You got one right!!");
	}
	else
	{
		Log("That's not right dumbass!");
	}
}

Second, goto. Pretend it doesn’t exist, consider it an expert level feature. There are very very few reasons to ever use it. goto makes it hard to see the control flow of your program and it’s the number 1 way to get spaghetti code.

A switch statement is not a good fit for the problem you are trying to solve. You have repeated yourself 10 times. DRY - don’t repeat yourself. Instead use a while loop for when the input is incorrect.

Also I would suggest you use std::array over C array’s.

Hi,

Thanks for the response, aye I made the functions as normally I declare them outside the main function but I wasn’t sure if, especially for a small programme like this, that was just creating extra declarations and definitions for no reason, then entirely forgot that made them pointless to exist. Just tried doing the proper declaring and defining and that made a whole mess of the variables :frowning: , need to get the hang of passing those things as arguments, though that is the 1 bit that always gave me a headache.

For goto is it just useful in very specific places or is it more something that’s so risky to use it’s best to exhaust every other option before using it?

Why is it better to use the std::array system instead of the one I used here? I’ve been reading up in a few other places like cplusplus and that tutorial uses the one I used, is it just out-dated or is it more complicated than the std::array one?

I may have another question later but I’m going to try and figure it out myself a bit first (need to go out for now sadly :frowning:) , the switch statement was used in order to have a difficulty level selector and I’m not sure how a while loop would allow you to select difficulty more easily… however as I said I’ll have a look into that later to see if I can work it out as I haven’t made much use of them so far.

Off the top of my head the only place I can think of where I would use it would be in a nested loop where the outer loop needs to go to the inner loop. Basically there is always better constructs to use instead of goto, like a while loop in your case.

Because it has value semantics so acts as expected i.e.

std::array<int, 3> a{1,2,3};
std::array<int, 3> b = a; 

b is a copy of a. You don’t get that with C-arrays. It also has a couple useful member functions like size.

The key part is to loop on incorrect input.

Bah I can’t figure it out :frowning: tried looking online and most of the time what comes up is starting at the lowest difficulty then going up, but I want the player to select the difficulty they want straight off the bat so they don’t need to slowly go up through them 1 by 1.

You already have most of it and you’re effectively doing it already just using a switch and goto instead of a while loop

std::cin >> LevelDifficulty;
while(/*incorrect*/)
{
    std::cin.clear();
    std::cin.ignore(1000, '\n');
    std::cin >> LevelDifficulty;
}

Ask the user for difficultly and store that in a variable just like their answer during the game.

You then have to have code that offers difficulty and also have code that allows that difficulty to be selected dynamically.

Let’s just simplify this last one…

you can have

ThreeLetterAnagrams[1] which contains eg “art”
FourLetterAnagrams[1] which contains eg “mart”

In this case, if user chose level 2 then you would use ThreeLetterAnagrams.

or you can even do

Anagrams[2] which contains eg “art” and “mart” with only one per level and this example being 2 levels.

so if user chose level 2 then you would use Anagrams[1].

or you could do the multi-array and combine it all so you can have multiple per level in one. Its probably best to not use multi-array for only one level as this needlessly over complicates it.

Anagrams[1][1] which contains eg “art” and “mart”.

Then if user chose level 1 then you would use [1][0], [1][1], [1][2], etc.

Looks like DanM got you the while loop there so that part is good :slight_smile:

For and easier time I say you should just use a single array with one word each level for now. then just use the user input number as the array location for the level. That would be quickly done. Then you can change it to increase it if wanting to.

eg
Anagrams[0] = “as”;
Anagrams[1] = “art”;
Anagrams[2] = “mart”;

LevelDifficulty is set by user as eg 1 (or LevelDifficulty - 1 if wanting 0 to be level 1) then…

You would then use Anagrams[LevelDifficulty] anagram with “art” in use.

You could then use another array for the matching holder where eg [LevelDifficulty] could be “Congrats for beating level 1” or whatever.

Privacy & Terms