I am trying to generate a deck of cards using C++. I have already written all of the code, but there is a problem that I can't seem to figure out:
Deck::Deck(){
Card card;
bool match = false;
for (int i=0;i<47;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
In my constructor for the Deck class, I have a for() loop which generates all 52 cards and makes sure that the deck contains no matching cards. At least it should. The thing is, I can't make the loop iterate more than 47 times and still have it work. Any number over 47 causes the console screen to be empty upon run time, except for the blinking cursor. I am not quite sure what it is about numbers greater than 47 that cause it to stop working. I have tested it extensively and every number between 0 and 48 works.
Maybe I have some tiny error somewhere else in my code that I'm just not seeing. I don't really know. But I would really appreciate any help that I can get.
Here is my full code:
#include<iostream>
#include<stdlib.h>
using namespace std;
void run();
class Card{
private:
char suit;
int value;
public:
Card();
void setCard();
void getCard();
int getValue();
int getSuit();
};
class Deck{
private:
Card cards[52];
int numDrawn;
public:
Deck();
void shuffle();
void draw();
bool cardInDeck(Card card, int index);
};
int main(){
run();
}
Card::Card(){
srand(time(NULL));
value = rand() % 12 + 1;
suit = rand() % 4 + 1;
}
void Card::setCard(){
value = rand() % 12 + 1;
suit = rand() % 4 + 1;
}
void Card::getCard(){
cout<<" ----"<<endl<<"| |"<<endl<<"| ";
if (value == 1) cout<<'A';
else if (value == 10) cout<<'J';
else if (value == 11) cout<<'Q';
else if (value == 12) cout<<'K';
else cout<<value;
if (suit == 1) cout<<(char)3;
else if (suit == 2) cout<<(char)4;
else if (suit == 3) cout<<(char)5;
else cout<<(char)6;
cout<<" |"<<endl<<"| |"<<endl<<" ----"<<endl;
}
int Card::getSuit(){
return suit;
}
int Card::getValue(){
return value;
}
bool Deck::cardInDeck(Card card, int index){
bool match;
for(int i=0;i<=index;i++){
if((card.getValue() == cards[i].getValue()) && (card.getSuit() == cards[i].getSuit())){
match = true;
break;
}
else match = false;
}
return match;
}
Deck::Deck(){
Card card;
bool match = false;
for (int i=0;i<47;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
void Deck::shuffle(){
Card card;
bool match = false;
for (int i=0;i<52;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
void Deck::draw(){
cards[numDrawn].getCard();
numDrawn++;
}
void run(){
Deck cards;
char choice;
int cardsDrawn = 0;
cout<<"Enter 's' to shuffle the deck, 'd' to draw a card, or 'x' to exit: ";
do{
cin>>choice;
switch(choice){
case 'X':
case 'x':break;
case 'S':
case 's':cards.shuffle();
cout<<"Deck shuffled."<<endl;
cardsDrawn = 0;
break;
case 'D':
case 'd':if (cardsDrawn == 52){
cout<<"Out of cards. Deck reshuffled."<<endl;
cards.shuffle();
cardsDrawn = 0;
break;
}
else{
cards.draw();
cardsDrawn++;
break;
}
default: cout<<"Invalid entry.\a Enter a valid option('s','d','x'): ";
}
}while((choice != 'x') && (choice != 'X'));
}
You are generating cards and discarding those already present. A better way would be to generate all of them linearly and them shuffle the deck.
The more your deck grows, the longer it gets to find a new valid card
There are 13 values in a 52 cards deck
Card::Card(){
srand(time(NULL));
value = rand() % 13 + 1;
suit = rand() % 4 + 1;
}
void Card::setCard(){
value = rand() % 13 + 1;
suit = rand() % 4 + 1;
}
12 * 4 -> 48
13 * 4 -> 52
Your original code with 12 values can only produce 48 different cards, this is why you get an infinite loop when you try to generate 52.
Edited :
By the way, you should follow Eric's and Hans Passant's (see comments on your question) advice. The way you do the shuffling is the wrong way to do it in the sense that there exists a much simpler / more natural / cleaner way. See below,
/**
* Forward counting implementation of Fisher-Yates / Knuth shuffle.
* see https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
*/
template< typename A >
void shuffle ( A& a, int i, const int j ) {
// one item left => no need to shuffle
const int _j = j - 1;
for ( ; i < _j ; ++i ) {
// pick item uniformly at random to put at ith position
// once moved the item will stay in place
const int k = i + rand() % ( j - i );
// swap
auto tmp = a[i];
a[i] = a[k];
a[k] = tmp;
}
}
then you would have to generate all the 52 different cards once, like this
Card::Card( const int value, const int suit ) {
this->value = value;
this->suit = suit;
}
// we do not need this anymore
// void Card::setCard(){
// value = rand() % 13 + 1;
// suit = rand() % 4 + 1;
// }
Card cards[52];
int i = 0;
for ( int suit = 1 ; suit <= 4 ; ++suit ) {
for ( int value = 1 ; value <= 13 ; ++value ) {
cards[i] = Card( value, suit );
++i;
}
}
and finally shuffle the deck
shuffle( cards, 0, 52 );
More references on this common issue : http://bost.ocks.org/mike/shuffle and http://blog.codinghorror.com/the-danger-of-naivete.
Also please consider (as drescherjm sugested in his comment) to put the call to srand outside of this class. The call to srand resets the seed for the rand function and should in a very basic scheme only be called once at the very beginning of your main function. In your case, without a call to setCard() for each card you have, you might end up with 52 times the same card even though they are generated randomly ( see http://en.wikipedia.org/wiki/Pseudorandomness ).
I you have time you should look at the C++ random standard library header which provides way more the C rand lib. There even is a shuffle method in <algorithm>!
Just start off with a fresh pack. And then go through them swapping the current one with a random one. Do this seven times them done.
See https://www.math.hmc.edu/funfacts/ffiles/20002.4-6.shtml
Sort of code
int pack[52];
for (int i = 0; i < 52; ++i) { pack[i] = i; }
for (int shuffle = 0; shuffle < 7; ++ shuffle) {
for (int i=0; i < 52; ++i) {
j = rand() % 52;
t = pack[i];
pack[i] = pach[j];
pack[j] = t;
}
}
This removes the problem as the pack is loaded and this shuffles it.
Here is a fully functional example that I did in class last semester, it works pretty well.
Deck::Deck()
{
cout << "Constructor was run" << endl;
nextCard = 0;
cards = new Card[numCards];
int c = 0;
for (int s = 0; s < Card::numSuits; s++)
{
for (int r = 1; r <= Card::numRanks; r++)
{
Card cd(s, r);
cards[c++] = cd;
}
}
srand(static_cast<int>(time(0)));
}
I would rather prepare full unshuffled deck first then every time user draws a card, pick random one from deck, replace its place in deck with last card on deck and decrement size of deck.
int deck[52];
int size=0;
void init()
{
for (int i=0; i<52; i++)
deck[i]=i;
size=52;
}
int draw()
{
if (!size)
init();
int i = rand()%size;
size--;
int card = deck[i];
deck[i]=deck[size];
return card;
}
Related
I'm trying to implement NegaMax ai for Connect 4. The algorithm works well some of the time, and the ai can win. However, sometimes it completely fails to block opponent 3 in a rows, or doesn't take a winning shot when it has three in a row.
The evaluation function iterates through the grid (horizontally, vertically, diagonally up, diagonally down), and takes every set of four squares. It then checks within each of these sets and evaluates based on this.
I've based the function on the evaluation code provided here: http://blogs.skicelab.com/maurizio/connect-four.html
My function is as follows:
//All sets of four tiles are evaluated before this
//and values for the following variables are set.
if (redFoursInARow != 0)
{
redScore = INT_MAX;
}
else
{
redScore = (redThreesInARow * threeWeight) + (redTwosInARow * twoWeight);
}
int yellowScore = 0;
if (yellowFoursInARow != 0)
{
yellowScore = INT_MAX;
}
else
{
yellowScore = (yellowThreesInARow * threeWeight) + (yellowTwosInARow * twoWeight);
}
int finalScore = yellowScore - redScore;
return turn ? finalScore : -finalScore; //If this is an ai turn, return finalScore. Else return -finalScore.
My negamax function looks like this:
inline int NegaMax(char g[6][7], int depth, int &bestMove, int row, int col, bool aiTurn)
{
{
char c = CheckForWinner(g);
if ('E' != c || 0 == depth)
{
return EvaluatePosition(g, aiTurn);
}
}
int bestScore = INT_MIN;
for (int i = 0; i < 7; ++i)
{
if (CanMakeMove(g, i)) //If column i is not full...
{
{
//...then make a move in that column.
//Grid is a 2d char array.
//'E' = empty tile, 'Y' = yellow, 'R' = red.
char newPos[6][7];
memcpy(newPos, g, sizeof(char) * 6 * 7);
int newRow = GetNextEmptyInCol(g, i);
if (aiTurn)
{
UpdateGrid(newPos, i, 'Y');
}
else
{
UpdateGrid(newPos, i, 'R');
}
int newScore = 0; int newMove = 0;
newScore = NegaMax(newPos, depth - 1, newMove, newRow, i, !aiTurn);
newScore = -newScore;
if (newScore > bestScore)
{
bestMove = i;
bestScore = newScore;
}
}
}
}
return bestScore;
}
I'm aware that connect four has been solved are that there are definitely better ways to go about this, but any help or suggestions with fixing/improving this will be greatly appreciated. Thanks!
I was recently working on the following problem.
http://www.codechef.com/problems/D2
The Chef is planning a buffet for the DirectiPlex inauguration party, and everyone is invited. On their way in, each guest picks up a sheet of paper containing a random number (this number may be repeated). The guests then sit down on a round table with their friends.
The Chef now decides that he would like to play a game. He asks you to pick a random person from your table and have them read their number out loud. Then, moving clockwise around the table, each person will read out their number. The goal is to find that set of numbers which forms an increasing subsequence. All people owning these numbers will be eligible for a lucky draw! One of the software developers is very excited about this prospect, and wants to maximize the number of people who are eligible for the lucky draw. So, he decides to write a program that decides who should read their number first so as to maximize the number of people that are eligible for the lucky draw. Can you beat him to it?
Input
The first line contains t, the number of test cases (about 15). Then t test cases follow. Each test case consists of two lines:
The first line contains a number N, the number of guests invited to the party.
The second line contains N numbers a1, a2, ..., an separated by spaces, which are the numbers written on the sheets of paper in clockwise order.
Output
For each test case, print a line containing a single number which is the maximum number of guests that can be eligible for participating the the lucky draw.
Constraints
1 ≤ N ≤ 10000
You may assume that each number number on the sheet of paper; ai is randomly generated, i.e. can be with equal probability any number from an interval [0,U], where U is some upper bound (1 ≤ U ≤ 106).
Example
Input:
3
2
0 0
3
3 2 1
6
4 8 6 1 5 2
Output:
1
2
4
On checking the solutions I found this code:
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#define LIMIT 37
using namespace std;
struct node {
int val;
int index;
};
int N;
int binary(int number, vector<int>& ans) {
int start = 0;
int n = ans.size();
int end = n - 1;
int mid;
if (start == end)
return 0;
while (start != end) {
mid = (start + end) / 2;
if (ans[mid] == number)
break;
if (ans[mid] > number)
end = mid;
else
start = mid + 1;
}
mid = (start + end) / 2;
return mid;
}
void display(vector<int>& list) {
cout << endl;
for (int i = 0; i < list.size(); i++)
cout << list[i] << " ";
cout << endl;
}
int maxsubsequence(vector<int>& list) {
vector<int> ans;
int N = list.size();
ans.push_back(list[0]);
int i;
// display(list);
for (i = 1; i < N; i++) {
int index = binary(list[i], ans);
/*if(index+1<ans.size())
continue;*/
if (list[i] < ans[index])
ans[index] = list[i];
if (list[i] > ans[index])
ans.push_back(list[i]);
// display(ans);
}
return ans.size();
}
int compute(int index, int* g) {
vector<int> list;
list.push_back(g[index]);
int itr = (index + 1) % N;
while (itr != index) {
list.push_back(g[itr]);
itr = (itr + 1) % N;
}
return maxsubsequence(list);
}
int solve(int* g, vector<node> list) {
int i;
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
return ret;
}
bool cmp(const node& o1, const node& o2)
{ return (o1.val < o2.val); }
int g[10001];
int main() {
int t;
cin >> t;
while (t--) {
cin >> N;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
cin >> g[i];
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
Can someone explain this to me. I am well aware of calculating LIS in nlog(n).
What I am not able to understand is this part:
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
and the reason behind sorting
sort(list.begin(),list.end(),cmp);
This algorithm is simply guessing at the starting point and computing the LIS for each of these guesses.
The first value in a LIS is likely to be a small number, so this algorithm simply tries the LIMIT smallest values as potential starting points.
The sort function is used to identify the smallest values.
The for loop is used to check each starting point in turn.
WARNING
Note that this algorithm may fail for certain inputs. For example, consider the sequence
0,1,2,..,49,9900,9901,...,99999,50,51,52,...,9899
The algorithm will try just the first 37 starting points and miss the best starting point at 50.
You can test this by changing the code to:
int main() {
int t;
t=1;
while (t--) {
N=10000;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
if (i<50)
g[i]=i;
else if (i<150)
g[i]=9999-150+i;
else
g[i]=i-100;
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
This will generate different answers depending on whether LIMIT is 37 or 370.
In practice, for randomly generated sequences it will have a good chance of working (although I don't know how to compute the probability exactly).
I'm back again. So I have created a Deck of cards in Linked List fashion using Cards as the nodes. I am having trouble with my riffle shuffle function, however. The function should create two Deck objects that each store half of my Deck drawPile. Those two half piles should then take a card off one at a time and add it back to the drawPile. I am not getting an error, but it is not shuffling the cards at all. I call the function as such: drawPile.shuffle(drawPile);
Deck::Deck()
{
top = NULL;
SIZE = 0;
}
Deck::Deck(Card *n)
{
top = n;
}
void Deck::shuffle(Deck &d)
{
srand((unsigned)time(0));
for (int i = 0; i < 7; i++){
//split deck in half -- leftHalf and rightHalf
Deck leftHalf, rightHalf;
int j = SIZE/2;
for (int k = SIZE; k > j; k--){
drawCard(leftHalf); //drawCard off Deck and addCard to leftHalf
}
for (j; j > 0; j--){
drawCard(rightHalf); //drawCard off Deck and addCard to rightHalf
}
while (leftHalf.getSIZE() > 0 && rightHalf.getSIZE() > 0){
int probPile = leftHalf.getSIZE()/(leftHalf.getSIZE() + rightHalf.getSIZE())*100;
int randomNum = rand() % 100 + 1;
if (randomNum <= probPile){
leftHalf.drawCard(d); //drawCard off leftHalf and addCard to Deck
}
else{
rightHalf.drawCard(d); //drawCard off rightHalf and addCard to Deck
}
}
while (leftHalf.getSIZE() > 0){
leftHalf.drawCard(d);
}
while (rightHalf.getSIZE() > 0){
rightHalf.drawCard(d);
}
}
}
void Deck::drawCard(Deck &d)
{
Card *draw = top;
if (draw != NULL){
top = top->getNext();
SIZE--;
d.addCard(draw->getVALUE(), draw->getSUIT());
}
}//end drawCard
void Deck::addCard(int val, string s)
{
top = new Card(val, s, top);
SIZE++;
}//end addCard
Your problem is here:
while (leftHalf.getSIZE() > 0 && rightHalf.getSIZE() > 0){
If you have drawn all the cards from leftHalf but rightHalf still contains some cards then your cycle ends. In that case your shuffled Deck doesn't contains all cards.
After that cycle you need for example to implement two cycles like this:
while (leftHalf.getSIZE() > 0)
// Draw all remaining cards from leftHalf
while (rightHalf.getSIZE() > 0)
// Draw all remaining cards from rightHalf
=============================================
Also you can get a "Null pointer access" error here:
d.addCard(draw->getVALUE(), draw->getSUIT());
because draw can be null.
=============================================
Also here:
for (int l = SIZE; l > 0; l--){
you try to draw too many cards. You can start the cycle from j instead of SIZE.
==============================================
Another problem is here:
int probPile = leftHalf.getSIZE()/(leftHalf.getSIZE() + rightHalf.getSIZE())*100;
probPile is always 0 because you use integer division (e.g. 5/100 is 0 if we use integer division). One of the solution to use
floating-point division. You can convert int value to double before division in some way, e.g. by multiplying to 1.0 and then convert the result back to int:
int probPile = static_cast<int>(leftHalf.getSIZE() * 1.0 /(leftHalf.getSIZE() + rightHalf.getSIZE())*100);
Or you can multiply by 100 before division:
int probPile = leftHalf.getSIZE() * 100/(leftHalf.getSIZE() + rightHalf.getSIZE());
//amt = amount of cents to get change for
//onhand = array of available coins . Ex: {3, 0, 1, 0} = 3 quart, 0 dime, 1 nickel, 0 pennies
//denoms = {25, 10, 5, 1}
//ndenoms = 4 ; i.e the number of different denominations
// thechange = array of change. Ex: if amt = 80, then one possible thechange = {3, 0, 1, 0} b/c 3*25 + 1*5 = 80 cents
int i = 0;
void makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
if ( (denoms[i] * onhand[i]) > amt)
{
onhand[i]--; // # of coins is too much, decrement and try again
makechange(amt, onhand, denoms, ndenoms, thechange); // try agan
}
thechange[i] = onhand[i]; //found #of coins
amt = amt - denoms[i]*onhand[i]; // get remaining amount from change
i++;
if (amt != 0) // we're not done with change so move on to next denomination
{
makechange(amt, onhand, denoms, ndenoms, thechange);
}
else if (amt == 0) // we're done with the change so all the other # coins = 0
{
for (int j = i; j < amt; j++)
{
thechange[j] = 0;
}
}
}
Now, down in main when I actually call the function prototype and print out the result
//
makechange(amt, onhand, denoms, ndenoms, thechange);
for (int k = 0; k < ndenoms; k++)
{
cout << thechange[i] << " ";
}
//
I get an error.
This algorithm seems seems sensible to me, does anyone know why it keeps crashing, though?
Have I properly used recursion here?
If you call makechange twice, the second time it won't work because the global variable i will be wrong.
Also what should happen if you try to makechange and don't have enough change on hand to make it?
Similarly what happens if you have 3 quarters and 3 dimes, and are asked to make 80 cents in change? Your algorithm will use all 3 quarters and then get stuck.
did you mean
for (int k = 0; k < ndenoms; k++) { cout << thechange[k] << " "; }
a little typo made possible by the use of global variable i.
also
for (int j = i; j < amt; j++) { thechange[j] = 0; }
I think you meant
for (int j = i; j < ndenoms; j++)
depending on the final value of amt, this will cause you to run off the end of the array, resulting in a crash.
you can solve this more easily without recursion. are you required to use recursion for an assignment? if not, try this:
int makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
for (int i=0; i < ndenoms && amt > 0; i++)
{
while (onhand[i] > 0 && denoms[i] <= amt)
{
onhand[i]--; // use one coin
thechange[i]++;
amt -= denoms[i];
}
}
return amt; // this is the amount you owe if you dont have enough on hand
}
I made the changes as mentioned by shsmith and here is the modified and complete c++ program.
#include <iostream>
using namespace std;
int i = 0;
void makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
if ( (denoms[i] * onhand[i]) > amt)
{
onhand[i]--; // # of coins is too much, decrement and try again
makechange(amt, onhand, denoms, ndenoms, thechange); // try agan
}
thechange[i] = onhand[i]; //found #of coins
amt = amt - denoms[i]*onhand[i]; // get remaining amount from change
i++;
if (amt != 0) // we're not done with change so move on to next denomination
{
makechange(amt, onhand, denoms, ndenoms, thechange);
}
else if (amt == 0) // we're done with the change so all the other # coins = 0
{
for (int j = i; j < ndenoms; j++)
{
thechange[j] = 0;
}
}}
int main(){
//Now, down in main when I actually call the function prototype and print out the result
int amt = 80, onhand[] = {3, 0, 1, 0}, denoms[] = {25, 10, 5, 1}, ndenoms = 4, thechange[4];
makechange(amt, onhand, denoms, ndenoms, thechange);
for (int k = 0; k < ndenoms; k++)
{
cout << thechange[k] << " ";
}
cout << "\n";
return 0;}
This code is running perfectly on my machine. I compiled it using Cygwin.
Note: This algorithm would work only if you have the denomination coins more or correctly onhand. If there are insufficient number of coins onhand, then there is no exit for the recursive method because 'amt' would never become zero. At the same time, you never check for the 'i' value whether it is in bounds of the 'ndenoms'. This could also result in out of boundary errors which could cause ur program to exit incorrectly.
I'm new to programming, and I'm stuck at a problem. I want my program to identify the separate digits in a given number, like if I input 4692, it should identify the digits and print 4 6 9 2. And yeah, without using arrays.
A perfect recursion problem to tackle if you're new to programming...
4692/1000 = 4
4692%1000 = 692
692/100 = 6
692%100 = 92
92/10 = 9
92%10 = 2
You should get the idea for the loop you should use now, so that it works for any number. :)
Haven't written C code in year, but this should work.
int i = 12345;
while( i > 0 ){
int nextVal = i % 10;
printf( "%d", nextVal );
i = i / 10;
}
Simple and nice
void PrintDigits(const long n)
{
int m = -1;
int i = 1;
while(true)
{
m = (n%(10*i))/i;
i*= 10;
cout << m << endl;
if (0 == n/i)
break;
}
}
Another approach is to have two loops.
1) First loop: Reverse the number.
int j = 0;
while( i ) {
j *= 10;
j += i % 10;
i /= 10;
}
2) Second loop: Print the numbers from right to left.
while( j ) {
std::cout << j % 10 << ' ';
j /= 10;
}
This is assuming you want the digits printed from right to left. I noticed there are several solutions here that do not have this assumption. If not, then just the second loop would suffice.
I think the idea is to have non reapeating digits printed (otherwise it would be too simple)... well, you can keep track of the already printed integers without having an array encoding them in another integer.
some pseudo C, to give you a clue:
int encoding = 0;
int d;
while (keep_looking()) {
d = get_digit();
if (encoding/(2**d)%2 == 0) {
print(d);
encoding += 2**d;
}
}
Here is a simple solution if you want to just print the digits from the number.
#include <stdio.h>
/**
printdigits
*/
void printDigits(int num) {
char buff[128] = "";
sprintf(buff, "%d ", num);
int i = 0;
while (buff[i] != '\0') {
printf("%c ", buff[i]);
i++;
}
printf("\n");
}
/*
main function
*/
int main(int argc, char** argv) {
int digits = 4321;
printDigits(digits);
return 0;
}
Is it correct
int main()
{
int number;
cin>>number;
int nod=0;
int same=number;
while(same){
same/=10;
nod++;
}
while(nod--){
cout<<(int)number/(int)pow10(nod)%10<<"\t";
}
return 0;
}