C++ console game: Modifying a battle function that allows different enemy stats - c++

I am creating a game using a 2D array grid, with the player controlling a character with enemies (with different stats/values) around the area. When the character is on the same grid as an enemy, the program initiates a battle function which contains large amounts of code that dictates how the battle works . However, since I want enemies to have different stats, I've been using structures in order to organize character/enemy stats.
For example:
struct Character { //character stats
int hp;
int atk;
int warpstk;
int heal;
int mana;
int money;
};
struct Enemy { //enemy stats
int mhp;
int matk;
int mwarpstk;
int mheal;
};
Character Player =
{
50, //Player.hp
10, //Player.atk
18, //Player.warpstk
12, //Player.heal
30, //Player.mana
50, //Player.money
};
Enemy Goblin =
{
40, //Goblin.mhp
10, //Goblin.matk
12, //Goblin.mwarpstk
8, //Goblin.heal
};
Enemy Dragon =
{
100, //Goblin.mhp
50, //Goblin.matk
70, //Goblin.mwarpstk
15, //Goblin.heal
};
//I want to modify the follow function so that it would change who the player is fighting depending on the grid placement.
void battleSequence(){
while (Player.hp > 0 && Goblin.hp > 0)
{
//randon battle code
}
int main()
{
if (player.x == goblin.x && player.y == goblin.y)
{
battleSequence();
if (Goblin.mhp < 1)
{
goblin.x = 25; //gave the goblin coordinates an out of bounds coordinate to leave loop
goblin.y = 25; //gave the goblin coordinates an out of bounds coordinate to leave loop
system("cls");
}
}
//Probably gonna do the same conditional for the dragon, but it entirely depends on the battle function
}
However, if I were to call the battle sequence function when my character is on the same grid as a goblin, how would I do it so it would be unnecessary to create a battle function of each and every enemy? How would I be able to avoid duplicate code lying around my program? Because so far, I have one function which uses only two variables for player stats: Player and Goblin, and I would hate to create another function for Player and Dragon, due to the length of the function (which is not shown here).
In other words, how would I be able to create ONE general battle sequence function that is accessable for every enemy, but I would only be fighting a "dragon" if I were on their grid, and only a "goblin" if I were on their grid?
(If you need more clarity, please do ask since it is pretty hard to comprehend my question. Ask if you need github repository of my current progress)

Could you simply make a base struct, called characterValues or something, which contains X and Y position, hp, att, Def, heal, and whatever else is common amongst all characters, or at least what's needed to perform a battle. Then the player struct contains an instance of this, as well as the enemy struct.
When you need to calculate the battles, you just need to compair player.charaterValues, with goblin.charaterValues or dragon.charaterValues. If two characters have the same X and Y value, then perform the battle with their health and attack data. Extra info can be stored seperte to this struct, like the players mana, or the enemy's loot data, etc.
If your writing this in c++, you should look upand read about inheritance if you haven't already, which can do some extra tricks along these lines. But with simple c, it can be done with nested structures.
Good luck with your game.

As already pointed out in the other answer, you must find out what all entities (players, goblins and dragons) have in common and create a "base struct", for example a struct CommonEntity, which is comprised of all common properties.
If you want the battle sequence to be strictly player vs. monster (or "enemy"), then it is not necessary for the player properties to be part of the struct CommonEntity. In that case, it would be sufficient for only all common monster properties to be in struct CommonEntity, and you could keep the player properties separate.
However, if monster vs. monster battles should also be possible, and if you want the same function to handle both types of battles, then it would probably be better to include all player properties in the struct CommonEntity, so that the battle function can treat players and monsters in exactly the same way and doesn't even have to know whether the combat participients are players or monsters.
The struct CommonEntity could look like this:
struct CommonEntity
{
//map coordinates
int x;
int y;
//combat stats
int hp;
int atk;
int warpstk;
int heal;
};
All of these properties are shared by both the player and all monsters. If mana can also used in combat, you might want to add it to the struct, and set it to zero for the monsters and nonzero for the players.
However, you probably want to be able to store additional information and the type of the additional information should depend on whether the entity is a player, goblin or dragon. For example, if it is a player, you want to be able to store the amount of money the player has. Therefore, you might want to use a union, like this:
struct AdditionalPlayerData
{
int money;
};
struct AdditionalGoblinData
{
//empty for now
};
struct AdditionalDragonData
{
//empty for now
};
struct Entity
{
//type of entity
enum class EntityType { player, goblin, dragon } type;
CommonEntity common;
union
{
AdditionalPlayerData player;
AdditionalGoblinData goblin;
AdditionalDragonData dragon;
};
};
Now, your struct is capable of storing both general information and additional information specific to the type of entity. You can always see which union field is valid by looking at the type member.
The function which evaluates the battle probably doesn't care about the additional information, it will only need to access the information contained in the common member. Therefore, you will no longer need a different function for handling different entity types, as the function probably won't even care about the type of entity. If it does care for some reason, it can still look up the type member and access the corresponding additional information in the union.
A more object-oriented approach to solving the problem would be the following:
You can use C++ inheritance by defining a common base class, class Entity, for all entities that exist in the game, for example class Player and class Enemy. Also, you can make class Enemy itself a base class for class Goblin, class Dragon, etc. You could then create an array (C-style or std::array) or std::vector of type class Entity * to reference all entities that exist in the game.
The functions which check for encounters and handle the actual battle then only have to deal with objects of type class Entity and do not care of what derived class these objects actually are. If these functions do need to determine the type of the entity, they can call a virtual function on the base class which will then automatically call the corresponding function in the derived class. In my example below, the functions handling the encounters and battles will call the virtual function GetEntityTypeName of class Entity to obtain the name of the entity type (i.e. "player", "goblin" or "dragon"), which they use to print a message about the encounter/battle to the screen.
#include <iostream>
#include <vector>
#include <memory>
#include <random>
class Entity
{
protected:
Entity() = delete;
Entity( int x, int y, int hp, int atk, int warpstk, int heal )
: x(x), y(y), hp(hp), atk(atk), warpstk(warpstk), heal(heal)
{}
public:
int GetX() { return x; }
int GetY() { return y; }
int GetHP() { return hp; }
int GetAttack() { return atk; }
int GetWarpStk() { return warpstk; }
int GetHeal() { return heal; }
void SetX( int newval ) { x = newval; }
void SetY( int newval ) { y = newval; }
void SetHP( int newval ) { hp = newval; }
//the following virtual function will call the derived class's
//function to retrieve the name of the entity type as a string
virtual const char* GetEntityTypeName() = 0;
protected:
//entity's coordinates
int x;
int y;
//entity's combat stats
int hp;
int atk;
int warpstk;
int heal;
};
//class Player inherits from class Entity
class Player : public Entity
{
public:
Player() = delete;
Player( int x, int y ) : Entity(x,y,50,10,18,12), mana(30), money(50) {}
//define additional functions
int GetMana() { return mana; }
int GetMoney() { return money; }
void SetMana( int newval ) { mana = newval; }
void SetMoney( int newval ) { money = newval; }
virtual const char* GetEntityTypeName() { return "player"; }
protected:
//define additional stats that are specific to player
int mana;
int money;
};
class Enemy : public Entity
{
protected:
Enemy() = delete;
Enemy( int x, int y, int hp, int atk, int warpstk, int heal )
: Entity(x, y, hp, atk, warpstk, heal)
{}
public:
//define additional functions here that are specific
//to all enemies, but not specific to certain enemy
//types (goblin, dragon, etc.)
//currently no additional functions
protected:
//define additional stats here that are specific to
//all enemies, but not specific to certain enemy types
//currently no additional stats
};
class Goblin : public Enemy
{
public:
Goblin() = delete;
Goblin( int x, int y ) : Enemy(x,y,40,10,12,8) {}
virtual const char* GetEntityTypeName() { return "goblin"; }
private:
//define additional stats here that are specific to goblins
//currently no additional stats
};
class Dragon : public Enemy
{
public:
Dragon() = delete;
Dragon( int x, int y ) : Enemy(x,y,100,50,70,15) {}
virtual const char* GetEntityTypeName() { return "dragon"; }
private:
//define additional stats here that are specific to dragons
//currently no additional stats
};
int MakeRandom( int min, int max, std::mt19937 &rng )
{
std::uniform_int_distribution<int> dis( min, max );
return dis( rng );
}
void PerformAttack( Entity &attacker, Entity &defender, std::mt19937 &rng )
{
int attack_strength = MakeRandom( 0, attacker.GetAttack(), rng );
std::cout << " " << attacker.GetEntityTypeName() << " hits " <<
defender.GetEntityTypeName() << " for " << attack_strength << " points\n";
defender.SetHP( defender.GetHP() - attack_strength );
}
void PerformBattleRound( Entity &e1, Entity &e2, std::mt19937 &rng )
{
Entity *first, *second;
//randomize which entity attacks first
if ( MakeRandom( 0, 1, rng ) == 0 )
{
first = &e1;
second = &e2;
}
else
{
first = &e2;
second = &e1;
}
//perform first attack
PerformAttack( *first, *second, rng );
if ( second->GetHP() <= 0 )
{
std::cout << " " << second->GetEntityTypeName() << " dies\n\n";
return;
}
else
{
std::cout << " " << second->GetEntityTypeName() << " has " <<
second->GetHP() << " HP remaining\n";
}
//perform second (counter) attack
PerformAttack( *second, *first, rng );
if ( first->GetHP() <= 0 )
{
std::cout << " " << first->GetEntityTypeName() << " dies\n\n";
return;
}
else
{
std::cout << " " << first->GetEntityTypeName() << " has " <<
first->GetHP() << " HP remaining\n";
}
std::cout << "\n";
}
void ProcessEncounters( std::vector<std::unique_ptr<Entity>> &entity_list, std::mt19937 &rng )
{
//this function does not only check encounters between player
//and enemies, but also enemies and enemies
int size = entity_list.size();
for ( int i = 0; i < size; i++ )
{
for ( int j = i + 1; j < size; j++ )
{
//check if both entities have the same coordinates
if (
entity_list[i]->GetX() == entity_list[j]->GetX() &&
entity_list[i]->GetY() == entity_list[j]->GetY()
)
{
//print information about encounter
std::cout <<
entity_list[i]->GetEntityTypeName() << " encounters " <<
entity_list[j]->GetEntityTypeName() << " at (" <<
entity_list[i]->GetX() << "," <<
entity_list[i]->GetY() << ")\n";
PerformBattleRound( *entity_list[i], *entity_list[j], rng );
}
}
}
}
int main()
{
//create a vector to contain all entities
std::vector<std::unique_ptr<Entity>> entity_list;
//seed the random number generator
std::random_device rd;
std::mt19937 rng( rd() );
//create player at coordinates (5,7)
entity_list.push_back( std::make_unique<Player>( 5, 7 ) );
//create goblin at coordinates (2,3)
entity_list.push_back( std::make_unique<Goblin>( 2, 3 ) );
//create goblin at coordinates (5,7)
entity_list.push_back( std::make_unique<Goblin>( 5, 7 ) );
//create goblin at coordinates (8,9)
entity_list.push_back( std::make_unique<Goblin>( 8, 9 ) );
//create dragon at coordinates (8,9)
entity_list.push_back( std::make_unique<Dragon>( 8, 9 ) );
ProcessEncounters( entity_list, rng );
}
}
The code above will print the following output:
player encounters goblin at (5,7)
goblin hits player for 1 points
player has 49 HP remaining
player hits goblin for 10 points
goblin has 30 HP remaining
goblin encounters dragon at (8,9)
goblin hits dragon for 2 points
dragon has 98 HP remaining
dragon hits goblin for 42 points
goblin dies
Due to the random number generator, the output will be different every time you run the program.
As you can see, I don't need an extra function for handling every type of entity, because the functions handling the encounter/battle do not even care about the type of entity they are dealing with.
Note that if you have 10,000 entities in the game, and if enemies can also encounter each other (not only the player), then it will take nearly 5 million(!) comparisons to compare every entity's coordinates with every other entity, as the time complexity is O(n2). Therefore, if you have that many entities, you might want to consider dividing the map into a grid of, for example, 100*100 tiles and keep a separate list of all entities that exist in every tile of that grid. That way, assuming 10,000 entities, you will only have to compare every entity with the coodinates of one other entity on average, instead of all other 10,000 entities. But as long as you have less than 100 entities in the game, it should not be a problem. Also, if enemies cannot encounter each other, then this will also not be a problem, as the time complexity will only be O(n) instead of O(n2).

Related

How to reset number of instances of a class to 1 on every loop iteration?

I have a player class where I am storing the player's current position, the number of players in the game and a static variable to store the total number of players like so:
#ifndef PLAYER_H
#define PLAYER_H
#include <ctime>
#include <random>
#include <iostream>
using std::time;
using std::cout;
class Player
{
private:
int m_Player_currentPosition, m_Player_number;
static int m_Player_numberOfPlayers;
public:
Player::Player():m_Player_currentPosition(1) {
m_Player_number = m_Player_numberOfPlayers;
++m_Player_numberOfPlayers;
}
void m_Player_SetPosition();
int m_Player_GetPosition();
int m_Player_GetPlayerNumber() { return m_Player_number; }
void m_Player_SetNumberOfPlayers() { m_Player_numberOfPlayers = 1; }
~Player() { --m_Player_numberOfPlayers; }
};
int Player::m_Player_numberOfPlayers = 1;
#endif
I also have a game class that creates a certain number of player instances using a vector. In my game class, the plan is to create players depending on user input (between 2-4 number of players) using m_Game_SetPlayers() member function and also printing the details of the players using the m_Game_PrintPlayers() member function.
#ifndef GAME_H
#define GAME_H
#include <iostream>
#include "Board.h"
#include "Player.h"
using std::cout;
using std::cin;
using std::vector;
class Game {
private:
bool m_Game_quit;
int m_Game_choice;
Board board;
vector<Player> m_Game_players;
public:
Game();
const bool &m_Game_GetQuit() const;
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.resize(numberOfPlayers);
}
void m_Game_PrintMenu();
void m_Game_PrintInstructions();
void m_Game_GetChoice();
void m_Game_PrintPlayers()
{
cout << '\n';
vector<Player>::iterator iter;
for (iter = m_Game_players.begin(); iter != m_Game_players.end(); ++ iter) {
cout << "Player " << iter->m_Player_GetPlayerNumber() << "'s position: " << iter-
>m_Player_GetPosition() << '\n';
}
}
void Update();
};
#endif // !GAME_H
However, in my main class, I am calling the Game class's update function under a while loop. Here is my game update member function declared in a separate implementation file that decides the control flow of the game.
void Game::Update()
{
m_Game_GetChoice();
switch (m_Game_choice) {
case 0: cout << "---Bye---\n";
m_Game_quit = true;
break;
case 1:
system("cls");
m_Game_PrintInstructions();
break;
case 2:
system("cls");
m_Game_SetPlayers();
system("cls");
board.m_Board_PrintBoard();
m_Game_PrintPlayers();
m_Game_players[0].m_Player_SetNumberOfPlayers();
break;
default:
cout << "--Invalid Option---\n";
break;
}
}
Here is my while loop in the main function:
#include "Game.h"
int main() {
Game game;
while (!game.m_Game_GetQuit()) {
system("cls");
game.m_Game_PrintMenu();
game.Update();
system("pause");
}
}
When I ran this program the first time, it worked as expected. However, imagine if I choose the play option from the menu and I enter 2 players, it creates 2 instances of the player class. On the next while loop iteration, I increase the size to 4 players which also works perfectly sometimes. Then, when I reduce the size and then again increase the size, the player number does not match. Here are the following images to help understand the problem:
Input 1: https://i.stack.imgur.com/reHjE.png
Output 1: https://i.stack.imgur.com/Dt68V.png
Input 2: https://i.stack.imgur.com/Xo83c.png
Output 2: https://i.stack.imgur.com/2Qso6.png
The expected output is:
Player's position 1: 1
Player's position 2: 1
Player's position 3: 1
So, I thought that I need to delete my instances, but since I cannot delete instances on a stack memory as long as I am in a while loop (How do I manually delete an instance of a class?, http://www.cplusplus.com/forum/beginner/107822/). I thought that I will resize the vector. It did resize the vector, but then it does not delete the instances of the player class but instead created a new instance of that class. Is there a way to destroy all the instances of the class on a stack memory even when it is inside the scope? If not, how do I solve this problem?
I may/may not have provided the code needed to debug this problem. So, I have attached my entire code on https://github.com/F3INTH34RTED/Cpp/tree/master/Beginner/16SnakesAndLadder if need be.
When you increase the size of the vector, say from 2 to 3, it only needs to create one new instance of Player, so it will create a single player with the next number.
The line
m_Game_players[0].m_Player_SetNumberOfPlayers();
on the previous loop iteration sets the global counter to 1. So this single new player gets number 1, not number 3 like you expect. You should be able to remove the above line and things will work as expected.
On a design note, it would probably be wiser to recreate the vector entirely when the number of players is changed and explicitly give each player a number via the constructor, like this:
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.clear();
for (int i = 1; i < numberOfPlayers; i++) {
m_Game_players.push_back(Player(i));
}
}
Updating the Player constructor to match, of course.
Your issue is that std::vector::push_back will do copy/move when it needs to resize internal buffer, and your (auto generated default) copy/move constructors doesn't handle that, you might do for example:
class Player
{
private:
int m_currentPosition;
std::optional<int> m_number;
static int m_numberOfPlayers;
public:
Player() : m_currentPosition(1), m_number(++m_numberOfPlayer) {}
Player(const Player&) = delete;
Player(Player&& rhs) : m_currentPosition(rhs.m_currentPosition), m_number(rhs.m_number) { rhs.m_number = std::nullopt; }
Player& operator = (const Player&) = delete;
Player& operator = (Player&& rhs) { std::swap(m_currentPosition, rhs.m_currentPosition); std::swap(m_number, rhs.m_number); }
int GetPlayerNumber() const { return *m_number; }
~Player() { if (m_number) --m_numberOfPlayers; }
};

Using vector of a class that contains static member variable

I had an Airplane class and this Airplane had a vector of Seat class named "m_seat".
In the Constructor of my Airplane, I used the number of seats as the needed parameter to resize the m_seat vector size to the requested size of the user. This was my code:
class Seat;
class Airplane {
vector<Seat> m_seat;
public:
Airplane(int);
};
class Seat{
static int m_seatNumber;
public:
Seat() { m_seatNumber += 10; }
};
int Seat::m_seatNumber = 100;
Airplane::Airplane(int numberOfSeats) {
for (int i = 0; i<numberOfSeats; ++i) {
m_seat.push_back();
}
}
int main()
{
Airplane(80);
return 0;
}
But it gave this error.
std::vector<_Ty,_Aloc>::push_back no overload of function takes 0 arguments,
and if this was really the problem, I had no idea what should I have put in my push_back()? So I tried {}
m_seat.push_back({});
and It worked!
Now, I have another problem which is my main problem(SO rule: Ask only one question at a time!) that all seat numbers appear to be increased to the same number! I also used the "resize" member function of the vector, instead of that loop:
m_seat.resize(numberOfSeats);
But the problem (same increase in the number of the m_seatNumber) remains unsolved.
Non-native English Speaker, Sorry.
Disclaimer: This is a "best guess" answer.
If you wanted each seat to have a different, automatically increasing number, you need two values; one non-static, describing each seat, and one static, describing last-used number:
class Seat{
static int lastSeatNumber;
int seatNumber;
public:
Seat() { seatNumber = lastSeatNumber; lastSeatNumber += 10; }
};
int Seat::lastSeatNumber = 100;
That way each seat will receive its distinct number. This design is bad, however, as it doesn't allow e.g. seat number sharing between two airplanes! It also doesn't allow you to "free up" the numbers of seats you're no longer using, and the number can only keep growing. Also copying a Seat, while possible, won't manipulate that number at all. It'd be much better to allow the Airplane class to assign the seat numbers:
class Seat{
int seatNumber;
public:
Seat(int seatNumber) : seatNumber(seatNumber) { }
};
Airplane::Airplane(int numberOfSeats) {
int seatNumber = 100;
const int numberIncrement = 10;
for (int i = 0; i < numberOfSeats; ++i) {
m_seat.push_back(Seat(seatNumber));
seatNumber += numberIncrement;
}
}
This way you can get the old behavior by adding another parameter to the airplane constructor telling it which number to start counting from.

map<string, class> using and couting

I have few maps in my project, which I don't know, how to use or simple said: I don't know how to cout some info from map, which has class attached.
My code (item.h):
#ifndef ITEM_H
#define ITEM_H
class Item
{
public:
int level, durability, damage, armor, weight, grade, sex;
Item(int _level, int _durability, int _damage, int _armor, int _weight, int _grade, int _sex);
Item();
virtual ~Item();
protected:
private:
};
#endif // ITEM_H
code (item.cpp):
#include "include/Item.h"
Item::Item(int _level, int _durability, int _damage, int _armor, int _weight, int _grade, int _sex)
{
level = _level;
durability = _durability;
damage = _damage;
armor = _armor;
weight = _weight;
grade = _grade;
sex = _sex;
}
Item::Item(): level(0), durability(20), damage(0), armor(0), weight(1), grade(1), sex(0)
{
//dtor
}
Item::~Item()
{
//dtor
}
Code (main.cpp):
std::map<std::string, Item> item;
// level, durability, damage, armor, weight, grade, sex
item.insert(std::pair<std::string, Item>("Wooden Sword", Item(1, 19, 3, 0, 1, 1, 0)));
How to cout some info from the selected array from map? Tried searching in the google, etc. Can't find answer and explanation why do I get error if I try something like this:
cout << item["Wooden Sword"]["level"];
for what purpose you can use item.find("Wooden Sword"); ?
how does map work with classes? How can I select data from maps which have classes. Really thanks in advance. :) Hope I explained what I want and gave you everything that you need.
The index operator returns a reference to the data element, in your case it returns an Item& that you use as a normal structure:
std::cout << item["Wooden Sword"].level << '\n';
As for the find function it returns an iterator. If you don't know about iterators, study them first.
If you want a good reference, see e.g. this site.
Using item.find("Wooden Sword"); you get an iterator to the matching key/value pair element. If there is no key like "Wooden Sword" it returns end(item);. Use find if you don't know if the item exists and don't want to add one.
auto it = item.find("Wooden Sword");
if (it != end(item))
{
std::cout << it->level; // use the -> operator
// std::string key = it.first;
// Item& item = it.second;
}
else
std::cout << "There is no Wooden Sword";
The []operator returns a reference to the matching item. If there is no item associated with this key, a new item will be inserted at this position.
std::cout << item["Wooden Sword"].level;

C++ Object or 2-dimensional Array as a Parameter?

In a Tic Tac Toe game I creating for school I have five classes: Game (acts as a controller for the game), Player (base class), HumanPlayer and AIPlayer (both derived from Player), and Board.
Board contains a 2D array and some functions for displaying and working on the array. All three player classes have a function makeAMove(Board &board) which will choose a position on the board and place an X or an O.
As you can see makeAMove accepts a Board object as a parameter. Then the function will decide on a move and alter the Board object's board array. If I'm understanding correctly, the actual object being passed in will be altered and there will not be any need to return anything back.
Am I understanding this correctly? Would it be better to use the 2d array as the parameter instead?
Here is a condensed version of my code.
#include <iostream>
#include <memory> // auto_ptr
class Board
{
public:
Board()
{
for (int row = 0; row < 3; row++)
{
for (int column = 0; column < 3; column++)
board[row][column] = ' ';
}
}
void displayBoard()
{
std::cout << "\n-------------" << std::endl;
for (int row = 0; row < 3; row++)
{
std::cout << "| " ;
for (int column = 0; column < 3; column++)
std::cout << board[row][column] << " | ";
std::cout << "\n-------------" << std::endl;
}
}
/* My thought was to use getBoard to return the array rather than using the
object as a parameter
char getBoard()
{
return board[][3];
}
*/
char getCell(int row, int column)
{
return board[row][column];
}
void setCell(int row, int column, char player)
{
board[row][column] = player;
}
private:
char board[3][3];
};
class Player
{
public:
virtual void makeAMove(Board &board) = 0;
};
class AIPlayer : public Player
{
virtual void makeAMove(Board &board)
{
// do some work ont the board array
}
};
class HumanPlayer : public Player
{
virtual void makeAMove(Board &board)
{
// do some work on the board array
}
};
class Game
{
public:
Game(unsigned int players)
{
if (players == 1)
{
player1.reset (new HumanPlayer());
player2.reset (new AIPlayer());
}
else
{
player1.reset (new HumanPlayer());
player2.reset (new HumanPlayer());
}
}
void playGame()
{
player1->makeAMove(myBoard);
}
private:
std::auto_ptr<Player> player1; // pointer to a Player object (C++11 has more secure unique_ptr)
std::auto_ptr<Player> player2; // pointer to a Player object
Board myBoard;
};
int main()
{
Game myGame(1);
myGame.playGame();
return 0;
}
Yes because you're passing the Board object by reference, any change to it in the function will alter the actual Board object. I think passing a Board object is a better idea, as it is better not to expose the actual implementation ( a 2D array in this case) of the game to the user. So passing as Board object gives more abstraction, which is good.
makeAMove belongs in board. The player objects should decide what move to make, then call board::makeAMove to make the move. That way the player objects don't care what the internal representation of the board is.
Pass the object by reference as you are instead of the array. Any alterations made by the player on the board will persist.
board is a private member of Board. It should only ever be returned by value and not by reference. If you pass the 2d array to the player by Value any changes they make to the board will not persist.
Your Player classes will need to access Board.setCell(int, int), in the makeAMove(Board &board) function and to do that they will need the board object.
However your Players classes will need to read the board. In order to make a move. The getCell(int,int) function might be enough but it might also be tedious to nested loop through all of the cells. A getBoard might be useful for a possible decideMove function.

Aggregation using C++

I am trying to make one class work with another class. It is supposed to decrement the member of the other class.
my first class is
class Bike
{
private:
int miles;
Speedometer speedom;
static int fuelCount;
public:
Bike();
Bike(int, Speedometer*); //Problem occurs here
~Bike();
int getMiles();
int getFuelCount();
void incrementMiles();
};
int Bike::fuelCount = 0;
Bike::Bike()
{
miles = 0;
fuelCount++;
}
Bike::Bike(int m, Speedometer * spm) //This is where I am having problems
{
miles = m;
speedom = &spm;
}
Bike::~Bike()
{
cout << "The Bike's destructor is running." << endl;
fuelCount--;
}
int Bike::getMiles()
{
return miles;
}
int Bike::getFuelCount()
{
return fuelCount;
}
void Bike::incrementMiles()
{
miles++;
if (miles == 999999)
miles = 0;
}
The other class which is supposed to be included in the first is:
Class Speedometer
{
private:
int fuel;
public:
Speedometer();
Speedometer(int);
~Speedometer();
int getFuel();
void incrementFuel();
void decrementFuel();
};
Speedometer::Speedometer()
{
fuel = 0;
}
Speedometer::Speedometer(int f)
{
fuel = f;
}
int Speedometer::getFuel()
{
return fuel;
}
void Speedometer::incrementFuel()
{
if (fuel <= 15)
fuel++;
}
void Speedometer::decrementFuel()
{
if (fuel > 0)
fuel--;
}
They are supposed to work together. Bike is to be able to work with speedometer object. It should decrease the speedometers current amount of fuel by one gallon for every 24 miles traveled.
This is supposed to be a aggregate relationship not composition.
Please help me just understand how to make that relationship and how its supposed to be called.
Thank you in advance.
here is my main function
btw - i have all the right #includes i just have not listed them here
int main(int argc, char *argv[])
{
Speedometer a(999970, spd);
for(int count = 0; count <=24; count++)
a.decrementMiles();
while (a.getFuel() > 0)
{
a.incrementMiles();
cout<< "Miles:" << a.getMiles() << endl;
cout<< "Fuel:" << a.getFuel() << endl;
}
return 0;
}
You have a large number of issues here.
First of all, in your main(), you construct your Speedometer object with a constructor you have not implemented. The only constructors you have defined are the default constructor and Speedometer(int). You then call Speedometer(int, ???), the ??? being spd because you do not declare spd anywhere in the code you have provided, so we have no idea what it is.
It's really impossible to say what's wrong with your code in its current state.
As written, you've made a composition; Speedometer is part of Bike since it is a field. To make it an aggregation, make Bike hold a pointer to Speedometer. Note that as a consequence, you'll probably need Bike to create or obtain an initial Speedometer (could be NULL to begin with, or pass one in the constructor), and you might want to add accessor methods to Bike in order to add/remove/change the Speedometer.
[edit] Bike might also need to know how to dispose of the Speedometer properly in order to avoid leaking it.
[edit 2] Also as #cjm571 pointed out, your main function is creating and operating directly upon a "disembodied" Speedometer. Shouldn't it be on a Bike? :)
#include <iostream>
using namespace std;
class Bike
{
private:
int miles;
static int fuelCount;
// Speedometer speedom;
public:
Bike();
Bike(int); // Speedometer *); check comment on line 82
~Bike();
int getMiles();
int getFuelCount();
void incrementMiles();
};
int Bike::fuelCount = 0;
Bike::Bike()
{
miles = 0;
fuelCount++;
}
Bike::Bike(int m)//Speedometer (*spm) I don't see the purpose of this in the current state of the program, I may not be seing the whole picture
{
miles = m;
/* speedom = spm; remember, there must be a parent and a child class, at the current state you'r trying
to call a child from parent, the child class has not been defined, so i switched them and now Bike is a chiled. */
}
Bike::~Bike()
{
cout << "The Bike's destructor is running." << endl;
fuelCount--;
}
int Bike::getMiles()
{
return miles;
}
int Bike::getFuelCount()
{
return fuelCount;
}
void Bike::incrementMiles()
{
miles++;
if (miles == 999)
miles = 0;
}
class Speedometer
{
private:
int fuel;
public:
Speedometer();
Speedometer(int f);
int getFuel();
Bike theBike; // This is what you needed in order to make incrementMiles to work.
void incrementFuel();
void decrementFuel();
};
Speedometer::Speedometer()
{
fuel = 0;
}
Speedometer::Speedometer(int f)
{
fuel = f;
}
int Speedometer::getFuel()
{
return fuel;
}
void Speedometer::incrementFuel()
{
if (fuel <= 15)
fuel++;
}
void Speedometer::decrementFuel()
{
if (fuel > 0)
fuel--;
}
int main(int argc, char *argv[])
{
Speedometer a(999); //You never declared this, did you mean spm???
for(int count = 0; count <=24; count++)
a.theBike.incrementMiles();
while (a.getFuel() > 0)
{
a.theBike.incrementMiles();
cout<< "Miles:" << a.theBike.getMiles() << endl;
cout<< "Fuel:" << a.getFuel() << endl;
}
cin.get();
return 0;
} //There is no break declared (that i can see at least) so the program runs an infinite loop
// Don't want to add too many things to it, I don't know what your plan is.
// Hoping to have made it clearer.