Need to find a logic error in a card shuffling method - c++

I'm trying to write a method that takes an array of integers (0-51, in that order), cuts it into two separate arrays (A and B in the below function by using the cut method, which I know for sure works) and then re-fuses the two arrays together by randomly selecting 0, 1 or 2 cards from the BOTTOM of either A or B and then adding them to the deck.
(ps- by "array" I mean linked list, I just said array because I thought it would be conceptually easier)
This is my code so far, it works, but there's a definite bias when it comes to where the cards land. Can anybody spot my logic error?
[code]
void Deck::shuffle(){
IntList *A = new IntList();
IntList *B = new IntList();
cut(A, B);
IntListNode *aMarker = new IntListNode;
aMarker = A->getSentinel()->next;
//cout<< A->getSentinel()->prev->prev->data <<'\n'<<'\n';
IntListNode *bMarker = new IntListNode;
bMarker = B->getSentinel()->next;
//cout<< B->getSentinel()->prev->data;
deckList.clear();
srand(time(NULL));
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
while(totalNumCards < 52){
randNum = rand() % 3;
if(randNum == 0){
selector = !selector;
continue;
}
numCards = randNum;
if(!aisDone && !bisDone){
if(selector){
for(int i = 0; i < numCards; i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
selector = false;
}else{
for(int i = 0; i < numCards; i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
selector = true;
}
}
if(aisDone && !bisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
//return;
}
if(bisDone && !aisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
//return;
}
totalNumCards += numCards;
}
int tempSum = 0;
IntListNode *tempNode = deckList.head();
for(int j = 0; j < 52; j++){
//cout<< (tempNode->data) << '\n';
tempSum += (tempNode->data);
tempNode = (tempNode ->next);
}
if(tempSum != 1326)
system("PAUSE");
return;
}
[/code]

What about just using std::random_shuffle? Yeah, it won't work for linked list, but you can change it to vector :)

If your instructor would have the moral to teach you programming the way it should be done then they'd encourage you to solve the problem like so, with four lines of code:
#include<algorithm>
#include<vector>
// ...
std::vector<int> cards; // fill it in ...
std::random_shuffle(cards.begin(), cards.end());
Using the standard library is the right way of doing things. Writing code on your own when you can solve the problem with the standard library is the wrong way of doing things. Your instructor doesn't teach you right. If they want to get a point across (say, have you practice using pointers) then they should be more attentive in selecting the exercise they give you.
That speech given, here is a solution worse than the above but better than your instructor's:
52 times do the following:
Choose two random none-equal integers in the range [0,52).
Swap the values in the array corresponding to these positions.

For most random number generators, the low bits are the least random ones. So your line
randNum = rand() % 3;
should be modified to get its value more from the high- to middle-order bits from rand.
Your expectations may be off. I notice that you swap the selector if your random value is 0. Coupled with the relative non-randomness of randNum, this may be your problem. Perhaps you need to make things less random to make them appear more random, such as swapping the selector every time through the loop, and always taking 1 or more cards from the selected deck.

Comments:
srand(time(NULL));
This should only be called once during an applications run. This it is usally best to call it in main() as you start.
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
One identifier per line. Every coding standard written has this rule. It also prevents some subtle errors that can creep in when using pointers. Get used to it.
randNum = rand() % 3;
The bottom bits of rand are the lest random.
rand Num = rand() / (MAX_RAND / 3.0);
Question:
if(!aisDone && !bisDone)
{
This can execute
and set one of the above to isDone
Example:
Exit state aisDone == false bsiDone == false // OK
Exit state aisDone == true bsiDone == false // Will run below
Exit state aisDone == false bsiDone == ture // Will run below
}
if(aisDone && !bisDone)
{
Is this allowed to run if the first block above is run?
}
if(bisDone && !aisDone)
{
Is this allowed to run if the first block above is run?
}
The rest is too complicated and I don't understand.
I can think of simpler techniques to get a good shuffle of a deck of cards:
for(loop = 0 .. 51)
{
rand = rand(51 - loop);
swap(loop, loop+rand);
}
The above simulates picking a card at random from the deck A and putting it on the top of deck B (deck B initially being empty). When the loop completes B is now A (as it was done in place).
Thus each card (from A) has the same probability of being placed at any position in B.

Related

Fill index common matrix fields [STRANGE BUGS]

It's my first time posting here, but I always look for some ideas between your posts.
I'm trying to fill the upper half of an array accordingly to the other filled cells (all with 0s and 1s), something like this:
if (matrix[3,2] == 1) and (matrix[3,1] == 1){
matrix[2,1] = 1;}
After much trying, I've made something that barely works with:
matrix[a][b] = 1;
for (unsigned int i = 0; i < max_index; i++){
if (matrix[i][a] == 1){
matrix[i][b] = 1;
}
}
But all I can do is wait for a matrix[corner_i.v1][corner_i.v2] that fills some gaps that shouldn't exists... like this [0, 2]:
01011
00111
00011
00001
00000
Can you guys give me some advices or show some way that I can make this happen? Thank you all.
[edit 2]:
I figured out this was left, but the code still not working at 100%:
for (unsigned int i = 0; i < max_index; i++){
if (matriz[i][a] == 1){
matriz[i][b] = 1;
}
else if (matriz[b][i] == 1){
matriz[a][i] = 1;
}
}
Output be like
[EDIT 3]:
I've solved part of the problem in the function void conectar_matriz(), but some of the inputs seems to bug the program, specially matrices over 40x40.
https://pastebin.com/L3GsciK0

Why is my output freezing when it gets to this section of the code?

I'm trying to compare two decks of cards, yet every time I try another method of doing it, I get the same result... Everything before the code outputs, and it just freezes as soon as it hits the comparison code, as if it's stuck in an infinite loop.
I've tried for loops, static variables, do-while loops, etc. This is my first time leaving the loop at the client code.
The code that supposedly throws the program into an infinite loop.
while (repeatLoop == false)
{
deck1.shuffleDeck();
counter++;
repeatLoop = deck1.compareDecks();
}
compareDecks function.
bool deck::compareDecks()
{
int deckCount = 0;
suitType tempOriginalSuit;
suitType tempShuffleSuit;
rankType tempOriginalRank;
rankType tempShuffleRank;
while (index < 52)
{
tempOriginalSuit = originalCardDeck[index].getSuit();
tempShuffleSuit = shuffledCardDeck[index].getSuit();
if (int(tempOriginalSuit) == int(tempShuffleSuit))
{
tempOriginalRank = originalCardDeck[index].getRank();
tempShuffleRank = shuffledCardDeck[index].getRank();
if (int(tempOriginalRank) == int(tempShuffleRank))
{
deckCount++;
if (deckCount == 52)
return true;
}
}
else
{
return false;
index++;
}
}
}
The shuffleDeck function
(This function pushes back the first card from the first half of the deck and the first card from the second half of the deck towards the end until all 52 cards have been pushed in this pattern. This makes the deck have 52 x 2 cards (with the second half of the deck being the perfect shuffle), so I delete the first half of the cards using .erase as it is not needed)
void deck::shuffleDeck()
{
for (int a = 0, b = 2; a < 2 && b < 4; a++, b++)
{
for (int i = 2; i < 15; i++)
{
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(a),
static_cast<cardSpace::rankType>(i) });
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(b),
static_cast<cardSpace::rankType>(i) });
}
}
shuffledCardDeck.erase(shuffledCardDeck.begin(),
shuffledCardDeck.begin() + (shuffledCardDeck.size() / 2));
}
The two decks initialized by this constructor.
deck::deck()
{
for (int i = 0; i < 4; i++)
{
for (int j = 2; j < 15; j++)
{
originalCardDeck.push_back(card{ static_cast<cardSpace::suitType>(i),
static_cast<cardSpace::rankType>(j) });
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(i),
static_cast<cardSpace::rankType>(j) });
}
}
}
Also note that I've done a perfect shuffle on the shuffledCardDeck vector in another function. I'm trying to repeat the perfectShuffle function until it reaches it's original state and output how many times it took to do this.
I get an infinite loop.
EDIT: I've decided to add the return false; statement in the compareDecks function into the if-else. Also, I think what's causing the problem is that my index i is reset to zero everytime it is called again. Are there any solutions you guys could propose to this? I've tried using static variables, but they just would not increment in the for loop.
EDIT 2: I enclosed my if statements within the curly braces, per users' request, as it's a flaw in my code.
EDIT 3: After commenting out
deck1.shuffleDeck()
The compareDecks function returned true, stating that the decks are equal, which isn't supposed to happen... This caused the loop to end after only one loop.
I was expecting you to actually shuffle the deck.
Your code was pushing a specific, newly synthesized card onto the end of the deck:
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(a),
static_cast<cardSpace::rankType>(i) });
For example, the first card it will push is always the 2 of 0's (Whatever the 0th suit is). That's not what you want. You actually want to push a copy of the card that is at a specific position index in the deck. For example, loop index from 0 to 25 and then push shuffledCardDeck[index] and shuffledCardDeck[26 + index].
Then you can still wrap up by using your technique of erasing the first half of the deck.
void deck::shuffleDeck()
{
for (int index = 0; index < 26; ++index) {
shuffledCardDeck.push_back(shuffledCardDeck[index]);
shuffledCardDeck.push_back(shuffledCardDeck[26 + index]);
}
shuffledCardDeck.erase(shuffledCardDeck.begin(),
shuffledCardDeck.begin() + 52);
}
You are not modifying the value in the loop, you're using a double equals sign:
repeatLoop == deck1.compareDecks();
That would explain your observed behavior.

How does the Hill Climbing algorithm work?

I'm learning Artificial Intelligence from a book, the book vaguely explains the code I'm about to post here, I assume because the author assumes everyone has experienced hill climbing algorithm before. The concept is rather straightforward, but I just don't understand some of the code below and I'd like someone to help me understand this algorithm a bit clearer before I move on.
I commented next to the parts that confuses me most, a summary of what these lines are doing would be very helpful to me.
int HillClimb::CalcNodeDist(Node* A, Node* B)
{
int Horizontal = abs(A->_iX - B->_iX);
int Vertical = abs(A->_iY - B->_iY);
return(sqrt(pow(_iHorizontal, 2) + pow(_iVertical, 2)));
}
void HillClimb::StartHillClimb()
{
BestDistance = VisitAllCities();
int CurrentDistance = BestDistance;
while (true)
{
int i = 0;
int temp = VisitAllCities();
while (i < Cities.size())
{
//Swapping the nodes
Node* back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back; // Why swap last city with first?
CurrentDistance = VisitAllCities(); // Why visit all nodes again?
if (CurrentDistance < BestDistance) // What is this doing?
{
BestDistance = CurrentDistance; //???
break;
}
else
{
back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back;
}
i++;
}
if (CurrentDistance == temp)
{
break;
}
}
}
int HillClimb::VisitAllCities()
{
int CurrentDistance = 0;
for (unsigned int i = 0; i < Cities.size(); i++)
{
if (i == Cities.size() - 1)//Check if last city, link back to first city
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[0]);
}
else
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[i + 1]);
}
}
return(CurrentDistance);
}
Also the book doesn't state what type of hill climb this is. I assume it's basic hill climb as it doesn't restart when it gets stuck?
Essentially, it does this in pseudo-code:
initialize an order of nodes (that is, a list) which represents a circle
do{
find an element in the list so that switching it with the last element of the
list results in a shorter length of the circle that is imposed by that list
}(until no such element could be found)
VisitAllCities is a helper that computes the length of that circle, CalcNodeDist is a helper that computes the distance between two nodes
the outer while loop is what I called do-until, the inner while loop iterates over all elements.
The if (CurrentDistance < BestDistance) part simply checks whether changing that list by swapping results in a smaller length, if so, update the distance, if not, undo that change.
Did I cover everything you wanted to know? Question about a particular part?

Increment the value of a map

need your help and better if you can help me fast. It is very trivial problem but still can't understand what exactly i need to put in one line.
The following code i have
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i));
}
else
{
how can i increment "i" if the key of my statation is already in the map.
}
}
Just briefly what i do , i take the first busrequest go to the second loop take the first station and find the minimum distance. After i go over the second loop , i add that station with minimum distance to my map . After i proceed with all my loops and if there is the same station , i need to increment it , so it means that that station is using two times and etc.
I need the help just give me hint or provide the line that i need to add.
I thank you in advance and waiting for your help.
And I think you meant Min Distance instead of i? Check and let me know.
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i)); // here???
}
else
{
// This routine will increment the value if the key already exists. If it doesn't exist it will create it for you
YourMap[YourKey]++;
}
}
In C++ you can directly access a map key without inserting it. C++ will automatically create it with default value.
In your case, if a station is not present in people map and you will access people[station] then people[station] will automatically be set to 0 ( default value of int is 0 ).
So you can just do this:
if (people[station] == 0)
{
// Do something
people[station] = station; // NOTE: i is not accessible here! check ur logic
}
else
{
people[station]++;
}
Also: In your code i cannot be accessed inside IF condition to insert into people map.

bus error caused by print statement

Ok so I have simple function that returns the highest non-pair card from a 5 card poker hand. But he problem I'm having is wierd. There is this random bus error that occurs randomly, and I don't know for what reason. I thought it was the print statements I was using but now I'm not sure. I know it looks a mess, but if you look at the line below where I print the words "test print", can someone tell me why immediately after this line theres a bus error and it doesn't get to the second "test print" statement. Could I have run out of memory for my program??? That probably makes no sense, but I can't really think of anything else (please exclude the slightly confusing code):
int Hand::highestNonPair(int *face_array_exclude, int size)
{
int highest = 0;
int contains_excludable = 0;
int i = 0;
if(this->hasAnother(i) == false)
highest = cards[i]->getFace();
for(i= 0;i<cards.size();i++)
{
if((cards[i+1]->getFace() > cards[i]->getFace()) &&
(this->hasAnother(i) == false)){
if(size>0){
for(int c = 0;c<size;c++){
if(cards[i]->getFace() == face_array_exclude[c])
contains_excludable = 1;
}
}
if(!contains_excludable)
highest = cards[i+1]->getFace();
cout<<\nTEST PRINT"<<endl;
contains_excludable = 0;
cout<<\nTEST PRINT"<<endl;
}
}
return highest;
}
The bit can case problems:
if((cards[i+1]->getFace() > cards[i]->getFace()) &&
As the highest value of i could be cards.size() - 1. This would mean that cards[i+1 will be an invalid entry.
Change the loop:
for(i= 0;i<cards.size();i++)
to
for(i= 0;i<cards.size() - 1;i++)
Perhaps