Problem with Deck reset function in a Deck - c++

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.

Related

Do classes hinder the execution time of a program (as opposed to an implementation using only free functions)?

There is a ""rumor"" that I've heard in the competitive programming community that an approach to implementing a data structure, for example, using classes would render a much slower time than an implementation basing itself on a purely functional paradigm. I've tested this out (on my recursive segment tree implementation using classes then only functions that were practically the same) with a completely random generator (the queries and the updates had an equal probability in appearing in the testcase), and the results concured with the hypothesis; the purely functional program averaged (~7 seconds) twice better than the object-oriented implementation (~12.8 seconds) in high (5 mil - 10 mil queries+updates) inputs.
So, my question is, why would this difference is so accentuated, and why does it even happen in the first place?
Thank you for reading this!
Here's the code(maybe I messed up something and that's why all of this happened):
The class implementation:
#include <iostream>
using namespace std; //poor practice :P
class AINT {
int tree[1048700];
public:
void update(int val, int poz, int node=1, int cl=1, int cr=500000) {
if(cl==cr) {
tree[node]=val;
return;
}
int mid=(cl+cr)/2;
if(poz<=mid)
update(val,poz,2*node,cl,mid);
else
update(val,poz,2*node+1,mid+1,cr);
tree[node]=max(tree[2*node],tree[2*node+1]);
}
int query(int l, int r, int node=1, int cl=1, int cr=500000) {
if(l<=cl && cr<=r) {
return tree[node];
}
int mid=(cl+cr)/2,a=0,b=0;
if(l<=mid)
a=query(l,r,2*node,cl,mid);
if(mid<r)
b=query(l,r,2*node+1,mid+1,cr);
return max(a,b);
}
}aint;
int main() {
int n;
cin >> n;
for(int i=0,t,x,y; i<n; i++) {
cin>> t >> x>> y;
if(t==1)
aint.update(y,x);
else
cout << aint.query(x,y) <<'\n'; // i added the output (which I then redirected to a file) because it seems relevant to also print the values (otherwise the compiler might just ignore the unused result)
}
return 0;
}
the purely functional implementation:
#include <iostream>
using namespace std;
int tree[1048700];
void update(int val, int poz, int node=1, int cl=1, int cr=500000) {
if(cl==cr) {
tree[node]=val;
return;
}
int mid=(cl+cr)/2;
if(poz<=mid)
update(val,poz,2*node,cl,mid);
else
update(val,poz,2*node+1,mid+1,cr);
tree[node]=max(tree[2*node],tree[2*node+1]);
}
int query(int l, int r, int node=1, int cl=1, int cr=500000) {
if(l<=cl && cr<=r) {
return tree[node];
}
int mid=(cl+cr)/2,a=0,b=0;
if(l<=mid)
a=query(l,r,2*node,cl,mid);
if(mid<r)
b=query(l,r,2*node+1,mid+1,cr);
return max(a,b);
}
int main() {
int n;
cin >> n;
for(int i=0,t,x,y; i<n; i++) {
cin>> t >> x>> y;
if(t==1)
update(y,x);
else
x=query(x,y); // i added the output (which I then redirected to a file) because it seems relevant to also print the values (otherwise the compiler might just ignore the unused result)
x=y+x*x;
}
return 0;
}
the generator:
#include <iostream>
using namespace std;
static int rand(int a, int b) {
return rand()%(b-a+1)+a;
}
int main(int argc, char * argv[]) {
srand(atoi(argv[1]));
int n;
n=10000000;
cout << n << '\n';
for(int i=0; i<n; i++) {
int t=rand(0,1),x=rand(1,500000),y=rand(1,500000);
if(t==0 && x>y)
swap(x,y);
cout << t << ' ' <<x << ' ' <<y <<'\n';
}
}
It depends if your class defines constructors or destructors or inherits from another class and especially if it uses inherited virtual functions like:
class Animal{
virtual void makeSound(){}
virtual std::string getName(){}
};
class Dog : Animal{
void makeSound(){}
std::string getName(){}
};
than there is overhead for using the virtual function table. I know for a fact that virtual destructors can really kill performance. However just moving a bunch of functions into a class will not hurt your performance at all.
It's also arguable that your example of 'pure functional' is not even close to the tag definition.
If you meant using a bunch of functions in the global namespace vs functions wrapped in class, there is no performance differences if you compile with -O3 optimizations or Release Mode on MSVC.
Although if your not going to use the features of classes and you just want a way to organize and find functions use a namespace like:
namespace animal {
namespace dog {
void bark() {}
}
}
animal::dog::bark();
Also please be careful how your measuring performance, if you're timing std::cout or std::cin you're going to get terrible numbers IO is always very slow and totally inconsistent.
You would never measure IO operations if you can help it. I suggest you watch this: https://www.youtube.com/watch?v=YG4jexlSAjc
by The Cherno a.k.a. Yan Chernokov , his tutorials are fantastic.

Towers of Hanoi with Classes

I keep getting the Error C2228 left of '.topDisk' must have class/struct/union and I have no idea what it means, or even how to fix it, even after some research. Is it possible for someone to explain what the error is and how to fix it? I think I've provided you with all the code you need.
HanoiPegClass.cpp File
//A function moving one disk from one peg to another
void moveDisk(Peg& beginning, Peg& destination)
{
assert(beginning.getNumDisks() > 0);
if (destination.getNumDisks() > 0)
{
//Where the error is
assert(beginning.getNumDisks.topDisk() < destination.getNumDisks.topDisk());
}
destination.addDisk(beginning.topDisk());
beginning.removeDisk();
}
Peg.cpp File
//Function to return the disk count (amount of discs on each peg)
unsigned int Peg::getNumDisks()
{
return diskStack.size();
}
//Function to return the value of the top disk
int Peg::topDisk()
{
return diskStack.back();
}
Peg.h File
#pragma once
#include <vector>
#include <string>
using namespace std;
class Peg
{
private:
vector<int> diskStack;
string pegName;
void setName(string name);
public:
Peg(string name, int totalDisks);
unsigned int getNumDisks();
void printDisks();
string getName();
int topDisk();
void addDisk(int totalDisks);
int removeDisk();
~Peg();
};
getNumDisks is a function which returns an unsigned integer, so you cannot use a . on it. You can use the . operator on a structure or class or union only.
So change
assert(beginning.getNumDisks.topDisk() < destination.getNumDisks.topDisk());
to
assert(beginning.topDisk() < destination.topDisk());

How to use member of one class in another class constructor

I have a class:
class Cave
{
private:
int no_of_rooms;
public:
vector<int>rooms;
Cave(int r);
Cave(){};
};
The constructor of Cave fills the vector rooms with random integers:
Cave::Cave(int r)
:no_of_rooms{ r }
{
int i = 0;
while (i<no_of_rooms)
{
rooms.push_back(randint(1, no_of_rooms));
++i;
}
}
I create another class:
class Player : public Cave
{
public:
Player(int *plyr)
:p_ptr{ plyr }
{
plyr = &rooms[0];
}
private:
int* p_ptr = nullptr;
};
This Player class seems to be a mess. I am trying to get access to the same rooms vector filled up by the Cave constructor.
I think you really should encapsulate Cave and not inherit from it. Try this.
cave.h
#include <vector>
#include <random>
class Cave
{
private:
int no_of_rooms;
public:
std::vector<int>rooms;
Cave(int r);
Cave(){};
};
inline int randint(int min, int max)
{
std::random_device device;
std::mt19937 engine(device());
std::uniform_int_distribution<int> dist(min, max);
return dist(engine);
}
cave.cpp
#include "cave.h"
Cave::Cave(int r)
:no_of_rooms{ r }
{
int i = 0;
while (i<no_of_rooms)
{
rooms.push_back(randint(1, no_of_rooms));
++i;
}
}
player.h
#include "cave.h"
class Player// : public Cave
{
public:
Player(int *plyr)
:p_ptr{ plyr }
{
cave = Cave(*plyr);
plyr = &cave.rooms[0];
}
private:
Cave cave;
int* p_ptr = nullptr;
};
I tried it using
#include "player.h"
int main(int argc, char* argv[])
{
int player_count = 2;
Player p(&player_count);
}
Also, I am not sure the unnecessary use of pointers in some of your code.
You may have a typo:
plyr = &rooms[0];
This sets the function argument, not the member.
You meant p_ptr = &rooms[0];?
But then why have a function argument at all. This makes no sense.
Unfortunately, you did not get around to telling us what you want to do, or what you want these classes to do, or what input you need to provide to the classes. So I cannot answer any further.

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.

changing QVector variables from separate functions

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.