Hi everyone, first post. I had a years worth of C++ classes over 10 years ago, but I've used this site over the last year or so, and refreshed all that I learned from them. I'm still pretty much in between beginner and novice, but I've been working on developing a game in c++.
I'm having a strange problem. The program below is copied and trimmed from the game I'm writing. It is meant to take an array of defined objects (cards), and assign them randomly into a new array. It seemed to be working just fine until I added multiplayer. The shuffle_deck function and the array assignment is done separately for each player...each player has their own deck. Logically it should assign unique shuffled decks for each player. Yet for some reason it assigns the same shuffled deck values to each player. Each time the program is run, the shuffle results are different, but they are always duplicated for each player.
I've tried a few different work arounds and have managed to get it to work a number of different ways, but I still want to know why it's happening, and perhaps a more elegant (invisible) work-around. It seems to be a timing issue... if the shuffled decks are assigned at (close to) the same time using a for loop, they duplicate. But if I wait until each players first turn to assign the deck, it works just fine. In fact the code below has two lines commented out, line 101 and 102. This is nested in the for loop that assigns the shuffled decks. It asks for a user input of any key before proceeding to the next assignment. Adding these two lines of code seems to be sufficient (yet ugly) at fixing the problem. Yet even still, if you press any key and enter fast enough, you will still be able to manage a duplicate array assignment.
So something very strange is going on. Perhaps it's platform dependent? I'm using a mac with os x 10.6, compiling using g++ fwiw. From what I know of c++, the logic should work. It has something to do with timing, and array assignment, and something being too fast, and something else being too slow. I'd like to learn about this, and ways to avoid it, and why it's happening. Any input is much appreciated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cstdio>
#include <time.h>
#include <map>
#include <utility>
using namespace std;
#define large_deck 108
class card
{
public:
int card_id;
string card_title;
string card_type;
};
class player_attributes
{
public:
card shuffled_game_deck [large_deck];
} player [4];
class mechanics
{
public:
card starting_deck [large_deck], shuffled_deck [large_deck];
short active_player, size_of_deck, number_of_players;
map<int, card> card_list;
int convert_to_int (const std::string& str);
void define_cards ();
void initialize_game_attributes ();
void initialize_starting_deck ();
void shuffle_deck (int deck_size);
void update_active_player ();
} game;
int main ()
{
game.initialize_game_attributes ();
system("clear");
for (int i = 0; i < game.number_of_players; i++)
{
cout << "Player " << (i+1) << ": " << endl;
for (int j = 0; j < game.size_of_deck; j++)
{
cout << player[i].shuffled_game_deck[j].card_id;
if (j != (game.size_of_deck - 1))
cout << ", ";
}
cout << endl;
}
return 0;
}
int mechanics::convert_to_int (const std::string& str)
{
int result;
std::stringstream(str) >> result;
return result;
}
void mechanics::define_cards ()
{
for (int i = 0; i < large_deck; i++)
{
card_list[i].card_id = i;
card_list[i].card_title = "TEST";
card_list[i].card_type = "TEST";
}
}
void mechanics::initialize_game_attributes ()
{
string user_input;
active_player = 0;
size_of_deck = large_deck;
define_cards ();
do
{
system("clear");
cout << "How many players? ";
cin >> user_input;
}while (user_input != "1" && user_input != "2" && user_input != "3" && user_input != "4");
number_of_players = convert_to_int (user_input);
initialize_starting_deck ();
for (; active_player < number_of_players; active_player++)
{
shuffle_deck (size_of_deck);
for (int i = 0; i < size_of_deck; i++)
player[active_player].shuffled_game_deck [i] = shuffled_deck [i];
// cout << "Type any key and press enter";
// cin >> user_input;
}
active_player = 0;
}
void mechanics::initialize_starting_deck ()
{
for(int i = 0; i < size_of_deck; i++) // initialize starting deck
starting_deck [i] = card_list [i];
}
void mechanics::shuffle_deck (int deck_size) /* Takes the contents of the
starting_deck array, and places them randomly into the shuffled_deck array. */
{
int card_place, shuffle_spot;
int empty_slot_count = 0;
bool has_been_checked [deck_size], empty [deck_size];
// Set default values for flag arrays
for (int i = 0; i < deck_size; i++)
{
has_been_checked [i] = false;
empty [i] = true;
}
/* Count down the ordered cards from back to front, and assign to random array
slot in shuffled_deck */
for (int cards_left = deck_size; cards_left > 0; --cards_left)
{
// Initialize random seed:
srand ( time(NULL) );
/* Generate random placement number, range equal to number of cards left to be
placed: */
card_place = rand() % cards_left + 1;
/* Count empty flags for shuffled_deck array, and when count is equal to random
placement number, store array location in shuffle_spot */
while (card_place > empty_slot_count)
{
for (int shuffle_index = 0; shuffle_index < deck_size; shuffle_index++)
{
if ((empty [shuffle_index] == true) && (has_been_checked [shuffle_index] == false))
{
shuffle_spot = shuffle_index;
++empty_slot_count;
has_been_checked [shuffle_index] = true;
shuffle_index = deck_size;
}
}
}
/* Stores value from starting_deck into the randomly chosen shuffle_spot
position of shuffled_deck, and sets flag to indicate that the array location is
no longer empty. Also resets working values to default for the next loop. */
shuffled_deck [shuffle_spot] = starting_deck [cards_left - 1];
empty [shuffle_spot] = false;
empty_slot_count = 0;
for (int i = 0; i < deck_size; i++)
has_been_checked [i] = false;
}
}
|