[web] [PHP] rand with percentage

Recommended Posts

menyo    972
hi,

I am trying to automaticly generate a tile map. Now let's say i want a 50% chance it makes a tile a grass tile, a 30% chance for a forest and a 20% chance for a mountain.

I could do it like this but there must be some shortcut to this:

let's say 1=grass, 2=forest and 3=mountain.

$type=array('1','1','1','1','1','2','2','2','3','3');echo$type[rand(0,9)];

problem here is if i want to have something with 4,3% chance i have to build an array with 1000 keys. So i could use:
$type = rand(1,1000);if ($type > 43){//insert that type}

Are there other ways to get what i want?

[Edited by - menyo on December 5, 2010 7:25:32 AM]

Share on other sites
Alan Kemp    772
If you have a list of the percentage chance you want for each tile type you could pick a random percentage (from 0-100) and go along your chances array adding up the values until you got to the slot that represents the chance you randomly selected.

Maybe something like this (my php is rusty, so the syntax might be off):

$tile_chances = array( 50, 30, 20 );$tile_types   = array( 1, 2, 3 );$chosen_value = rand( 0, 100 );$current_percent = 0;for ( $i = 0;$i < 3; $i++ ){$current_percent = $current_percent +$tile_chances[ $i ]; if ($current_percent >= $chosen_value ) { // use tile from$tile_types[ $i ] }} Alan Share this post Link to post Share on other sites Cygnus_X 359 Why not just do:$Rand = mt_rand(0, 10000) / 100; //creates a number between 0.00 and 100.00

if($Rand < 10.03) { //make tile 1; } elseif($Rand >= 10.03  Rand < 20.22)
{ //make tile 2; }

etc

I'm sure there is a way to improve upon the if/else statements, but its pretty direct and works.

Share on other sites
leiavoia    960
You might consider a lottery-ball system. This was copied from some C++ code i wrote a million years ago, but i'm sure you can reappropriate it for PHP:

// given a vector of integer lotto balls, picks an index// returns 0 otherwise (since there is usually a first index)int Lotto(  std::vector<int> v  ) {	// count them all for a total	int total = 0;	for(unsigned int x=0; x < v.size(); x++) {		total += v[x];		}	// short circuit for floating point exceptions	if (total == 0) {return 0;}	// choose one	int pick = int( rand() % (total) );	// find the index it belongs to	int run = 0;	for(unsigned int x=0; x < v.size(); x++) {		int was = run;		run += v[x];		if ( (pick >= was) && (pick < run) ) {return x;} else {continue;}		}	return 0;	}

Share on other sites
menyo    972
Thnx all,

I am going for the if statement technique. However i was hoping for a quicker approach. I vaguely remember a Pascal program i wrote an age back for school that had something similar but way shorter. The if statement technique ill work fine i guess.