I need to write a spell book and I have two ways to do it - use enum, or use std :: map, as it is easier for me to use enum. But I ran into a problem how to display my enum?
I want to make it so that I can display all these spells on the screen and ask the user which of these spells do you want to use?
for example:
enum Book {
Tornado,
FireBall,
etc,
};
I want it to be output to the console like this :
choose one:
1.Tornado
2.FireBall
how to output this,for example with using array,is it possible?
If you want to display the enum (Tornado, FireBall) instead of 1, 2 you can create a separate function doing that display
#include <iostream>
enum Book {
Tornado,
FireBall,
};
void yourFunction(const Book& book)
{
switch(book)
{
case Book::Tornado:
std::cout<<"Tornado"<<std::endl;
break;
case Book::FireBall:
std::cout<<"FireBall"<<std::endl;
break;
default:
break;
}
}
int main()
{
Book b=Book::FireBall;
yourFunction(b);
return 0;
}
The general problem described here is associating a known integer value with a text string. The solution can be as straightforward as this:
enum Book {
Tornado,
Fireball,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball"
};
To display the menu, just go through the enumerators:
for (int i = Tornado; i < last_index; ++i)
std::cout << (i + 1) << '.' << names[i] << '\n';
You can do this because enumerators start at 0 and increase by 1, that is, the value of Tornado is 0 and the value of Fireball is 1. The value of last_index is 2.
The reason for using last_index is to make it easier to maintain the code. If you add an enumerator that loop doesn't change:
enum Book {
Tornado,
Fireball,
GladHands,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball",
"Glad Hands"
};
With the added enumerator, the value of GladHands is 2 and the value of last_index is 3, so the original loop still works.
Note that this does not generate text from the name of the enumerator. The name of the enumerator has restrictions on it that the text version doesn't, so you really can't generate text in most cases. In particular, GladHands has no spaces, but its text version has one.
Related
I have a number of bool and int variables, that I need to access by some sort of index. I found a way to do so, but it seems a bit too complicated. Is there a way to do this in more elegant way?
For now in header file I have structure
struct FDialogueFlags
{
bool tmpFlag1;
bool tmpFlag2;
// bool tmpFlagX;
int tmpState1;
int tmpState2;
// int tmpStateX;
};
and enumeration
enum class Eflags
{
// NAME = flag_ID,
TMP_FLAG_1 = 1,
TMP_FLAG_2 = 10,
// TMP_FLAG_X = XX,
TMP_STATE_1 = 101,
TMP_STATE_2 = 110,
// TMP_STATE_X = XXX,
};
And in source file I have function, that returns values for given index - flag_ID
int GetFlagValue(int flag_ID)
{
switch (Eflags(flag_ID))
{
case (Eflags::TMP_FLAG_1):
return flagsAndStates.tmpFlag1;
break;
case (Eflags::TMP_FLAG_2):
return flagsAndStates.tmpFlag2;
break;
/*case (Eflags::TMP_FLAG_X):
return flagsAndStates.tmpFlagX;
break;*/
case (Eflags::TMP_STATE_1):
return flagsAndStates.tmpState1;
break;
case (Eflags::TMP_STATE_2):
return flagsAndStates.tmpState2;
break;
/*case (Eflags::TMP_STATE_X):
return flagsAndStates.tmpStateX;
break;*/
default:
break;
}
}
That way everytime I need to add new "flag" or "state" I have to edit 3 places in my code.
Besides, if I need to access any "flag" or "state" by it's name written in enum, I can not do so, because Eflags (TMP_FLAG_1) returns TMP_FLAG_1 and not a number.
The other important thing, I'd like to keep variable namings, there might be up to hundred of this "flags" and "states" and it's crusial for them to have unique names and not just iterative numbers (Code above is just an example, in the end product I would name all of them according to their meaning)
If possible I'd like to avoid using std::map since it isn't supported natively by UE4.
So, the core idea is to access certain amount of variables of different numeric types by given number, possibly keeping variable naming.
Assuming you are asking for syntactic alternatives, Can you use tuples? Here - http://en.cppreference.com/w/cpp/utility/tuple
They are similar to structures and you can use std::get to retrieve values with index-based method. You can then use if statements for comparisons instead of switch statement.
Example -
#include <iostream>
#include <tuple>
int main()
{
auto t = std::make_tuple(1, true, 25);
std::cout << std::get<0>(t) << "\n"
<< std::get<1>(t) << "\n"
<< std::get<2>(t) << "\n";
}
IDEONE
I don't have any experience with UE4 and what native support means, but there are numerous drop-in alternatives to std::map like this one.
Recently I've been working on an inventory system for a text-based game that uses a global array for the inventory system and a corresponding function to read true or false in said array. The problem I've run into is this, the function I'm using to modify the array
void playerGet(bool items[], int itemNumber) //this function takes an assigned argument of the array indices variable, and changes that array indices from true, to false.
{
items[itemNumber] = true;
}
only modifies the array within the scope of the function its housed in. The array is defined in a .cpp file like this:
void inventoryArray(bool items[]) //This function establishes all the items in the game, the true false statement expresses whether or not the item is in the player's inventory.
{
items[WEAPON_RELIC_RIFLE] = false;
items[WEAPON_SCALPEL] = false;
items[MISC_ACTION_FIGURE] = false;
items[MISC_FIRE_EXTINGUISHER] = false;
items[MISC_LIFE_RAFT] = false;
}
and is then declared in a .h file like this:
void inventoryArray(bool items[]);
the enums used in the array are defined in a header file like this:
enum equipment //This declares a list of enums for each item in the game, consumables, not included.
{
WEAPON_RELIC_RIFLE, // = 0
WEAPON_SCALPEL, // = 1
MISC_ACTION_FIGURE, // = 2
MISC_FIRE_EXTINGUISHER, // = 3
MISC_LIFE_RAFT, // = 4
MAX_EQUIPMENT
};
the function that reads the inventory array is this:
void twoScavengerCombat(bool items[])
{
for (int item = 0; item < MAX_EQUIPMENT; ++item)
{
if (items[item] == true) //if true proceed
{
switch (item)
{
case 0: //if array indices identifier = 0, print relic rifle
cout << "1: Use the Relic Rifle\n";
break;
case 1:
cout << "2: Use the Scalpel\n";
break;
case 2:
break;
case 3:
cout << "3: Use the Fire Extingusher\n";
break;
case 4:
cout << "4: Use the Life Raft\n";
break;
default:
cout << "Error";
break;
}
}
else
cout << "Option Unavailible\n"; //if false print Option Unavailible
}
compiled, with the array and enums headers declared the main file would look like this:
int toolSearch()
{
bool items[MAX_EQUIPMENT];
inventoryArray(items);
playerGet(items, 0);
}
void twoScavengerCombat(bool items[])\\ declared in this file, but since its just above here i left it as a forward declaration to save space
int main()
{
toolSearch();
twoScavengerCombat(items);
return 0;
}
Ideally this would produce the result: Use Relic Rifle
Option Unavailable
Option Unavailable
Option Unavailable
Option Unavailable
but instead it produces 5 Option Unavailable's. What am I missing?
You would want
//bunch of #include<> directives
bool items[MAX_EQUIPMENT];
int toolSearch()
{
inventoryArray();
playerGet( 0);
}
void twoScavengerCombat()
...
// other functions here
int main()
{
toolSearch();
twoScavengerCombat();
return 0;
}
Note that bool items[MAX_EQUIPMENT]; is not defined in a function. It is off on it's own at the top of the file in plain view of anything defined below it. This is what it means to be global. Anyone and everyone can access it, if they know where it is or you tell them where it is with an extern statement. It is created when the program starts (even before main and that can cause some really fun debugging if the initialization logic of the variable is faulty) and dies only when the program does.
Lightness Races in Orbit delves a bit deeper here, but is more concerned with making a global variable extend past a single file
There is no need to pass items into any function because everyone can see items The downside is there is one and only one items so if you have multiple players each with different item lists, you're going to have problems.
You might want to look into std::vector (resizable array) and std::map (which will allow you to look items up by name items["sword"].attackFoe(foe);) and std::set (which makes it really easy to see what a player has (if (items.find("Vorpal Hand Grenade") != items.end()) BlowStuffUp();) rather than having to search through each item every time.
I wrote a program to find duplicate entry in a table. I am a beginner in C++, hence I don't know how this program is working efficient. Is there any other idea to write this program? Here I have 3 tables (2D Vector), that they are 1)aRecord_arr 2)mainTable and 3)idxTable. idxtable is use to identify the keys to check duplicate entry. aRecord_arr table to be add in maintable. If it is already exist in maintable, it will show the error "Duplicate Entry". So Check this program, and give your suggestions.
typedef vector<string> rec_t;
typedef vector<rec_t> tab_t;
typedef vector<int> cn_t;
int main()
{
tab_t aRecord_arr= { {"a","apple","fruit"},
{"b","banana","fruit"} };
tab_t mainTable = { {"o","orange","fruit"},
{"p","pineapple","fruit"},
{"b","banana","fruit"},
{"m","melon","fruit"},
{"a","apple","fruit"},
{"g","guava","fruit"} };
tab_t idxTable = { {"code","k"},
{"name","k"},
{"category","n"}};
size_t Num_aRecords = aRecord_arr.size();
int idxSize = idxTable.size();
int mainSize = mainTable.size();
rec_t r1;
rec_t r2;
tab_t t1,t2;
cn_t idx;
for(int i=0;i<idxSize;i++)
{
if(idxTable[i][1]=="k")
{
idx.push_back(i);
}
}
for(size_t j=0;j<Num_aRecords;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r1.push_back(aRecord_arr[j][idx[id]]);
}
t1.push_back(std::move(r1));
}
for(int j=0;j<mainSize;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r2.push_back(mainTable[j][idx[id]]);
}
t2.push_back(std::move(r2));
}
for(size_t i=0;i<t1.size();i++)
{
for(size_t j=0;j<t2.size();j++)
{
if(t1[i]==t2[j])
{
cout<<"Duplicate Entry"<<endl;
exit(0);
}
}
}
}
If you want to avoid duplicate entries in an array, you should consider using a std::setinstead.
What you want is probably a std::map or a std::set
Don't reinvent the wheel, the STL is full of goodies.
You seem to be rooted in a weakly typed language - but C++ is strongly typed.
You will 'pay' the disadvantage of strong typing almost no matter what you do, but you almost painstakingly avoid the advantage.
Let me start with the field that always says 'fruit' - my suggestion is to make this an enum, like:
enum PlantType { fruit, veggie };
Second, you have a vector that always contain 3 strings, all with the same meaning. this seems to be a job for a struct, like:
struct Post {
PlantType kind;
char firstchar;
string name;
// possibly other characteristics
};
the 'firstchar' is probably premature optimization, but lets keep that for now.
Now you want to add a new Post, to an existing vector of Posts, like:
vector<Post> mainDB;
bool AddOne( const Post& p )
{
for( auto& pp : mainDB )
if( pp.name == p.name )
return false;
mainDB.push_back(p);
return true;
}
Now you can use it like:
if( ! AddOne( Post{ fruit, 'b', "banana" } ) )
cerr << "duplicate entry";
If you need speed (at the cost of memory), switch your mainDB to map, like:
map<string,Post> mainDB;
bool AddOne( const Post& p )
{
if( mainDB.find(p.name) != mainDB.end() )
return false;
mainDB[p.name]=p;
return true;
}
this also makes it easier (and faster) to find and use a specific post, like
cout << "the fruit is called " << mainDB["banana"].name ;
beware that the above will cause a runtime error if the post dont exists
As you can see, firstchar was never used, and could be omitted. std::map
has a hash-function-specialization for string keys, and it will probably be
orders of magnitude faster than anything you or I could whip up by hand.
All of the above assumed inclusion of the correct headers, and
using namespace std;
if you dont like using namespace, prepend std:: to all the right places
hope it helps :)
I have the following problem:
enum Language { English, French, German, Italian, Spanish };
int main() {
Language tongue = German;
tongue = static_cast<Language>(tongue + 1);
cout << tongue;
}
//it returns 3.....but i want to get the language name on index 3.....
I find that an explicit look up table works best, for both converting from enum to text and text to enum:
enum Language_Enum
{
LANGUAGE_FIRST = 0,
LANGUAGE_GERMAN = LANGUAGE_FIRST,
LANGUAGE_ENGLISH,
LANGUAGE_HOPI,
LANGUAGE_WELSH,
LANGUAGE_TEXAN,
LANGUAGE_DUTCH,
LANGUAGE_LAST
};
struct Language_Entry
{
Language_Enum id;
const char * text;
};
const Language Entry language_table[] =
{
{LANGUAGE_GERMAN, "German"},
{LANGUAGE_HOPI, "Hopi"},
{LANGUAGE_DUTCH, "Dutch"},
// ...
};
const unsigned int language_table_size =
sizeof(language_table) / sizeof(language_table[0]);
Specifying the enum along with the text, allows for the enum order to change with minimal effect to the search engine.
The LANGUAGE_FIRST and LANGUAGE_LAST identifiers allow for iteration of the enum:
Language_Enum l;
for (l = LANGUAGE_FIRST; l < LANGUAGE_LAST; ++l)
{
// ...
}
You'll have to create an array of strings which matches your enum e.g.
std::string[] LangTxt = { "English", "French", "German", "Italian", "Spanish" };
then you can reference them as follows:
cout << LangTxt[tongue];
Be careful to keep the definitions together though so they are updated side by side.
It is not so simple to print the enum name for a given enum value in C++. Instead, you can use a map or string array to hold the values, which do allow you to get both the index and the string value.
Best Way to use enum is first give initial value to your enum.
enum TestEnum
{
Zero=0,
One,
Two
}
Even you wont specify anything the default starting index is zero.
To get the value at a particular index simple do that
TestEnum(index);
Suppose I am working on a card game, and I am using the numbers 0 to 3 to represent the suits internally, as it's easier to work with numbers. So:
0 is equivalent to hearts
1 is equivalent to clubs
2 is equivalent to spades
3 is equivalent to diamonds
When I need to output the suits as strings, though, I can easily use an array of strings to convert them, like this one:
char *suits[] = {"heats","clubs","spades","diamonds"};
So that I can type:
cout << suits[card.suit]
and the output would be the exact string of the suit.
What if I want to do this the other way around though? That is, I'll be reading the suits from a file as strings, and I want to convert them to their respective numerical value (0 to 3) on the fly. How can I do it?
My initial idea was to create a very small hash table (i.e., 4 elements in this case), then hash the strings as I read them and get their respective numerical value from the hash table.
Is there an easier way I am missing (specifically in C or C++)?
std::map<std::string, int> assoc;
assoc["hears"] = 0;
assoc["clubs"] = 1;
...
char *suits[] = {"heats","clubs","spades","diamonds"};
for (char *data : suits)
{
std::cout << assoc[data];
}
Like Joachim said, I would recommend a std::map<std::string, int>.
You can then do stuff like.
std::cout << map["heart"];
I would recommend to check out the std::map class as it is quite a nice tool, but also holds some gotchas.
If you want to use it in both directions, you could also use a boost::bimap.
std::map<std::string, int id> cardsToIdMap;
int stringToCardId(std::string s) {
return cardsToIdMap[s];
}
A map is hugely overkill here:
#define SIZE(x) (sizeof (x)/sizeof(*(x)))
const char *suits[] = {"heats","clubs","spades","diamonds"};
int suit_to_int(char *s)
{
for(int x=0; x<SIZE(suits);x++)
if(strcmp(s, suits[x])==0)
return x;
return SUIT_ERR;
}
char* suit;
if (*suit == 'h') {
return 0;
} else if ...