changing QVector variables from separate functions - c++

I have a function in deck.cpp which deals random cards from a deck:
QVector<card> Deck::deal_rand_cards(QVector<card> vDeck, int quantity)
{
QVector<card> vDealt;
int deckSize = vDeck.size();
card randCard;
qsrand(QTime::currentTime().msec());
for (int i=0;i<quantity;i++)
{
int rn=rand()%deckSize;
randCard = vDeck[rn];
qDebug()<<vDeck.size();
vDealt.append(randCard);
vDeck.remove(rn);
}
return vDealt;
}
My issue is that everytime the function is run from mainwindow.cpp, vDeck contains the full deck, instead of the deck minus dealt cards which i removed with the function.
If I deal 3 cards twice, debug prints:
54 53 52 54 53 52
How to update a variable within a function that is used by other functions and in other files? I have a feeling a pointer is involved, but I still don't quite grasp the concept.
Thanks
here's deck.h
#ifndef DECK_H
#define DECK_H
#include <QString>
#include <QVector>
struct card
{
QString suit;
QString color;
int rank;
};
class Deck
{
private:
int size;
int jokers;
public:
QVector<card> build_deck(int deckSize, int jokers);
QVector<card> deal_rand_cards(QVector<card> vDeck, int quantity);
};
#endif // DECK_H

You need to pass reference of vDeck into deal_rand_cars function, currently you are working on a copy of vDeck.
QVector<card> deal_rand_cards(QVector<card> &vDeck, int quantity);
^^^ pass by reference
If you use a reference as an argument, the function works with the original data instead of with a copy.

Related

Problem with Deck reset function in a Deck

I am currently working on making a program where a deck of 52 cards are displayed. You will be able to reset the deck, pick a card or exit the program. I have gotten the Card.h and Card.cpp parts done without any issue.
Card.h:
enum class Suit
{
Spades,
Hearts,
Diamonds,
Clubs
};
class Card
{
private:
int m_value;
Suit m_suit;
void display();
void set(int v, Suit s);
int getValue();
Suit getSuit();
};
Card.cpp:
#include "Card.h"
#include <iostream>
using namespace std;
Card::Card() :
m_value()
{
}
void Card::display()
{
if (m_value != 0)
{
cout << m_value; m_suit;
}
else
{
cout << "--";
}
}
void Card::set(int v, Suit s)
{
m_value = v;
m_suit = s;
}
int Card::getValue()
{
return m_value;
}
Suit Card::getSuit()
{
return Suit();
}
I have also managed to successfully write in the code for Deck.h, shown below:
#pragma once
#include "Card.h"
class Deck
{
public:
static const int c_numCards = 52;
private:
int m_cards[c_numCards];
int m_cardsLeft;
void reset();
void display();
bool pickCard(Card& card);
};
However, I have been struggling with the reset method, shown below:
#include "Deck.h"
#include "Card.h"
#include <iostream>
Deck::Deck() :
m_cards{},
m_cardsLeft()
{
}
void Deck::reset()
{
//This method initializes the deck setting all card values and suits in order of value (1’s in each suit, then 2’s,etc)//
int i = 1;
for(int j = 0; j < 14; j++)
{
m_cards[j].set(i, Suit::Spades);
m_cards[j + 1].set(i, Suit::Hearts);
m_cards[j + 2].set(i, Suit::Diamonds);
m_cards[j + 3].set(i, Suit::Clubs);
j = j + 4;
}
}
void Deck::display()
{
//This method displays the entire deck using the display() method//
}
bool Deck::pickCard(Card& card)
{
//This method passes in a "blank" card object. It chooses a single card on random, copying it into the object and returns it true. When its picked, the card is no longer capable of being chosen in the deck.
//however, if there are no more cards left to be chosen, it will return false.//
}
as clarification, I haven't done the other methods yet since my way of doing stuff forces me to focus on one part first before anything else.
I mainly want help for the reset method, although help for the two other methods would be appreciated. I haven't included main since I seek to figure that part out on my own.
I also want to clarify, this does not have any vectors. It specifically needs arrays, unscoped and scoped enums
I have attempted various ways of rendering the code, such as with if statements, but so far only this one has proven successful. everything works fine, but Visual Studios tells me that int statements dont work, and whenever I attempt to change it gives me new errors.

How can I best decouple two classes, which one way dependencies

I am attempting to create a D&D combat encounter simulator using C++ and since it's D&D, all aspects of the simulation are going to depend heavily on the "Dice" Class and its methods.
I could instantiate a "Dice" object every time another class needs
to invoke its methods, however, that would leave everything heavily
coupled and make it very difficult to make changes or extensions later.
I don't have any practical knowledge about things such as Factories, dependency injections, and other such methods.
My question therefore in essence is:
What would be the best way to ensure that the "Dice" class remains as
decoupled as possible from all other classes?
While still enabling them to make use of the "Dice" objects, and its methods, when needed.
Dice.h
#ifndef dice_h_
#define dice_h_
#include <stdlib.h>
class Dice
{
private:
int maxValue;
public:
Dice(int maxValue);
~Dice();
int getMaxValue( void ){return maxValue;}
void setMaxValue(int newMaxValue){maxValue = newMaxValue;}
int rollDice();
int rollMultipleDice(int numberOfDiceRolls);
};
#endif
Dice.cpp
#ifndef dice_cpp_
#define dice_cpp_
#include "dice.h"
Dice::Dice(int maxValue){this->maxValue = maxValue;}
Dice::~Dice(){}
int Dice::rollDice()
{
return (rand() % maxValue) + 1;
}
int Dice::rollMultipleDice(int numberOfDiceRolls)
{
int i = numberOfDiceRolls, sum = 0;
while(i-- > 0)
{
sum += rollDice();
}
return sum;
}
#endif
Actor.h
#ifndef actor_h_
#define actor_h_
#include "dice.h"
class Actor
{
private:
unsigned int hp;
unsigned int ac; // Armor Class
unsigned int dmg;
public:
Actor(unsigned int hp, unsigned int ac, unsigned int dmg);
~Actor();
unsigned int getHP( void );
unsigned int getAC( void );
unsigned int getDmg( void );
void setHP( unsigned int newHP);
void setAC( unsigned int newAC);
void setDmg( unsigned int newDmg);
void attack(Actor* target);
bool isHit(Actor target);
};
#endif
Actor.cpp
#ifndef actor_cpp_
#define actor_cpp_
#include "actor.h"
Actor::Actor(unsigned int hp, unsigned int ac, unsigned int dmg)
{
this->hp = hp;
this->ac = ac;
this->dmg = dmg;
}
Actor::~Actor(){}
unsigned int Actor::getHP( void ){return hp;}
unsigned int Actor::getAC( void ){return ac;}
unsigned int Actor::getDmg( void ){return dmg;}
void Actor::setHP( unsigned int newHP ){this->hp = newHP;}
void Actor::setAC( unsigned int newAC ){this->ac = newAC;}
void Actor::setDmg( unsigned int newDmg ){this->dmg = newDmg;}
void Actor::attack(Actor* target)
{
Dice damageDice(8);
if (isHit(*target))
{
target->setHP(target->getHP() - damageDice.rollDice());
}
}
// helper function to attack function
// do not use elsewhere
bool Actor::isHit(Actor target)
{
Dice atkDice(20);
return atkDice.rollDice() >= target.getAC();
}
#endif
You talk about singletons and the like in the question so do you want ever class that needs to use the dice to use the same instance of the Dice class?
If so since the Dice class doesn't have any states to hold onto it can be a static class. I would then remove the MaxValue and add an input to the RollDice and RollMutiDice to take a Max Value (which I am guessing is suppose to the "sides" of the dice). So a call to Dice::RollDice(3) is to roll a 3 sided dice or Dice::RollMutiDice(6,3) would roll a 6 sided dice 3 times.
Also make sure you send the rand() class. I think is it srand(int). Usually you pass it time so it is fairly random

How do I properly handle #includes in multi-file programming

First post so take it easy on me :). I don't think I really need to put up any actual code for this, but let me know if I'm wrong. This is for a homework assignment in my college programming class. I am confused as to how to properly use my #include statements. Here is my file structure:
Header Files-->
header.h (Main header file, contains #include for various libraries, declares namespace, and provides my name and class info)
room.h (Blueprint for the room class)
ship.h (Blueprint for the ship class)
Source Files-->
main.cpp (Main Program)
functions.cpp (Functions for the main program)
room.cpp (Functions in the Room class)
ship.cpp (Functions in the Ship class)
Basically, my first instinct was to " #include "header.h" " in room.h, ship.h, main.cpp, and functions.cpp. Then " #include "ship.h" in ship.cpp, and " #include room.h " in room.cpp. However I began getting errors up the wazoo. I was having a similar problem during class but I had my teacher there to sort it out and I'm not exactly sure how we did it, and I also know that tons of errors usually indicates an include error.
Its annoying because I had it working somehow before I added the functions.cpp, but I really want to keep main.cpp pretty clean, so I would rather have functions in a separate file.
What is the best pattern for includes in a situation like this?
EDIT: I'll post my 3 header files
header.h
/*
Author: *********
Class : **********
Assignment : Programming Assignment 2
Description :
This program will construct a ship for the user. It accepts input from a file
containing information on various rooms. It will then check the rooms
validity and add it to the ship if it's valid. Once all of the rooms have been added,
the program will determine if the entire ship is valid and let the user know.
Certification of Authenticity :
I certify that this is entirely my own work, except where I have given
fully - documented references to the work of others.I understand the
definition and consequences of plagiarism and acknowledge that the assessor
of this assignment may, for the purpose of assessing this assignment :
-Reproduce this assignment and provide a copy to another member of
academic staff; and / or
- Communicate a copy of this assignment to a plagiarism checking
service(which may then retain a copy of this assignment on its
database for the purpose of future plagiarism checking)
*/
#ifndef header_h
#define header_h
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
#endif
room.h
#ifndef room_h
#define room_h
#include "header.h"
enum RoomType
{
UNKNOWN = -1,
BAY,
LATRINE,
CABIN,
BRIDGE,
NUM_ROOM_TYPES
};
const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
class Room
{
public:
//default constructor
Room();
//constructor
Room( RoomType type, int width, int breadth, int height );
//destructor
~Room(){};
//accessors
inline RoomType getType() const { return mType; };
inline int getHeight() const { return mHeight; };
inline int getWidth() const { return mWidth; };
inline int getBreadth() const { return mBreadth; };
inline int getVolume() const { return getWidth() * getBreadth() * getHeight(); }; //currently unused
inline string getRoomName(){ return ROOM_STRINGS[mType]; };
string getDescription();
//mutators
void setType(RoomType type) {mType = type; };
void setHeight(int height) {mHeight = height; };
void setWidth(int width) {mWidth = width; };
void setBreadth(int breadth) {mBreadth = breadth; };
private:
//type of room
RoomType mType;
//floor dimensions - in feet
int mWidth;
int mBreadth;
//ceiling height - in feet
int mHeight;
};
#endif
ship.h
#ifndef ship_h
#define ship_h
#include "header.h"
const int MAX_BAY = 4;
const int MAX_LATRINE = 15;
const int MAX_BRIDGE = 1;
const int MAX_CABIN = 25;
const int MIN_BAY = 1;
const int MIN_LATRINE = 1;
const int MIN_BRIDGE = 1;
const int MIN_CABIN = 0;
const int MIN_ROOM_HEIGHT = 7;
const int MIN_ROOM_AREA = 20;
class Ship{
public:
Ship();
bool addRoom(const Room& theRoom);
string getDescription();
//Accessors
int getNumBays(){ return bayTotal; };
int getNumLatrines(){ return latrineTotal; };
int getNumBridges(){ return bridgeTotal; };
int getNumCabins(){ return cabinTotal; };
int getTotalSquareFootage(){ return totalSquareFootage; };
private:
Room Bay[MAX_BAY];
Room Latrine[MAX_LATRINE];
Room Bridge[MAX_BRIDGE];
Room Cabin[MAX_CABIN];
int bayTotal;
int latrineTotal;
int bridgeTotal;
int cabinTotal;
int totalSquareFootage;
bool isShipValid();
void addSquareFootage(float);
};
#endif
What kind of errors? Your issue might be including the same header more than once.
Try adding this to each header:
#ifndef ROOM_H
#define ROOM_H
... code ...
#endif
To be clear the 'ROOM_H' above needs to be unique to each header.
If you use #include "room.h" in different cpp files then you probably get a linker error because this below here is not a type declaration.
const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
You are creating and allocating a variable with name ROOM_STRINGS. By declaring it in different cpp files you will have multiple copies of the same global variable which is an error. You could replace it with
static const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
You will still have multiple copies but each cpp file will have its own private copy. A better solution is to move this declaration into the room cpp file together with the code of the getRoomName.
Or you could declare ROOM_STRINGS as extern in the header and then you still need to add the variable allocation in a cpp file.

C++ object orientated issue

I am trying to learn C++ OOP and I made the follwing code:
main.cpp
#include <iostream>
#include <string>
#include "monster.h"
using namespace std;
int main(int argc, char** argv) {
Monster monster("Wizard",150,50);
Monster monster2("Gorgoyle",450,15);
cout << monster2.getHealth() << endl;
monster.attack(monster2);
cout << monster2.getHealth() << endl;
}
monster.h
#ifndef MONSTER_H
#define MONSTER_H
#include <iostream>
#include <string>
using namespace std;
class Monster
{
public:
Monster(string name_, int health_, int damage_);
~Monster();
int attack(Monster opponet);
int getHealth();
string name;
int damage;
int health = 0;
int getDamage();
void setHealth(int health_);
void setDamage(int damage_);
void setName(string name);
void doDamageToOpponent(Monster opponent);
string getName();
};
#endif
monster.cpp
#include "monster.h"
Monster::Monster(string name_, int health_, int damage_) {
health = health_;
setDamage(damage_);
setName(name_);
}
Monster::~Monster() { }
int Monster::attack(Monster opponent) {
doDamageToOpponent(opponent);
}
void Monster::doDamageToOpponent(Monster opponent) {
int newHealth = opponent.getHealth() - this->getDamage();
opponent.setHealth(newHealth);
}
int Monster::getHealth() {
return health;
}
int Monster::getDamage() {
return damage;
}
void Monster::setHealth(int health_) {
health = health_;
}
void Monster::setDamage(int damage_) {
this->damage = damage_;
}
void Monster::setName(string name_) {
this->name = name_;
}
string Monster::getName() {
return name;
}
Now my problem is that, when I run this code I expect to have monster2 object to have 400 health left, but it is still 450 :S
What must be done here in order to to so? I noticed that it can be 400 in doDamageToOppoenet but when it leaves that block, then it is still 450. Please help me! Thanks.
You're passing objects by value:
void Monster::doDamageToOpponent(Monster opponent) <- This should be by reference
int Monster::attack(Monster opponent) <- idem
that means: you're creating a new copy of the Monster object you meant to deal damage to in the functions you're calling, and then actually dealing that copy damage but leaving the original old object with the value untouched.
Signatures as follows would work instead:
void Monster::doDamageToOpponent(Monster& opponent)
int Monster::attack(Monster& opponent)
If you want to learn more about this, something to read on: Passing stuff by reference and Passing stuff by value
The reason is that functions attack and doDamageToOpponent are taking copies of arguments, because you pass them by value. What happenes then is you change the copies of passed Monsters inside functions. After functions return, these copies die (as they are local to functions) and nothing happens to original, interested parties.
Try instead pass the argument by reference. Reference works as if it was the original variable. Consider:
int a = 0;
int &refa = a; /* refa acts as real "a", it refers to the same object "a" */
int b = a; /* this is your case */
b = 6; /* b will be changed, but "a" not */
refa = 6; /* a is changed, really "a", refa is just different name for "a" */
Try:
int Monster::attack( Monster &opponent){
doDamageToOpponent( opponent);
}
void Monster::doDamageToOpponent( Monster &opponent){
int newHealth = opponent.getHealth() - this->getDamage();
opponent.setHealth( newHealth);
}
You are passing the opponent by value, i.e., the function:
int Monster::attack(Monster opponent);
will actually receive a copy of the opponent and modify that copy. Every time you have a function that modifies some object you need to pass the object to be modified by reference or pass a pointer to it, e.g.,
int Monster::attack(Monster& opponent);
or
int Monster::attack(Monster* opponent);
I recommend using const T& for input parameters and T* for output parameters, so in this case, the latter form. The reason why I recommend the latter for output parameters is because it makes it more explicit to the caller:
monster.attack(&monster2); // passing a pointer: monster2 will be modified.

Getter returning 2d array in C++

this is my first post on SO, even though i've spent some time already here.
I've got here a problem with a function returning a 2d array. I have defined a private 2d int array property int board[6][7] in my Game class, but i don't know how to create a public getter for this property.
These are relevant parts of my game.h:
#ifndef GAME_H
#define GAME_H
class Game
{
public:
static int const m_rows = 6;
static int const m_cols = 7;
Game();
int **getBoard();
private:
int m_board[m_rows][m_cols];
};
#endif // GAME_H
Now what I would like is something like this in game.cpp (cause I thought array name without brackets is a pointer to first element, obviously it doesn't work with 2d arrays) :
int **Game::getBoard()
{
return m_board;
}
So that i can put this for example in my main.cpp:
Game *game = new Game;
int board[Game::m_rows][Game::m_cols] = game->getBoard();
Can anybody help me, what should i put in my game.cpp ?
Thanks!
You cannot pass arrays by value into and out of functions. But there's various options.
(1) Use a std::array<type, size>
#include <array>
typedef std::array<int, m_cols> row_type;
typedef std::array<row_type, m_rows> array_type;
array_type& getBoard() {return m_board;}
const array_type& getBoard() const {return m_board;}
private:
array_type m_board;
(2) Use the correct pointer type.
int *getBoard() {return m_board;}
const int *getBoard() const {return m_board;}
private:
int m_board[m_rows][m_cols];
An int[][] has no pointers involved. It isn't a pointer to an array of pointers to arrays of integers, it's an array of an array of integers.
//row 1 //row2
[[int][int][int][int]][[int][int][int][int]]
Which means one int* points to all of them. To get to a row offset, you'd do something like this:
int& array_offset(int* array, int numcols, int rowoffset, int coloffset)
{return array[numcols*rowoffset+coloffset];}
int& offset2_3 = array_offset(obj.getBoard(), obj.m_cols, 2, 3);