C++ Roulette design

As a consequence of a post I've seen on here, I thought roulette would be something that would tweak my limited "C++" skills. What I'm looking for here is;

(a) hints of general algorithm design
(b) where C++ containers, vectors or anything else could be implemented.

A couple a points about this code. I generally try to design top/down so this snippet demonstrates that the random number generator is working as intended and I get to see what the probabilities are. I don't often do this, but "WatchDog" is something I'll probably leave in as it will circumvent program not terminating.

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
#include	<iostream>
#include	<iomanip>
#include	<ctime>

using namespace std;

	// Globals
	int Count [36];

	// Forward declrations
	void ShowStats ();
	void MinMax (int, int);
	
int main (void) {
	int WatchDog = 256;
	
	system ("cls");
	cout << "\n\tRoulette \n\n" << endl;
	srand (time(NULL));
	
	do {
		int Roll = rand () % 37;		// Generate numbers between 0 & 36.
		Count [Roll]++;
		
		cout << setw (4) << Roll;
		if ( !(--WatchDog % 16))
			cout << endl;
		
	} while ( WatchDog );
	
	ShowStats ();
	cout << "\n\n\tBYE" << endl;
	return 0;
}

void ShowStats () {
	int Min, Max;
	int MinI, MaxI;
	
	cout << "\n\tStatistics:\n\n\t\t";
	
	for ( int x = 0; x < 37; x++ ) {
		int Value = Count [x];
		
		if ( !x )
			Min = Max = Value;
		else if ( Min > Value )
			{ Min = Value, MinI = x; }
		else if ( Max < Value )
			{ Max = Value; MaxI = x; }
			
		cout << "[" << setw (2) << x << setw (3) << Value << "] ";
		
		if ( !(x % 3) || !x)
			cout << "\n\t";	
	}
	
	cout << "\n\t  ";
		 MinMax ( Min, MinI);
		 cout << " &"; 
		 MinMax ( Max, MaxI);
		 cout << endl;
}

void MinMax ( int count, int index) {
	cout << setw (3) << count << setw (3) << index;
	
	// Append "'s" for values greater than 1
	if ( count > 1 )
		cout << "'s";
}


Formatting with ios::??? is another thing I have no familiarity with

	Roulette 


   4   6  16  29   2  20  14   4  30  31  13  20   3  25  27  21
  26  29  22  15  14  28  10  23   6  26  27  35   0  13  22   8
  11   2  21   5  28   0  13   0  20  10   0  32  28  30  12  28
   8  16  20  18  34  21  21  18  10  27  30   3   3  21  24  18
   3  15  20  26  35  14  14  15  31  14  14   8  21  28  13   7
  33   2  28   6  25   4  27   0  35  20  18   9   3  11  24  26
  23  12  35  14  31  29   1   0   7  21  24  11  27  27  28  18
   7   8  26  12  25  19  19  17   1   2  34  19  36  35  33  10
  31  21  34  13  25  25  28  17   8  21  18  27  12  32   7  22
   1  23  24   6  25  31  34  25  25  20  12  10   6  29  14   4
  26  17  27  11  29  29   9   7   7   0   8  35  20   0   2  17
  15  31  22  33   8  19  34  11   3   8   4  28   8  14  18  13
  15  34  12   8  30   9  35   1  26   8  17  25  30   3  30   7
  22   2  10  28  13  36   5  11  15  13  16  19  31  25  20   4
  34  27  12  31  11  21  26   6  21  30  24   6  16  11   1   8
  28  15  22   8   8  16  35   4   4   2  26   5  27   8  17   9

	Statistics:

		[ 0  8] 
	[ 1  5] [ 2  7] [ 3  7] 
	[ 4  8] [ 5  3] [ 6  7] 
	[ 7  7] [ 8 15] [ 9  4] 
	[10  6] [11  8] [12  7] 
	[13  8] [14  9] [15  7] 
	[16  5] [17  6] [18  7] 
	[19  5] [20  9] [21 11] 
	[22  6] [23  3] [24  5] 
	[25 10] [26  9] [27 10] 
	[28 11] [29  6] [30  7] 
	[31  8] [32  2] [33  3] 
	[34  7] [35  8] [36  2] 
	
	    2 32's & 15  8's


	BYE
Last edited on
Since you're using C++ you should probably look into using the C++ random class to get better random numbers.

http://www.cplusplus.com/reference/random/

I'd also recommend that you avoid the global variables. And instead of that "raw" array use either std::vector or std::array.
There is no need for a global variable, Count, here. You should pass it as a parameter for ShowStats. As a rule, you should avoid using global variables.

Functions shouldn't have side effects, and should be reentrant. Functions shouldn't use variables that aren't parameters, they should behave like mathematical functions.

As to passing that parameter, if it's an STL container (std::array or std::vector), then it has a little more information than just passing around the address of the first element, which is what happens when you pass an array around.
int Count [36];

Valid indices for Count are 0 to 35.

Which means that:
1
2
        int Roll = rand () % 37;		// Generate numbers between 0 & 36.
        Count [Roll]++;
has undefined behavior.
I guess I've got a couple of days of reading and experimenting jlb. I hadn't realized how comprehensive C++ generators are and I want to have a good understanding of the implications, not just adapt an example.

While I was posting the code kbw, that was one of the first things I had contemplated using <array>.

As a rule, you should avoid using global variables.
From my limited knowledge, I would disagree with that as it's implications on the stack, but as I don't really know how arrays and vectors are constructed. Would I be correct in assuming, it's only the pointer to that container that's on the stack, 8 bytes in my case, rather than 36*8 (288) bytes, plus overhead for the container. When I get to that, I'll just trace into it with GDB and then I'll know, hopefully. Then I might be dealing with compiler options I'm not aware of.

Generally I like to keep main () as clean as possible or at least at a glance be able to recognize program flow. Functions like ShowStats () could just as well have been inserted at line 44, otherwise be it in functions/subroutine or main, I like to avoid nesting any deeper than 4 levels of braces.

Fundamentally, I consider functions that don't return a value a subroutine, but I do concur how ones that return values should be re-entrant. Not exactly sure how I would go about excluding local aka temporary variables from every situation, but first random numbers and then I can deal with that.
From my limited knowledge, I would disagree with that as it's implications on the stack, but as I don't really know how arrays and vectors are constructed.

Why are you so worried about the stack? If you're having problems with stack space then use std::vectors, since they use heap to store the data.

Using global variables makes following the program logic much harder and you should be striving for readability. Unless you have a huge array, or a lot of moderate sized arrays stick with the local variables.

Generally I like to keep main () as clean as possible or at least at a glance be able to recognize program flow.

This is a good practice for all functions not only main(). Strive to keep your functions simple, doing as little as possible. This'll make writing and testing the functions much simpler. Since you can test each function outside of your "big" program.



Last edited on
cire
int Count [36];

Valid indices for Count are 0 to 35.

Which means that:
1
2
3
         int Roll = rand () % 37;		// Generate numbers between 0 & 36.
        Count [Roll]++;
 
has undefined behavior.

I had not contemplated bounds checking, but this error exemplifies the fallacy of not using constants. Had I declared something like const int ArraySize = 37 I would have avoided that problem. As an experiment, I moved Count[12] inside main and I wasn't surprised as to the outcome, but that array in uninitialized space yields a pretty bizarre result. I limited my loop to 48 interations so the probability of some numbers not being selected was more likely.

	Statistics:

		[ 03036865] 
	[ 1  1] [ 2  2] [ 3  0] 
	[ 4  3] [ 5  2] [ 64201253] 
	[ 7  1] [ 8  1] [ 9  2] 
	[104201134] [11  0] [12  6] 
	[13  1] [14 34] [15  0] 
	[16  4] [17  1] [18  2] 
	[19  1] [203036833] [21  2] 
	[224199401] [23  0] [24  0] 
	[25  1] [26 10] [27  1] 
	[284229673] [29  1] [30  3] 
	[31  0] [32  1] [33  0] 
	[34  3] [35  1] [36  1] 
	
	    0  3 &4229673 28's

I'm also surprised that windows "program not responding" only happened once of the 5 times I tried the broken code. I guess that fortifies undefined behavior.
Last edited on
This is what I've come up with now, which I believe is consistent with recommendation and conforms more with the spirit of C++. I've confirmed, numbs is a pointer to the vector and doesn't have an adverse affect on stack no matter ArraySize. Output also demonstrates the significance of line 20 and distribution is fairly uniform even with iteration counts less than 32. Most of what is in this snipped will eventually be removed, but this has confirmed the randomness I was looking for.

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
#include	<iostream>
#include	<chrono>
#include	<random>
#include	<iomanip>
#include	<vector>

using namespace std;

  const int ArraySize = 37;
  
  void MinMax (int, int);
  
int main (void) {
	int count, value;
	int Min, MinIndex, Max, MaxIndex;
	vector <int> numbs ( ArraySize, 0 );
	
	unsigned seed = chrono::system_clock::now ().time_since_epoch ().count ();
	default_random_engine randGen (seed);
	uniform_int_distribution <int> distribution (0, ArraySize - 1);
	
 	cout << "\n\tRoulette number generator test bed. How many iterations? ";
	cin >> count;
	
	if ( !count )
		exit (-1);
	
	system ("cls");
	cout << " ";
	
	do {
		value = distribution (randGen);
		numbs [value]++;
		
		cout << setw (4) << value;
		
		if ( !((count-1) % 32) )
			cout << endl << " ";
		
	} while ( --count );
	
	cout << "\n\n\tStatistics:\n" << endl;
	count = 0;
	cout << "\t\t";
	
	for ( auto Value : numbs ) {
		if ( !count )
			Min = Max = Value;
		else if ( Min > Value )
			{ Min = Value, MinIndex = count; }
		else if ( Max < Value )
			{ Max = Value; MaxIndex = count; }
			
		cout << "[" << setw (2) << count << setw (3) << Value << "] ";
		
		if ( !(count % 3) || !count)
			cout << "\n\t";	
		
		count++;
	}
	
	cout << "\n\t  ";
	MinMax ( Min, MinIndex);
	cout << " &"; 
	MinMax ( Max, MaxIndex);
	cout << endl;
	
	cout << endl;
	return 0;	
}

void MinMax ( int count, int index) {
	cout << setw (3) << count << setw (3) << index;
	
	// Append "'s" for values greater than 1
	if ( count > 1 )
		cout << "'s";
}
Last edited on
Topic archived. No new replies allowed.