Working on a solitare program in C++

  • (2 Pages)
  • +
  • 1
  • 2

16 Replies - 664 Views - Last Post: 30 November 2017 - 07:06 AM Rate Topic: -----

#1 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Working on a solitare program in C++

Posted 26 November 2017 - 02:37 PM

Hello all,
I am currently working on creating a console style solitaire program and have run into some walls I was hoping someone could provide insight on.
What I have so far-
Currently, the program generates 52 cards, the cards are assigned a rank (1 for Ace, 2 for two, 3 for three...)
as well as a suit (H for heart, D for Diamond....)
I then split those card up into two piles, one pile for the cards in the drawing pile(pile at the top left of the screen) and a hand pile (all the cards on the board.) Both of these piles were placed into stacks.
What I am struggling with-
What I am currently trying to do is place the cards from the hand pile into 7 different deques to represent the seven piles of cards on the board, however I have no clue how to achieve this. I am a novice coder and in a little over my head. Ive read up on the syntax for queues and dequeues, but still don't have a firm grasp on it. Any help would be greatly appreciated.

I know the code is very unorganized, im still in the early stages of trying to get everything to work.
#include "stdafx.h"  //REMOVE IF NOT USING VISUAL STUDIO
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctime>
#include <windows.h>
#include <stack>
using namespace std;

/*
Creating Pile class.
initializing pointers to 
card rank and suit
to chars*/

class Pile{
	
public: 
	char *cardRank;
	char *cardSuit;
	void fillDeck();
	

};

typedef Pile card;
card deck[52];
int shuffled = 1250;

void shuffleNow();
void fillDeck(card *, char *[], char *[]);
void shuffle(card *, int);
void deal(card *);
void WaitKey();

class drawPile : public Pile {

private:
	int queue;
};

void shuffle(card *wDeck, int shuffled)
{
	int i, j, x;
	card temp;
	for (x = 0; x < shuffled; x++) // A big shuffle
	{
		for (i = 0; i < 52; i++)
		{
			j = rand() % 52;
			temp = wDeck[i];
			wDeck[i] = wDeck[j];
			wDeck[j] = temp;
		}
	}
}

void fillDeck(card *wDeck, char *wFace[], char *wSuit[])
{
	int i;

	for (i = 0; i < 52; i++)
	{
		wDeck[i].cardRank = wFace[i % 13];
		wDeck[i].cardSuit = wSuit[i / 13];
		
	}
}

void deal(card *wDeck)
{
	int i;
	for (i = 0; i < 52; i++)
	{
		cout << "Card" << i+1 << ":" << "[" << wDeck[i].cardRank << " of " << wDeck[i].cardSuit << "]" << (i + 1) % 3 << endl;
		//cout << wDeck[51].cardRank, wDeck[51].cardSuit;
		//printf("    %5s of %-8s (%s) %c", wDeck[i].cardRank, wDeck[i].cardSuit, (i + 1) % 3 ? '\b' : '\n');
		//printf("\t\t\t     %5s of %-8s (%s) \n", wDeck[51].cardRank, wDeck[51].cardSuit);
	}

}

void showstack(stack <char> *gq, stack <char> *bd)
{
stack <char> a = *bd;
	stack <char> g = *gq;
	
	while (!g.empty()||!a.empty()){
		if (g.top() == 'H') { cout << "Of HEARTS "; };
		if (g.top() == 's') { cout << "of SPADES "; };
		if (g.top() == 'D') { cout << "of DIAMONDS "; };
		if (g.top() == 'C') { cout << "Of CLUBS "; };
		if (g.top() == '1') { cout << "Ace "; };
		if (g.top() == '2') { cout << "Two "; };
		if (g.top() == '3') { cout << "Three "; };
		if (g.top() == '4') { cout << "Four "; };
		if (g.top() == '5') { cout << "Five "; };
		if (g.top() == '6') { cout << "Six "; };
		if (g.top() == '7') { cout << "Seven "; };
		if (g.top() == '8') { cout << "Eight "; };
		if (g.top() == '9') { cout << "Nine "; };
		if (g.top() == 'X') { cout << "Ten "; };
		if (g.top() == 'J') { cout << "Jack "; };
		if (g.top() == 'Q') { cout << "Queen "; };
		if (g.top() == 'K') { cout << "King "; };
		//cout << '\t' << g.top();
		g.pop();
	}
	cout << '\n';
}


void splitDeck(card *wDeck) {
	cout << "---------" << "HAND PILE AFTER SHUFFLE" << "---------" << endl;
	for (int i = 0; i < 28; i++) {
		//cout << "hand pile Card" << i + 1 << ":" << "[" << wDeck[i].cardRank << " of " << wDeck[i].cardSuit << "]" << (i + 1) % 3 << endl;
		
		stack <char> handPileRank, handPileSuit;
		handPileRank.push(*wDeck[i].cardSuit);
		handPileRank.push(*wDeck[i].cardRank);
		
		
		showstack(&handPileRank, &handPileSuit);
	}
	cout << "--------------------------------------------" << endl;
	cout << "---------" << "DRAW PILE AFTER SHUFFLE" << "---------" << endl;
	for (int i = 28; i < 52; i++) {
		//cout << "draw pile Card" << i + 1 << ":" << "[" << wDeck[i].cardRank << " of " << wDeck[i].cardSuit << "]" << (i + 1) % 3 << endl;
		
		stack <char> drawPileRank, drawPileSuit;
		drawPileRank.push(*wDeck[i].cardSuit);
		drawPileRank.push(*wDeck[i].cardRank);
		
		
		// This currently does nothing, a very poor attempt at trying to use queues

	deque<char> dequeSuit(*wDeck[i].cardSuit);
	dequeSuit.push_back(*wDeck[i].cardSuit);
	cout << "NOWTESTING DEQUE" << &dequeSuit[i];
		
		
		showstack(&drawPileRank, &drawPileSuit);
	}
	cout << "--------------------------------------------";


}

void setBoard(card *wDeck)
{
	
	for (int i = 0; i < 1; i++) {
			//cout << "Queue 1 " << handPileRank;
	}
}
int main() {
	char *cardRank[] = { "1","2","3","4","5","6","7","8","9","X","J","Q","K" }; //{ "Ace", "Two", "three", "Four", "five", "Six", "VII", "Eight", "Nine", "X", "Jack", "Queen", "King" };
	char *cardSuit[] = { "Hearts","Clubs","Diamonds","spades" };
	time_t t;
	srand((unsigned)time(&t));
	fillDeck(deck, cardRank, cardSuit);
	shuffle(deck, shuffled);
	//deal(deck);
	splitDeck(deck);
	setBoard(deck);
		system("pause");
		return 0;
	
}





Is This A Good Question/Topic? 0
  • +

Replies To: Working on a solitare program in C++

#2 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1467
  • View blog
  • Posts: 4,726
  • Joined: 20-March 10

Re: Working on a solitare program in C++

Posted 26 November 2017 - 04:04 PM

Hmm,

Generally games are a bad idea for beginners but in case we cannot dissuade you...

You have stack <char> drawPileRank, drawPileSuit; inside your loop so you are resetting its value back to an initial state,

move this outside the for loop like so

stack <char> drawPileRank, drawPileSuit;
	for (int i = 28; i < 52; i++) {


Was This Post Helpful? 0
  • +
  • -

#3 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6290
  • View blog
  • Posts: 21,613
  • Joined: 05-May 12

Re: Working on a solitare program in C++

Posted 27 November 2017 - 08:02 AM

Just my thoughts on this assuming the version of Solitaire being played is Klondike:
- each of the 7 columns of the tableau are "stack"s
- each of the 4 foundations are real stacks
- the drawn cards is "stack"
- only the deck is a dequeue

I put the word "stack" in quotes because this flavor of stack will need to allow peeking at the cards beyond just the top of the stack. A traditional stack ADT only allows access to the top of the stack. If you don't want this special definition of a "stack", then use a list.
Was This Post Helpful? 1
  • +
  • -

#4 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Working on a solitare program in C++

Posted 27 November 2017 - 10:33 AM

// always remove
// #include "stdafx.h"  //REMOVE IF NOT USING VISUAL STUDIO
#include <iostream>
// NO #include <stdio.h>
// NO #include <stdlib.h>
// NO #include <conio.h>
#include <ctime>
// NO #include <windows.h>
// I tried, this is just too many headaches
// #include <stack>
// instead
#include <vector>

#include <string>

// not yet
// using namespace std;

/* wtf is this?
class Pile {
    public:
    char *cardRank;
    char *cardSuit;
    void fillDeck();
};

typedef Pile card;
globals? GLOBALS?!?
card deck[52];
int shuffled = 1250;

class drawPile : public Pile {

private:
int queue;
};

*/

// right
typedef unsigned char Card; // because, honestly, this is all you need
typedef std::vector<Card> Pile;
const int DECK_SIZE = 52; // magic numbers, bad
const Card INVALID_CARD = 69; // chances are, you'll want this at some point

// functions
Pile initDeck();
Card deal(Pile &);
// void shuffle(card *, int);
// for shuffle, you might want to reconsider using stack... but, ok
Pile shuffle(const Pile &);
void showCard(Card);
void showCards(const std::string &, const Pile &);
bool isValidCard(Card);
int cardFace(Card);
int cardSuit(Card);

// ?? 
// void showstack(stack <char> *gq, stack <char> *bd) {
// void splitDeck(card *wDeck) {
// ok, I think I see what's going on here...
// so
struct Piles {
    Pile hand, draw;
};
Piles splitDeck(const Pile &);



int main() {
    srand(time(NULL));
    Pile deck = initDeck();
    showCards("initDeck", deck);
    deck = shuffle(deck);
    showCards("shuffled", deck);

    Piles p = splitDeck(deck);
    showCards("HAND", p.hand);
    showCards("DRAW", p.draw);

    system("pause");
    return 0;
}



Results:
initDeck: 1H 2H 3H 4H 5H 6H 7H 8H 9H XH JH QH KH 1C 2C 3C 4C 5C 6C 7C 8C 9C XC JC QC KC 1D 2D 3D 4D 5D 6D 7D 8D 9D XD JD QD KD 1S 2S 3S 4S 5S 6S 7S 8S 9S XS JS QS KS
shuffled: XH 5D 6S 7S XD XC QS 5C KH 3S 9H 9C QH 4S 3H 9D 4H JS 9S QD 4C 8H 1H 7H 8S 2D KC 3C 4D 2C 8C 1S 8D 6C 6D 7D 1D XS JD KS 5S 2S 6H KD 2H QC JC 7C 3D 1C 5H JH
HAND: XH 5D 6S 7S XD XC QS 5C KH 3S 9H 9C QH 4S 3H 9D 4H JS 9S QD 4C 8H 1H 7H 8S 2D KC 3C
DRAW: 4D 2C 8C 1S 8D 6C 6D 7D 1D XS JD KS 5S 2S 6H KD 2H QC JC 7C 3D 1C 5H JH
Press any key to continue . . .



So, here a created as struct for those piles. You could extend that idea to any layout you need.

While dealing from a stack makes sense, iterating over a stack doesn't, and you'll often need to do that. A vector has a push and pop, as well as any other toys you'll want.

I made card simple here, but you could reasonably do something like this, if it makes more sense to you:
class Card {
public:
    Card();
    Card(int);
    bool isValid() const;
    int face() const;
    int suit() const;
    const std::string &name() const;
private:
    const int value;
};



See how many of the floating functions in the first example can be grouped into card class?

Hope this helps.
Was This Post Helpful? 1
  • +
  • -

#5 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6290
  • View blog
  • Posts: 21,613
  • Joined: 05-May 12

Re: Working on a solitare program in C++

Posted 27 November 2017 - 01:18 PM

Yup, good ol' std::vector. It's the swiss army knife of C++ development: act like an array, a list, a queue, a dequeue, a stack. If you play your cards right, you can even make it act like a binary tree.
Was This Post Helpful? 0
  • +
  • -

#6 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Working on a solitare program in C++

Posted 27 November 2017 - 01:49 PM

Well, the problem is the shuffle and iteration.

Considering the mutating operations are just push, pop, and shuffle, and the max size is known, it is honestly more fun to roll your own:
class Cards {
public:
    static const int DECK_SIZE = 52;
    Cards(bool fill = false);
    Cards(const Cards &);
    void add(Card);
    Card deal();
    Cards dealCards(int size); // helper
    void shuffle();
    void print(std::ostream &) const;
    bool empty() const;
    int count() const;
private:
    Card items[DECK_SIZE];
    int size;
};



However, learning not to reinvent the wheel is also nice.
Was This Post Helpful? 1
  • +
  • -

#7 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Re: Working on a solitare program in C++

Posted 27 November 2017 - 06:05 PM

Appreciate the input all, and I know my code was an absolute mess as it was, at the start the
class Pile {...}
and
class drawPile : public Pile {...}
were eventually supposed to be made to hold all of their relevant functions. I was kind of working backwards and creating the functions and then determining what class to put them in after, but I know that is a poor practice. I think my biggest issue is not knowing how to properly generate the queues and deque's. I believe Skydiver's breakdown of how the piles should be split up is the closest to what I was aiming for. As of now I have 7 deque's ( cards 1-28 ) and 1 queue (cards 29-52 ), but I'm still going about it through the iteration method
for (int j = 0; j < 1; j++) {
deque <char>queue1;
			queue1.push_front(*wDeck[j].cardSuit);
			queue1.push_front(*wDeck[j].cardRank);
			
			cout << "Queue1 Test" << "| " << queue1.front()<<queue1.back() <<  "| ";
		}

Was This Post Helpful? 0
  • +
  • -

#8 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Re: Working on a solitare program in C++

Posted 27 November 2017 - 06:15 PM

I also like Baavgai's suggestion. Would it be possible to set up classes like this -
//An initial class that holds all 52 cards
class Pile {
	protected: 
	int topcard;
	public : 
	void putcard();
	getcard();
	isFull();
	isEmpty();
	
}
//A class that inherits from Pile, Takes last 24 cards and puts them into a Queue
class DrawPile : public Pile
{
	private: 
	Cards queue;
	flipCards();
}
//A class that inherits from Pile, this is where the 4 empty stacks would be created
class TargetPile : public Pile
{
	private: 
	Cards stack;
	public: endOfGame();
}
//A class that inherits from pile, places first 28 cards into 7 deque's 
class Hand : public Pile
{
	private:
	Cards deque;
}

Was This Post Helpful? 0
  • +
  • -

#9 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6290
  • View blog
  • Posts: 21,613
  • Joined: 05-May 12

Re: Working on a solitare program in C++

Posted 27 November 2017 - 06:24 PM

Yes, splitting things up into those classes would help immensely. When doing object oriented programming/design, you want to think in terms of high level "objects" that send messages to each other instead of doing low level manipulation of data.
Was This Post Helpful? 2
  • +
  • -

#10 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Working on a solitare program in C++

Posted 28 November 2017 - 08:18 AM

First, queue and deque are implementation details. You may very well use them, but don't about about them just yet.

Instead, think about organizing your code into classes and only the public methods you are offering.

You have the idea of Pile, which will just be a collection of cards. What basic methods does it need? You want to be able to add and remove cards from the pile. You will ultimately need to access all cards stored, for printing and probably logic purposes.

Now, what public methods must DrawPile offer than your basic Pile does not? I see flipCards() and endOfGame(); can these be done with flipCards(Pile) and endOfGame(Pile)?

Game states are fun and also good exercise. At the highest level, you need to identify all the moving parts of your game. You have multiple piles of cards that are manipulated in some way until the game is done. So, think about all the data that must be available at the beginning, the initial state. Then, what operations are performed that change that state, ultimately leading to a final, or done, state.

A standard game template might look like:
class Game {
public:
    Game();
    bool done() const;
    void display() const;
    void userInput(InputType);
private:
    // details
};

int main() {
    Game g;
    while (!g.done()) {
        g.display();
        g.userInput(getUserInput());
    }
    return 0;
}



Hope this helps.
Was This Post Helpful? 1
  • +
  • -

#11 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Re: Working on a solitare program in C++

Posted 28 November 2017 - 02:34 PM

This is all really helpful, and I know this is the way I should be coding from the get-go. I appreciate you going through the thought process as much as I do helping me with the actual code. I plan on using vectors to generate the deck(they seem much more versatile), and then place portions of that vector into queues/deques later. I am starting to clean it up piece by piece, the first issue (and something that will keep popping up) that I'm running into is trying to create a function definition inside my pile class.

class Pile
{
public:
	Pile();
	void putCard();
	int getCard();
	bool isFull();
	bool isEmpty();
protected:
	int topCard;
	//Initializing a function that returns a vector for use in deck generation
	vector<int> generateDeck(const int size);
};


And the function I am creating-

vector<int> Pile::generateDeck(const int size){.....}
{


I receive two errors, first it says generateDeck has no type specifier, if I want the function to return the vector, is my syntax correct? Secondly,it says generateDeck is not a member of Pile. Should I be creating a vector of size 52, and then passing it into a function instead of trying to go about it this way?
Was This Post Helpful? 0
  • +
  • -

#12 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Working on a solitare program in C++

Posted 28 November 2017 - 04:59 PM

I'm confused. Doesn't Pile represent a collection of cards? So wouldn't you have something like:
Pile generateDeck(const int size);



What on earth would void Pile::putCard() do? Maybe: void Pile::putCard(int)

As to vector<int> generateDeck(const int size); declaration issues. Unless you have using namespace std; before the declaration, which you don't want to do in a header, you'll need that prefix: std::vector<int> generateDeck(const int size);. You'll also want to make sure you have vector in your includes.
Was This Post Helpful? 1
  • +
  • -

#13 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Re: Working on a solitare program in C++

Posted 28 November 2017 - 06:57 PM

Yes, Pile is the class where all 52 cards are generated. I did not format putCard() correctly, I was unsure of what parameters it would be taking in but you are correct, putCard(int) is what I will be using later on. Also thank you for the suggestion, placing std:: in front of the vectors made it work correctly. I had assumed that if I include namespace std; in my main.cpp it would work for all of the headers but realize now that that makes no sense. My Pile.cpp is now functional, but I can't use any of the functions in my main.cpp. All I need to do is include "Pile.h" in both my Pile.cpp and main.cpp files correct? I know you are never supposed to include .cpp files (learned after just dealing with a ton of linker errors).

This post has been edited by Failing Calculus: 28 November 2017 - 06:57 PM

Was This Post Helpful? 0
  • +
  • -

#14 Failing Calculus   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 23
  • Joined: 07-March 16

Re: Working on a solitare program in C++

Posted 28 November 2017 - 07:42 PM

Update: forgot about creating class objects, goodness, it is becoming obvious where my weaknesses lie.
Was This Post Helpful? 0
  • +
  • -

#15 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Working on a solitare program in C++

Posted 29 November 2017 - 08:44 AM

View PostFailing Calculus, on 28 November 2017 - 08:57 PM, said:

All I need to do is include "Pile.h" in both my Pile.cpp and main.cpp files correct?


Yes, though for different reasons. Pile.h should define a structure, but not the details. For Pile.cpp, you implement those details and you're using Pile.h as more of a reference. In main.cpp, the Pile.h is more of a promise. It tells main.cpp that such a structure exists and has also been implemented.

You'll get a link error in main if Pile.cpp didn't compile or if it didn't implement all the code in Pile.h. Because of how C/C++ works, declarations like the stuff in headers are all assumed valid for phase one of the compile. In the linking phase, the promised code is looked for and if not found, you'll get those link errors.
Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2