C++ hat random container

Started by
53 comments, last by GameDev.net 19 years, 6 months ago
bug fix: revision 1.55 fixes a bug in the new implementation of std_rand, where _normalized chance weights would always return the first value when using default random number generator.

-:|:-
AngleWyrm
--"I'm not at home right now, but" = lights on, but no ones home
Advertisement
Here's a better implementation of monster drops:
/*================================================================================ hat container example program       http://home.comcast.net/~anglewyrm/hat.html PROBLEM:   Given a set of treasures, and monsters which specifiy their chances of each,   roll up a random treasure according to that monster's level.      Each monster class can have it's own subset of the treasure types available,   with differing probabilities. This way a ThunderChicken isn't carrying a sword.================================================================================*/#include <cstdlib>  // system#include <iostream> // cout#include "hat.h"    // hatusing namespace std;////////////////////////////////////////////////////////////////////////////////// Master treasure list// one type of treasure is coinsint coins[] = { 1, 2, 3, 5, 7, 11 };         // prime number coin countsenum {cp_1, cp_2, cp_3, cp_5, cp_7, cp_11 }; // for clarity in monster definitions////////////////////////////////////////////////////////////////////////////////// Mainint main(){    // create two treasure possibilities: poor and rich        // poor    float poor_dist[3][2] = { {cp_1, 0.50}, {cp_2, 0.30}, {cp_3, 0.20}};    hat<int>poor;    for( int i=0; i<3; i++) {        poor.put_normalized( (int)poor_dist[0], poor_dist[1] );    }        // rich    float rich_dist[6][2] = {         {cp_1,0.15}, {cp_2, 0.10}, {cp_3, 0.15},        {cp_5,0.30}, {cp_7, 0.20}, {cp_11, 0.10}    };        hat<int>rich;    for( int i=0; i<6; i++) {        rich.put_normalized( (int)rich_dist[0], rich_dist[1] );    }        // initialize random number generator    srand( time(NULL) ); rand();        // roll up a poor and a rich level-3 monster    int poor_sum = 0, rich_sum = 0;    for( int i = 0; i < 3; i++ ){ // level three monsters get three rolls        poor_sum = poor_sum + coins[ poor.get() ];        rich_sum = rich_sum + coins[ rich.get() ];    }        // and our monsters have...    cout << "Rich orc has " << rich_sum << " copper pieces." << endl         << "Poor orc has " << poor_sum << " copper pieces." << endl;    cout << endl << endl;    system("pause");}

Hope ya like it,

-:|:-
AngleWyrm

[Edited by - AngleWyrm on September 10, 2004 11:57:32 PM]
--"I'm not at home right now, but" = lights on, but no ones home
I've been working on a quality control testbed, which consists of three files; qc.h, qc.cpp, and main.cpp.

So far, I've been testing specifications to their limits, erroneous use cases, and out_of_range tests. There is a section for compile-time errors, and run-time errors.

I've also been working on error messages that cannot be handled by the class construct, due to design of the container, or due to language limitation.

Anyone got some scenarios that should go into a/this QC process?

-:|:-
AngleWyrm
--"I'm not at home right now, but" = lights on, but no ones home
For those of you using Dev-Cpp, there is now a DevPak available for easy installation.

link from www.devpaks.org
from homepage
--"I'm not at home right now, but" = lights on, but no ones home
Did a marginal improvement on the implementation of std::rand() as a function object; this one stores state information so that you can have several independant random variables in one program. One advantage of this is that you can perform repeatable experiments with different seeds. Another advantage is that you can provide extra dimensionality to your random numbers, so that they don't get over-taxed between several jobs. To do this, create a separate instance for each use, with a separate seed; the extra dimension support comes from the extra seeds.

One caveat: Because std::rand() uses global state info, this function object isn't thread safe. If multiple threads call rand(), then the sequence of numbers generated from a given seed will get 'cross-posted' between the threads, and thus won't be repeatable.

/*================================================================================ hat container example program       http://home.comcast.net/~anglewyrm/hat.html PROBLEM:   Use a custom random number generator,    and produce two independant random variables    using two instances with different seeds.================================================================================*/#include <cstdlib>  // system#include <iostream> // cout#include "hat.h"    // hatusing namespace std;////////////////////////////////////////////////////////////////////////////////// marginal improvement on std::rand()// This functor stores state information,// so that multiple instances can have different seeds.// NOTE: This class is not thread safe (because std::rand isn't); if multiple threads poll rand(),// then the sequence of numbers from a given seed won't be repeatable.class rng_class {public:    void seed( unsigned int s ){ current = s; };    unsigned int operator()(unsigned int range)    {        if ( range == 0 ) return 0; // only one possibility.        // save global rand state, and restore this instance's state        unsigned int global_state = rand();        srand( current );                       // handle cases where range doesn't evenly divide RAND_MAX,        unsigned int bucket_size = RAND_MAX / range;        unsigned int result;        do {           current = std::rand();            result = current / bucket_size;        }  while ( result >= range );                srand( global_state ); // restore global state                return result;    }    protected:    unsigned int current;};////////////////////////////////////////////////////////////////////////////////// Mainint main(){    // create two instances of my rng_class, and seed/initialize them    rng_class first_instance, second_instance;    first_instance.seed( 1234 );    second_instance.seed( 5678 );      // construct two hats that will use the above instances of custom rng_class        hat<string, rng_class> first( first_instance );    hat<string, rng_class> second( second_instance );        // put data into hat    string names[] = { "alpha", "bravo", "charlie", "delta", "echo", "foxtrot"};    for( int i=0; i<6; i++ )    {        first.put( names );        second.put( names );    }            // display a dozen random call signs from two independant random variables    for ( int i = 0; i < 12; i++ )    {       cout << first.get() << "\t" << second.get() << endl;    }                    cout << endl << endl;    system("pause");}


-:|:-
AngleWyrm

[Edited by - AngleWyrm on October 9, 2004 12:13:14 PM]
--"I'm not at home right now, but" = lights on, but no ones home
I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!! I'M THE MAP!!!
Quote:Original post by Anonymous Poster
I'M THE MAP!!! ...


You're wong. You're a human being. I you still think that you are the map then something goes really wrong and I urge you to go and see a doctor.

HTH,
New example program to illustrate using several different probability distributions on a given set:
/*================================================================================hat container example                http://home.comcast.net/~anglewyrm/hat.html  PROBLEM:      Apply several distributions to a given set.    ================================================================================*/#include <iostream> // cout, endl#include <iomanip>  // setw#include <string>   // string#include "hat.h"    // hat containerusing namespace std;int main(){    // A sorted set that we are going to draw from    string days[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };        // Make three different distributions over the subscript,    // so that we can swap in different curves over our data        // first distribution: equal chances of returning any index    hat<size_t> even_chances;    for( int i=0; i<5; i++ ){        even_chances.put( i ); // each offset has default weight of 1 chance    }        // second distribution: skip Tuesdays and Thursays, double chance of Friday    hat<size_t> skip;    size_t indexes[] = { 0, 2, 4 };    size_t weights[] = { 1, 1, 2 };    for( int i=0; i<3; i++ ){        skip.put( indexes, weights );    }            // third distribution: calculated slope using a formula    // ( this formula happens to produce 1/15, 2/15, 3/15, 4/15, 5/15 )    hat<size_t> slope;    for( int i=0; i<5; i++ ){        slope.put_normalized( i, float(i+1)/15.0 );    }        // Initialize random number generator    srand( time(NULL) ); rand();        // Now choose from days[] by using random indexes    for( int i=0; i<20; i++ )    {        // display even chances        cout << setw(10)             << days[ even_chances.get() ];                // second column no Tuesdays or Thursdays        cout << setw(10)             << days[ skip.get() ];                // third column higher chances toward end of week        cout << setw(10)             << days[ slope.get() ];                cout << endl;    }                 cout << endl << endl;    system("pause");}


--"I'm not at home right now, but" = lights on, but no ones home
Revision 1.56 is now up, which adds const_iterator to the class. It also defines const versions of begin() and end(), and will convert from regular iterator to const_iterator.

-:|:-
AngleWyrm
--"I'm not at home right now, but" = lights on, but no ones home
Nice. I, for one, welcome our new random hat overlords. Keep up the good job.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement