Dice experiment

So, I'm trying to make a program that generates a random number between 1 and 36 (the number of combinations possible with dice) and using the real life odds, document which numbers get "rolled" the most (of course, 7 should show up most, but this is just for fun). However, I have a few problems. First of all I'm using time to help with random number generator, but heck, I don't want to wait a second to make sure the next number is different! Secondly, I have a huge problem, I'm using an array for the documentation and for some reason it wants to add to the wrong array number and then go ahead and do the same with the rest (before I learned of the goto command, but it still starts at the wrong number). It's really hard to explain without seeing the code so here it is.

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
#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <ctime> // Needed for the true randomization
#include <cstdlib> 

using namespace std;

int main()
{
	
	int repeat;
	int xRan;
	char end;
	while (true){
		 end;
		 xRan;
		 repeat = 50;
		int Result[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

		while (repeat > 0){

			srand(time(NULL));
			xRan = rand() % 36 + 1; // Randomizing the number between 1-36.

			if (xRan == 1){
				Result[2]++; goto ha;
			}
			
			else if (xRan == 2, 3){

				Result[3]++; goto ha;
			}
			else if(xRan == 4, 5, 6){

				Result[4]++; goto ha;
			}
			else if (xRan == 7, 8, 9, 10){

				Result[5]++; goto ha;
			}
			else if (xRan == 11, 12, 13, 14, 15){

				Result[6]++; goto ha;
			}
			else if (xRan == 16, 17, 18, 19, 20, 21){

				Result[7]++; goto ha;
			}
			else if (xRan == 22, 23, 24, 25, 26){

				Result[8]++; goto ha;
			}
			else if (xRan == 27, 28, 29, 30){

				Result[9]++; goto ha;
			}
			else if (xRan == 31, 32, 33){

				Result[10]++; goto ha;
			}
			else if (xRan == 34, 35){

				Result[11]++; goto ha;
			}
			else if (xRan == 36){

				Result[12]++; goto ha;
			}

			ha:

			cout  << xRan;
			system("PAUSE");
			repeat--;
		}

		cout << Result[2], Result[3], Result[4], Result[5], Result[6], Result[7], Result[8], Result[9], Result[10], Result[11], Result[12];
		cin >> end;
	}
	return 0;
}


p.s. I know this is TERRIBLY inefficient... another reason I'm posting this here, I'd love any advice on shortening it.
As you mentioned, there are some problems with your code, for instance, seeding more than once, and line 78 doesn't do what you think it does.

Consider the following function:

1
2
3
4
5
6
7
8
int random(int min, int max) {
	static bool random = false;//variable is static - life not bound by function scope
	if(!random) {
		random = true;
		srand(time(0));//seed once
	}
	return (min+(rand()%(max+min-1)));
}


Which can be used like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <ctime>
#include <windows.h>

int random(int min, int max) {
	static bool random = false;
	if(!random) {
		random = true;
		srand(time(0));
	}
	return (min+(rand()%(max+min-1)));
}

int main(int argc, char* argv[]) {

	int r = random(1, 4);//random number between one and four inclusive

	std::cin.get();
	return 0;
}
Last edited on
For starters I wouldn't suggest using goto.

xismn wrote:
return (min+(rand()%(max+min-1)));

Shouldn't this be return( rand() % ( max - min + 1) + min )

Just think if you wanted a number between 2 and 36 then yours would be:
2 + ( rand() % 36 + 2 - 1 ) == 2 + ( rand() % 37 ) == 2 + 0->36 == 2->38


OP wrote:
xRan == 2, 3
you do it several times through your code. You can't chain like that using the comma operator. It should be xRan == 2 || xRan == 3

Same goes with your output:
OP wrote:
cout << Result[2], Result[3], Result[4], Result[5], Result[6], Result[7], Result[8], Result[9], Result[10], Result[11], Result[12];
it should be cout << result[2] << result[3] << ect...
document which numbers get "rolled" the most (of course, 7 should show up most, but this is just for fun)


Why would 7 show up the most?

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

struct Die
{
    Die(unsigned faces = 6) : _faces(faces), _die(std::random_device()()) {}
    Die(const Die& d) : _faces(d._faces), _die(std::random_device()()) {}

    unsigned operator()() 
        { return std::uniform_int_distribution<unsigned>(1, _faces)(_die); }

private:
    unsigned _faces;
    std::mt19937 _die;
};

int main()
{
    const unsigned trials = 100000;
    const unsigned faces = 6;
    const unsigned num_dice = 6;

    std::vector<Die> dice(num_dice, Die(faces));
    std::vector<unsigned> counts(faces * num_dice + 1);

    for (unsigned i = 0; i < trials; ++i)
    {
        unsigned rolls = 0;
        for (auto& die : dice)
            rolls += die();
        
        ++counts[rolls];
    }

    std::cout << "Counts\n";

    for (unsigned i = num_dice; i < counts.size(); ++i)
    {
        std::cout << std::setw(2) << i << ": ";
        std::cout << std::setw(6) << counts[i] << " - ";
        std::cout << std::setw(5) << std::fixed << std::setprecision(2);
        std::cout << (counts[i] / (double) trials)*100.0 << "%\n";
    }
}
Counts
 6:      3 -  0.00%
 7:     11 -  0.01%
 8:     55 -  0.06%
 9:    121 -  0.12%
10:    286 -  0.29%
11:    506 -  0.51%
12:    972 -  0.97%
13:   1664 -  1.66%
14:   2515 -  2.51%
15:   3579 -  3.58%
16:   4872 -  4.87%
17:   6169 -  6.17%
18:   7437 -  7.44%
19:   8406 -  8.41%
20:   9027 -  9.03%
21:   9199 -  9.20%
22:   9082 -  9.08%
23:   8362 -  8.36%
24:   7281 -  7.28%
25:   6057 -  6.06%
26:   4752 -  4.75%
27:   3506 -  3.51%
28:   2485 -  2.48%
29:   1711 -  1.71%
30:    975 -  0.97%
31:    541 -  0.54%
32:    246 -  0.25%
33:    123 -  0.12%
34:     40 -  0.04%
35:     15 -  0.01%
36:      2 -  0.00%


http://ideone.com/KLNFU8
Alright for starters, thanks for the pointer on the cout and if statements, I'm so used to using commas... Also, I've made a few adjustments but before I put those up (They are not yet finished), could someone explain the random number generation to me? I sort of just took something that looked like it worked and threw some code together...

Also for the 7 being rolled the most, in dice, there are more combinations possible for 7 than any other number, this is what I'm trying to do in my program, however, due to probability rules I'm going to actually generate two random numbers and use these instead of 1-36.
Last edited on
I would assume 7 would be towards the bottom when you roll 6 dice...

You would have to get a 2 and a 1 on the rest.. so there should only be 6 possible ways to get a 7. With a 6 there are even less choices there is only 1 possible solution all 1s.

So a 7:
2 1 1 1 1 1
1 2 1 1 1 1
1 1 2 1 1 1
1 1 1 2 1 1
1 1 1 1 2 1
1 1 1 1 1 2


The numbers towards the middle should be the most popular since there are the most choices to make that number. So a 7 would only be the most popular with 2 dice not 6. Again 7 would be between 2-12.

With 6 dice there is a total of 66 = 46656 possible combinations.

Here is a program that will do every single roll and output the statistics:

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
#include <iostream>
#include <iomanip>
int main()
{
	int Numbers[31] = { 0 };
	const int Max = 6;
	
	for( int d1 = 0; d1 < Max; ++d1 )
	{
		for( int d2 = 0; d2 < Max; ++d2 )
		{
			for( int d3 = 0; d3 < Max; ++d3 )
			{
				for( int d4 = 0; d4 < Max; ++d4 )
				{
					for( int d5 = 0; d5 < Max; ++d5 )
					{
						for( int d6 = 0; d6 < Max; ++d6 )
						{
							++Numbers[d1+d2+d3+d4+d5+d6];
						}
					}
				}
			}
		}
	}
	
	std::cout << "Number\tTimesRolled\tPercentage" << std::endl;
	const int MaxCombinations = 46656;
	for( int i = 0; i < 31; ++i )
	{
		std::cout << i + 6 << '\t' << Numbers[i] << '\t' <<
		std::showpoint << std::setprecision(3) <<
		(double)Numbers[i] / MaxCombinations * 100 << '%' std::endl;
	}
	return 0;
}
Number	TimesRolled	Percentage
6	1	0.00214
7	6	0.0129
8	21	0.0450
9	56	0.120
10	126	0.270
11	252	0.540
12	456	0.977
13	756	1.62
14	1161	2.49
15	1666	3.57
16	2247	4.82
17	2856	6.12
18	3431	7.35
19	3906	8.37
20	4221	9.05
21	4332	9.28
22	4221	9.05
23	3906	8.37
24	3431	7.35
25	2856	6.12
26	2247	4.82
27	1666	3.57
28	1161	2.49
29	756	1.62
30	456	0.977
31	252	0.540
32	126	0.270
33	56	0.120
34	21	0.0450
35	6	0.0129
36	1	0.00214

http://ideone.com/3Y7EbO

I see you fixed your thing now so it is correct with 2 dice...

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

int main()
{
	int Numbers[11] = { 0 };
	const int Max= 6;
	const int Combinations = 36;
	
	for( int d1 = 0; d1 < Max; ++d1 )
	{
		for( int d2 = 0; d2 < Max; ++d2 )
		{
			++Numbers[d1+d2];
		}
	}
	
	std::cout << "Number\tTimesRolled\tPercentage" << std::endl;
	for( int i = 0; i < 11; ++i )
	{
		std::cout << i + 2 << '\t' << Numbers[i] << '\t' <<
		std::showpoint << std::setprecision(3) <<
		(double)Numbers[i] / Combinations * 100 << '%' << std::endl;
	}
}
Number	TimesRolled	Percentage
2	1	2.78%
3	2	5.56%
4	3	8.33%
5	4	11.1%
6	5	13.9%
7	6	16.7%
8	5	13.9%
9	4	11.1%
10	3	8.33%
11	2	5.56%
12	1	2.78%



http://ideone.com/EgHQe3


http://www.mathsisfun.com/data/probability.html


I appreciate all the help with the probability, really. However, I've got some pretty nice math skills and my only real problems now are the efficient documentation of 36 possible combos (I want to document what exactly was rolled now ex. two fours were rolled to get eight, or a three and a five were rolled to get eight or a five and an eight and so on so forth.) and the problem with coming up with 50 random numbers instantly instead of waiting a few seconds before generating a new one.
By the way, I found a fix to my original problem so now my code looks like this:

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
#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <ctime> // Needed for the true randomization
#include <cstdlib> 


using namespace std;

int main()
{
	
	int repeat;
	int Die1;
	int Die2;

	while (true){
		
		 Die1;
		 Die2;
		 repeat = 50;
		 int Result[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

		while (repeat > 0){

			srand(time(0));
			Die1 = rand() % 6 + 1; // Randomizing the number between 1-6.
			Die2 = rand() % 6 + 1; // Randomizing between 1-6 for second die.

			int numrolled = Die1 + Die2;
			
			Result[numrolled]++;
			
	

			cout << numrolled;
			system("PAUSE");
			repeat--;
		}

		repeat = 36;

		cout << Result[1] << "\n" << Result[3] << "\n" << Result[4] << "\n" << Result[5] << "\n" << Result[6] << "\n" << Result[7] << "\n" << Result[8] << "\n" << Result[9] << "\n" << Result[10] << "\n" << Result[11] << "\n" << Result[12];

		system("PAUSE");
		
	}
	return 0;
}
I get what you were trying to do now. Since there are 36 possible combinations rolling two dice you were trying to pick a random combination. Though for this you would have to have a list of the combinations first and it would be more of a hastle.
Your biggest problem is that you continue to seed the random number generator every time through the loop. Do this once per program run, not once per iteration of the inner loop.

Here's a version using the same Die class in the earlier code I posted. It's not terribly efficient, but it doesn't need to be.

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
#include <map>
#include <sstream>
#include <vector>
#include <random>
#include <iostream>
#include <iomanip>
#include <numeric>

struct Die
{
    Die(unsigned faces = 6) : _faces(faces), _die(std::random_device()()) {}
    Die(const Die& d) : _faces(d._faces), _die(std::random_device()()) {}

    unsigned operator()()
    {
        return std::uniform_int_distribution<unsigned>(1, _faces)(_die);
    }

private:
    unsigned _faces;
    std::mt19937 _die;
};

int main()
{
    const unsigned trials = 100000;
    const unsigned faces = 6;
    const unsigned num_dice = 2;

    std::vector<Die> dice(num_dice, Die(faces));

    using seq_map = std::map<std::vector<unsigned>, unsigned>;
    seq_map sequence_frequency ;

    // generate and store roll sequences.
    for (unsigned i = 0; i < trials; ++i)
    {
        std::vector<unsigned> rolls;
        for (auto& die : dice)
            rolls.push_back(die());

        ++sequence_frequency[rolls];
    }

    // collate roll sequences which have the same total.
    std::map<unsigned, std::vector<seq_map::const_iterator>> by_total ;
    for (auto it = sequence_frequency.cbegin(); it != sequence_frequency.cend(); ++it)
    {
        unsigned total = std::accumulate(it->first.cbegin(), it->first.cend(), 0u);
        by_total[total].push_back(it);
    }

    // display:
    for (const auto& seq : by_total)
    {
        std::cout << std::setw(3) << seq.first << ": ";
        
        std::ostringstream rolls_string;
        
        unsigned freq = 0;
        for (const auto& roll : seq.second)
        {
            for (const auto& value : roll->first)
                rolls_string << '[' << value << ']';
            rolls_string << " (" << roll->second << ")  ";
            freq += roll->second;
        }

        std::cout << std::setw(6) << freq << " - ";
        std::cout << std::setprecision(2) << std::fixed << std::setw(5);
        std::cout << (freq / (double) trials*100.0) << "%\n";
        
        std::cout << '\t' << rolls_string.str() << '\n';
    }
}


http://ideone.com/G3GcDz
Ohhhhhh now I get the seeding part... thank you so much I just couldn't understand what you meant before there. So now I've got a code that rolls 2 dice 50 times and tells you how often each number was rolled and now I want to have it say that number and other number were rolled to get this. I don't want to type all 36 things out, anyone know how I can make this efficiently?

Also, here's my new code:

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
#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <ctime> // Needed for the true randomization
#include <cstdlib> 


using namespace std;

int main()
{
	
	int repeat;
	int Die1;
	int Die2;
	srand(time(0));
	while (true){
		
		 Die1;
		 Die2;
		 repeat = 50;
		 int Result[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

		while (repeat > 0){

		
			Die1 = rand() % 6 + 1; // Randomizing the number between 1-6.
			Die2 = rand() % 6 + 1; // Randomizing between 1-6 for second die.

			int numrolled = Die1 + Die2;
			
			Result[numrolled]++;
			
	

			cout << numrolled;
			repeat--;
		}

		repeat = 36;

		cout << Result[2] << "\n" << Result[3] << "\n" << Result[4] << "\n" << Result[5] << "\n" << Result[6] << "\n" << Result[7] << "\n" << Result[8] << "\n" << Result[9] << "\n" << Result[10] << "\n" << Result[11] << "\n" << Result[12];

		system("PAUSE");
		
	}
	return 0;
}
Last edited on
Topic archived. No new replies allowed.