Not sure if rand() working properly

I have a simple program to generate some random dice rolls. There is also a child class called LoadedDice that has a 50% chance to return the max value. Everything seems to work fine, but the loaded die isn't returning the max value 50% of the time. It seems to return the max value once or twice every ten rolls. Is there a mistake in my code? The function in question starts at line 41.

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

using namespace std;

class Dice
{
public:
	Dice()
	{
		numSides = 6;
	}

	Dice( int numSides)
	{
		this->numSides = numSides;
	}

	virtual int rollDice() const
	{
		return (rand() % numSides + 1);
	}
protected:
	int numSides;
};

class LoadedDice : public Dice
{
public:
	LoadedDice()
	{
		numSides = 6;
	}

	LoadedDice( int numSides)
	{
		this->numSides = numSides;
	}

	int rollDice() const
	{
		if((rand() % 2 + 1) == 1)
		{
			return (rand() % numSides + 1);
		}
		else
		{
			return numSides;
		}
	}
};

// Take two dice objects, roll them, and return the sum
int rollTwoDice(const Dice& die1, const Dice& die2)
{
	return die1.rollDice() + die2.rollDice();
}

int main()
{
	srand(time(NULL));

	Dice sixSidedDie(6);
	Dice tenSidedDie(10);

	cout << "\nRolling two normal dice:\n";

	for(int i = 0; i < 10; ++i)
	{
		cout << rollTwoDice(sixSidedDie, tenSidedDie) << endl;
	}

	LoadedDice loadedDie;

	cout << "\n\nRolling the loaded die with a 50 percent chance to roll max val:\n";

	for(int i = 0; i < 10; ++i)
	{
		cout << loadedDie.rollDice() << endl;
	}

	LoadedDice twentySidedLoadedDie(20);

	cout << "\n\nRolling a 20-sided loaded die:\n";

	for(int i = 0; i < 10; ++i)
	{
		cout << twentySidedLoadedDie.rollDice() << endl;
	}

	return 0;
}
Last edited on
It worked fine for me. It could just be chance (you are using 'random' numbers). Here is an example output for me:

Rolling two normal dice:
8
9
13
5
6
8
3
12
6
7


Rolling the loaded die with a 50 percent chance to roll max val:
6
6
6
6
6
4
6
6
6
6


Rolling a 20-sided loaded die:
20
20
20
20
3
8
20
20
13
20
my output seems to be working as well.
Rolling two normal dice:
6
11
7
15
5
5
7
11
3
14


Rolling the loaded die with a 50 percent chance to roll max val:
3
6
6
4
2
6
3
3
2
6


Rolling a 20-sided loaded die:
20
11
20
6
20
20
20
3
19
20

Weird, it must just have something to do with my environment. Thanks for reassuring me, though!
Looks reasonable to me. You just have very small samples.

If you're interested in a slightly different implementation which uses the more up-to-date C++11 random facilities:

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
#include <iostream>
#include <random>
#include <numeric>
#include <iterator>

// seed the generator
std::mt19937 generator((std::random_device())());

struct DieInterface
{
    virtual ~DieInterface() = default;
    virtual unsigned operator()() const = 0 ;
    virtual unsigned sides() const = 0;
};

struct Die : public DieInterface
{
    Die(unsigned nSides) : _dist(1, nSides) {}

    unsigned operator()() const { return _dist(generator); }
    unsigned sides() const { return _dist.b(); }

private:
    mutable std::uniform_int_distribution<unsigned> _dist;
};

struct LoadedDie : public DieInterface
{
    using distribution = std::uniform_int_distribution<unsigned>;

    LoadedDie(unsigned nSides, unsigned loadedFace, unsigned weight_out_of_100)
        : _dist(1, nSides - 1), _face(loadedFace), _weight(weight_out_of_100) {}

    unsigned operator()() const
    {
        using param_type = distribution::param_type;

        if (_dist(generator, param_type{ 1, 100 }) >= _weight)
            return _face;
        else
        {
            unsigned face = _dist(generator);

            if (face >= _face)
                ++face;

            return face;
        }
    }

    unsigned sides() const { return _dist.b() + 1; }

private:
    mutable distribution _dist;

    unsigned _face;
    unsigned _weight;
};


// Take two dice objects, roll them, and return the sum

template <typename iter_type>
unsigned roll(iter_type beg, iter_type end)
{
    using die_type = const DieInterface&;
    return std::accumulate(beg, end, 0u, [](unsigned x, die_type d) { return x + d(); });
}

int main()
{
    Die dice[] = { Die(6), Die(10) };

    std::cout << "\nRolling two normal dice:\n";
    for (int i = 0; i < 10; ++i)
        std::cout << roll(std::begin(dice), std::end(dice)) << '\n';

    {
        const unsigned faces = 6;
        const unsigned loaded_face = 6;
        const unsigned weight = 50;

        LoadedDie die(faces, loaded_face, weight);

        std::cout << "\n\nRolling the loaded die with a 50 percent chance to roll max val:\n";
        for (int i = 0; i < 10; ++i)
            std::cout << die() << '\n';
    }

    {
        const unsigned faces = 20;
        const unsigned loaded_face = 5;
        const unsigned weight = 50;

        LoadedDie die(faces, loaded_face, weight);

        std::cout << "\n\nRolling a 20-sided loaded die: (" << loaded_face << "is loaded)\n";
        for (int i = 0; i < 10; ++i)
            std::cout << die() << '\n';
    }
}


http://ideone.com/g6rmXt
Topic archived. No new replies allowed.