-3

I am trying to output a random value of a vector and I managed to do something like

srand(time(0));
cout << enemies[rand() % enemies.size()].getName() << endl;

Why wouldn't it return a value of

 {5, 15, 0, "name1", 40, 20},
 {10, 10, 0, "name2", 60, 30},
 {5, 15, 0, "name3", 20, 20},

but it does return the "something" from

class Enemy : public Player
{
public:
    int exp;
int money;

Enemy(int attack = 0, int defense = 0, int evasion = 0, string name = "something", int money = 0, int exp = 0)

Could somebody point to what am I not understanding here? I have a class, a constructor and a vector to store the data and I want to output a random value in order to get a random enemy in the encounter. Please.

#include <cstdlib>
#include <iostream>
#include <ctime>
#include <vector>
#include <string>

using std::cout;

using std::cin;
using std::endl;
using std::string;
using std::vector;


class Player
{
public:
    int attack;
    int defense;
    int evasion;
    string name;

Player(int atk = 0, int def = 0, int eva = 0, string nameClass = "Wiz")
{
    attack = atk;
    defense = def;
    evasion = eva;
    name = nameClass;
}

void setAttack(int atk)
{
    attack = atk;
}

int getAttack()
{
    return attack;
}

void setDefense(int def)
{
    defense = def;
}

int getDefense()
{
    return defense;
}

void setEvasion(int evs)
{
    evasion = evs;
}

int getEvasion()
{
    return evasion;
}

string getName()
{
    return name;
}
};

class Enemy : public Player
{
public:
    int exp;
    int money;

Enemy(int attack = 0, int defense = 0, int evasion = 0, string name = "Wiz", int money = 0, int exp = 0)
{
}

int getAttack()
{
    return attack;
}

int getDefense()
{
    return defense;
}

int getEvasion()
{
    return evasion;
}

string getName()
{
    return name;
}

int getMoney()
{
    return money;
}

int getExp()
{
    return exp;
}
};


int main() 

{
    srand(time(0));

Enemy timberWolf(5, 15, 0, "Timber Wolf", 40, 20);
Enemy dwarvenSharpshooter(10, 10, 0, "Dwarven Sharpshooter", 60, 30);
Enemy pharaohCat(5, 15, 0, "Pharaoh Cat", 20, 20);
Enemy swashbuckler(5, 20, 0, "Swashbuckler", 20, 10);
Enemy steelBeetle(30, 20, 30, "Steel Beetle", 160, 80);
Enemy scavengingHyena(45, 20, 30, "Scavenging Hyena", 180, 100);
Enemy manaWyrm(35, 45, 30, "Mana Wyrm", 170, 90);
Enemy manaCyclone(35, 20, 30, "Mana Cyclone", 180, 90);
Enemy pyromaniac(65, 35, 45, "Pyromaniac", 290, 160);
Enemy flamewalker(60, 50, 50, "Flamewalker", 320, 160);
Enemy arcaneAmplifier(65, 55, 45, "Arcane Amplifier", 320, 170);
Enemy voidTerror(55, 45, 55, "Void Terror", 310, 170);
Enemy mistwraith(85, 35, 65, "Mistwraith", 330, 175);
Enemy plaguebringer(75, 30, 70, "Plaguebringer", 310, 175);
Enemy henchClanBurglar(80, 35, 85, "Hench-Clan Burglar", 330, 165);
Enemy yeti(80, 40, 60, "Yeti", 320, 180);
Enemy oasisSurger(90, 45, 55, "Oasis Surger", 340, 175);
Enemy starvingBuzzard(85, 45, 60, "Starving Buzzard", 330, 190);
Enemy earthElemental(90, 45, 70, "Earth Elemental", 345, 180);
Enemy abomination(80, 55, 45, "Abomination", 340, 175);
Enemy cenarius(100, 65, 65, "Cenarius", 380, 210);
Enemy kingKrush(100, 70, 60, "King Krush", 400, 220);
Enemy archmageAntonidas(95, 65, 60, "Archmage Antonidas", 380, 210);
Enemy alAkirTheWindlord(90, 60, 65, "Al'Akir the Windlord", 360, 200);
Enemy deathWing(110, 90, 80, "Death Wing");

Player wizard(60, 40, 60, "Wizard");
Player warrior(50, 60, 40, "Warrior");
Player paladin(40, 70, 50, "Paladin");
Player druid(60, 40, 60, "Druid");
Player assassin(70, 30, 70, "Assassin");


vector<Enemy> enemies
{
    {5, 15, 0, "Timber Wolf", 40, 20},
    {10, 10, 0, "Dwarven Sharpshooter", 60, 30},
    {5, 15, 0, "Pharaoh Cat", 20, 20},
    {5, 20, 0, "Swashbuckler", 20, 10},

    {30, 20, 30, "Steel Beetle", 160, 80},
    {45, 20, 30, "Scavenging Hyena", 180, 100},
    {35, 45, 30, "Mana Wyrm", 170, 90},
    {35, 20, 30, "Mana Cyclone", 180, 90},

    {65, 35, 45, "Pyromaniac", 290, 160},
    {60, 50, 50, "Flamewalker", 320, 160},
    {65, 55, 45, "Arcane Amplifier", 320, 170},
    {55, 45, 55, "Void Terror", 310, 170},

    {85, 35, 65, "Mistwraith", 330, 175},
    {75, 30, 70, "Plaguebringer", 310, 175},
    {80, 35, 85, "Hench-Clan Burglar", 330, 165},
    {80, 40, 60, "Yeti", 320, 180},

    {90, 45, 55, "Oasis Surger", 340, 175},
    {85, 45, 60, "Starving Buzzard", 330, 190},
    {90, 45, 70, "Earth Elemental", 345, 180},
    {80, 55, 45, "Abomination", 340, 175},

    {100, 65, 65, "Cenarius", 380, 210},
    {100, 70, 60, "King Krush", 400, 220},
    {95, 65, 60, "Archmage Antonidas", 380, 210},
    {90, 60, 65, "Al'Akir the Windlord", 360, 200},

    {110, 90, 80, "Death Wing"},
};
enemies.insert(enemies.begin(), 26);

cout << enemies[rand() % enemies.size()].getDefense() << endl;

return 0;
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
Enthale
  • 7
  • 6
  • The call to `getName()` is returning one of "name1", "name2", "name3", which is being printed? – Caleth Mar 10 '20 at 21:25
  • None. I get the "something" from the constructor. I have 25 objects inside that vector and I can't get any with that cout << rand...; any idea why? – Enthale Mar 10 '20 at 21:27
  • 2
    Please post a [mcve] – 463035818_is_not_an_ai Mar 10 '20 at 21:29
  • Aside: [`std::sample`](https://en.cppreference.com/w/cpp/algorithm/sample) exists – Caleth Mar 10 '20 at 21:30
  • 2
    btw your inheritance looks a bit odd. Why is every `Enemy` a `Player`? In any case it seems not relevant for the question. Do one thing at a time. A minimal example could use a `std::vector` to print a random element of it – 463035818_is_not_an_ai Mar 10 '20 at 21:31
  • The problem's not with your print statement or your `rand()`. Your code, as shown, will print the result of `getName()` called on a random element of `enemies`. Use your debugger or print statements to see what the contents of the `enemies` is. My best guess without having more context is that you're passing `enemies` by value to a `generateEnemies(std::vector enemies)` function, and expecting it to effect the values in the original `vector`. – JohnFilleau Mar 10 '20 at 21:31
  • Here is a sample text copied in notepad: https://ufile.io/lakow124 I really cannot figure why wouldn't it give a vector value as long as it has the vector inside it formula. – Enthale Mar 10 '20 at 21:32
  • 2
    Please put all relevant text in the question, not as links in comments. I promise I will not click on that link. – JohnFilleau Mar 10 '20 at 21:32
  • Alright, apologies for my mistakes. I began with a class Player which has 4 variables and a Player constructor where the variables are initialized and inside it i put get and set functions so I can change the vector values later as the game goes on. That being said, I did make a subclass Enemy with 2 more variables and Enemy constructor and with it I set the vector values (as you can see a sample in the main text). After initializing things with the constructor value ( Enemy name1(5, 15, 0, "name1", 40, 20);) I set the rand code you saw above. Is this enough info to diagnose this? – Enthale Mar 10 '20 at 21:38
  • I love seeing these game development question. They excite me. I love seeing new programmers interested in learning the language. But in order for us to help you, you MUST read [example] and [ask]. We're not mind readers. We need more relevant context. You may not know what context is relevant, and that's fine, which is why we're asking questions for more clarification. Please clarify, in the question body, when you are able to. – JohnFilleau Mar 10 '20 at 21:38
  • That is not enough to diagnose this. We would need to see where you initialize your `enemies` vector, and where you set the values of each `Enemy` in the vector. As code, please. – JohnFilleau Mar 10 '20 at 21:39
  • You are able to edit your question, as well. Click "edit" right under your question (between "share" and "flag") – JohnFilleau Mar 10 '20 at 21:40
  • Many apologies, I swear I embarassed by this. I wrote the whole bit inside my question. I have more code, but it's below and it wouldn't affect the behaviour. – Enthale Mar 10 '20 at 21:43
  • @Enthale you will be horrified to learn what Undefined Behaviour can do: [ANYTHING](https://en.cppreference.com/w/cpp/language/ub). – user4581301 Mar 10 '20 at 21:45
  • 2
    Your `Enemy` constructor doesn't do anything with its parameters – Alan Birtles Mar 10 '20 at 21:47
  • Found your problem: "Flamewakers" are called "Flamewakers", not "Flamewalkers". They don't have legs. They slither. – JohnFilleau Mar 10 '20 at 21:49
  • Learn about [member initializers](https://stackoverflow.com/q/1711990/10077) and [base class initializers](https://stackoverflow.com/q/7405740/10077). – Fred Larson Mar 10 '20 at 21:49
  • Listen to @Alan above. Your `Enemy` constructor takes a bunch of parameters, but then doesn't do anything with them. C++ will not automatically pass parameters from a derived class constructor to a base class constructor. You need to do something with those parameters in the body of the derived constructor, or you need to call the base constructor in the derived constructor's initializer list, or a combination of the two. – JohnFilleau Mar 10 '20 at 21:52
  • @AlanBirtles I have in the code switch case when the battles are taking place and I want to make something like switch(enemies[rand() % enemies.size()]) and then case 1: {5, 15, 0, "name1", 40, 20}; case 2:{10, 10, 0, "name2", 60, 30}; And for this I need to get the random values from the vector. It has its functionality (though I'm certanly sure somebody with more experience would use a much better solution to this) and I thought it doesnt need to do anything as long as it has values to randomize and output them. – Enthale Mar 10 '20 at 21:54
  • Also, `enemies.insert(enemies.begin(), 26);` is undefined behavior. This will add to a container, by iterating through the same container. Iterating through a container while modifying it is usually undefined. But I feel like you added this line as desperation when you were just trying things. In reality you don't need to do anything like this at all. – JohnFilleau Mar 10 '20 at 21:54
  • @Enthale forget the random selection of an enemy from the vector. Your current problem is that all of your enemies have default initalized member variables. You're not setting their data to anything. They all look the same. – JohnFilleau Mar 10 '20 at 21:56
  • Also, learn to use your debugger. This isn't optional. It's a necessary part of C++ development. Using your debugger you can see the values of different variables in real time during program operation without having to guess if they're right - you can just look at any object and make sure it's behaving as you expect. – JohnFilleau Mar 10 '20 at 21:58
  • @John Yes, you are right. It doesn't make sense the enemies.insert(enemies.begin(), 26); I did it at Player because I wanted to begin with 1, not with 0 and when the user choose the class, he can begin with 1. I will look into yours and Alan's suggetions and try things out. I knew I wasn't writing anything spectacular, but I wanted it to work so I could get some courage to learn more as it goes. Lovely humor with the flamewaker. They are just characters from Hearthstone – Enthale Mar 10 '20 at 22:00
  • Oh, great suggestion. And debugging is so easy with Visual studio. Or at least what I can think it does, of course. Can't comprehend what I don't know. – Enthale Mar 10 '20 at 22:01
  • @Enthale I'm very well aware that these are Hearthstone cards. They're really called "Flamewakers" though. You have "Flamewalker" written in your code. Definitely not causing the logic bug, but thought I'd help with the QA process ahead of time. Do you have a good [C++ Book](https://stackoverflow.com/questions/388242)? You shouldn't try to learn C++ piecemeal off the internet. It's better to have a structured guide. – JohnFilleau Mar 10 '20 at 22:02
  • Oh, I thought that if I call .getAttack or something else, the randomization would have the means to choose from something and not go into an empty space – Enthale Mar 10 '20 at 22:03
  • c++ primer, a tour of c++ and sam teach yourself c++. Though I focus on c++ primer and a tour of c++ – Enthale Mar 10 '20 at 22:04
  • I really don't know what do to now. I'm overwhelmed with the amount of information I've been given these last minutes. If using rand doesn't work even if i write the values something like case 1: wizard.getAttack(), wizard.getDefense(), wizard.getEvasion(), wizard.getName(); break; then I'll have to rewrite it. I'll think about it in the morning as I don't have the capacity right now to make a decision. Thanks for all you guidance and apologies for taking so much time from you. I learned a lot! – Enthale Mar 10 '20 at 22:10
  • Again - the problem is not your use of `rand()`. You're using `rand()` fine. It's just that every `Enemy` in your `std::vector enemies` doesn't have its data members set. The problem is in the constructor for your `Enemy` class. – JohnFilleau Mar 10 '20 at 22:15
  • Alright, I managed to solve it for the moment. I made Enemy the second base class and it works just fine. I will look into properly solving this tomorrow:) Again, thanks a lot! – Enthale Mar 10 '20 at 22:54

1 Answers1

0

Your issue is that you aren't passing arguments from your Enemy constructor to your Players class. This issue is hidden by your use of default arguments. If we remove the default arguments then you should get an error similar to this in the 'Enemy' constructor:

error: no matching function for call to 'Player::Player()'

As you haven't explicitly called the base class constructor the compiler is attempting to call the default one which doesn't exist. The solution is to call the base class constructor:

Enemy(int attack, int defense, int evasion, string name, int money = 0, int exp = 0)
:Player(attack, defense, evasion, name),
 exp(exp),
 money(money)
{
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60