Josh Cooper
, , ,
No Comments


Number distributions are excessively useful to random number generators. Procedural generation tends to revolve around random numbers, ergo number distributions are immensely useful in procedurally generating data.

With distributions you can easily give some spice to your random number rolls. Give a hero a damage range (eg. damage: 400-800), next calculate the weight of values in that range based on the hero’s level. So now you have a hero at level 1 who will roll more 400’s than 800’s; take a max level hero and they can roll more 600’s or 800’s or whatever number from the range that you want. This type of generation can apply to whatever you’d like though.

In my Hypermaze project I used number distributions for the maze graph generation. The distributions, essentially, defined all the features of the maze. As for how I calculated, and weighted the distributions, most things were tied to the value of C (complexity parameter). So instead of using something like a hero’s level to affect generation, I was using a (0.0 – 1.0) value. Suddenly I could directly affect how many shortcuts, loops, corridors, and dead-ends would be generated throughout a maze’s creation.

Here you can see how easy it is to setup number distributions with C++11; I doubt C++14 has changed it much.
(Note: If you want to take a look at the rest of the Generate() function, the file is /src/World/src/Graph.cpp)

//Generates the Maze Graph
	Node* Generate( GraphSet& graph, ushort N, float C )
	{
		assert( graph.empty() );
		assert( N >= 2 );
		assert( C >= 0 && C <= 1.0 );

		//Mathematical function to help determine probability fields
		auto W = [&]( ushort X )
		{
			double Slope = cos( C * PI );
			return 5 + ( Slope * sin( X*( PI / 5 ) ) );
		};

#pragma region "RNG Setup"
		std::vector<double> intervals1{3, 4, 5, 6, 7, 8};
		std::vector<double> intervals2{2, 3};
		std::vector<double> weights1{W( 3 ) * 1, W( 4 ) * 2, W( 3 ) * 2, W( 5 ) * 3, W( 7 ) * 3, W( 6 ) * 2};
		std::vector<double> weights2{W( 3 ) * 10, W( 7 ) * 5};

		std::piecewise_linear_distribution<double> BigRoom_DoorGen( intervals1.begin(), intervals1.end(), weights1.begin() );
		std::piecewise_linear_distribution<double> SmallRoom_DoorGen( intervals2.begin(), intervals2.end(), weights2.begin() );
		std::bernoulli_distribution BIGROOM_Chance( 0.1 + ( 0.5f * C ) );
		std::bernoulli_distribution DEADEND_Chance( 0.87 - ( 0.62 * C ) );
		std::bernoulli_distribution LOOP_Chance( 0.23 + ( 0.42f * C ) );
		std::uniform_int_distribution<int> DirectionGen( 0, 3 );
		std::default_random_engine RNG( (unsigned int)time( NULL ) );
		srand( (unsigned int)time( NULL ) );
		
		intervals1.resize( 0 );
		intervals2.resize( 0 );
		weights1.resize( 0 );
		weights2.resize( 0 );
#pragma endregion