Strange behavior (Solved: srand() called more than once)

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;
	}
}

Last edited on
Try calling srand only once in your program (in other words, move your call to srand() to the top of main() ).
Amazing!
THANK YOU!
That did it.
Topic archived. No new replies allowed.