Jump to content

Welcome to Geeks to Go - Register now for FREE

Need help with your computer or device? Want to learn new tech skills? You're in the right place!
Geeks to Go is a friendly community of tech experts who can solve any problem you have. Just create a free account and post your question. Our volunteers will reply quickly and guide you through the steps. Don't let tech troubles stop you. Join Geeks to Go now and get the support you need!

How it Works Create Account
Photo

Need help with PHP - rand() problems


  • Please log in to reply

#1
Coel321

Coel321

    New Member

  • Member
  • Pip
  • 7 posts
Hello, for a school project, I am making an internet game in PHP, an online strategy game.(That means text/click based) Which is the most important project in my school career so far. But I'm stuck on a part where I am building an engine(for fighting simulation) which has been bothering me for quite some time now and I finally decided to ask for some help here, because I can't seem to find a solution to this, and since the deadline is february, I don't got much time left(since I also have a lot more things to do for school).

First, I'll talk something about my problem here, then I will give some of the source code to get a better insight into the problem.

I use randoms to randomly decide who will be fighting who(random battles)There are 13 types of units, so it is x=rand(1,13) to ensure x is a natural number n, example: 5 or 8 I made round(rand(1,13)) now the problem is as following, I got this rand and twelve other rands(13 in total) which should all give a number between 1 and 13. Now to avoid conflict, every one of these numbers should be different, so random #1 could have number 1, but random #8 can't have 1 as well. The problem is, that it does give the same numbers again, despite my effort to avoid that.

Here's a bit of source code:

while($count1 != 1){
	 $rrand = round(rand(1,13));
	 echo "1: $rrand<BR>";
	 $count1 = 1;
	 }
Now this part defines the initial value of the rand(), of course, this is just one of the 13, but there's no real need to show them all, as they are all practically the same. The echo is a test to see what value it gets. $count1 is used to go back to this loop later on in the script, in certain situations as in, you get the value of the rand, you go into a switch with 13 situations(1-13). If the rand returns 1, then situation 1 is going to happen, but if the other user does not have that type of unit, so unit>=1, then we continue the script, else we set $count1 to 0, so the loop starts again, and the rand() generates a new number.

Then we got the first check to see if the output of a rand is the same as another.
if($krand == $orand)
	{
	$count13 = 0;	
	}
	elseif($krand == $brand)
	{
		$count13 = 0;
	}
	elseif($krand == $lrand)
	{
		$count13 = 0;
	}
	elseif($krand == $jrand)
	{
		$count13 = 0;
	}
	elseif($krand == $crand)
	{
		$count13 = 0;
	}
	elseif($krand == $frand)
	{
		$count13 = 0;
	}
	elseif($krand == $vrand)
	{
		$count13 = 0;
	}
	elseif($krand == $mrand)
	{
		$count13 = 0;
	}
	elseif($krand == $trand)
	{
		$count13 = 0;
	}
	elseif($krand == $srand)
	{
		$count13 = 0;
	}
	elseif($krand == $arand)
	{
		$count13 = 0;
	}
	elseif($krand == $rrand)
	{
		$count13 = 0;
	}
Pretty self-explanatory, if $krand is the same as another rand($arand , $srand, etc) then we go back to his own loop als output a new number, until it got a number that the other rand's didn't get yet.(I chose this one, since this one is the last rand that is called, and thus should get the last remaining number, that's why it checks with every other rand if it's the same or not).

Then for the actual fighting here, let's see how the rand is used in here:

switch($rrand){// What value did we get from the rand() ?
		 case 1:// In case the rand() returned 1
		 if($amountRiflemanb >= 1){//In case the opponent has that type of unit
		switch($role){ // What role do you have?
		case "attacker": // In case you are the attacker
		$sra = $sra * 1.05;
		$srb = $srb * 0.95;// This is for balancing, sra= damage that the Rifleman deals(defined earlier on)
		break;
		case "defender":// In case you are the defender
		$sra = $sra * 0.95;
		$srb = $srb * 1.05;
		break;
		}
		$verliesra = round($srb / $RiflemanHPA);// The loss of your Rifleman = round(damage dealt by opponent's Riflemen / HP of your Rifleman)
		$verliesrb = round($sra / $RiflemanHPB);
		 }
		 else{// In case your opponent does not have Riflemen, then we go back to the loop to generate a new number
			$count1 = 0; 
		 }
		 
		 break;// Rifleman vs Rifleman

So I think here I would have been protected from having the same values for the rands, turns out that I'm wrong. It does produce the same numbers.
Output(for the rands) are the following(before it goes into any kind of checking):(First # of rand, then the output)
1: 11
2: 2
3: 6
4: 12
5: 2
6: 1
7: 6
8: 3
9: 4
10: 3
11: 11
12: 11
13: 2

As you can see, it produces numbers that are the same, but these are what we start with.
At the end of the script, I have placed another echo of these values to see how they changed, and this is the result:

1: 11
2: 2
3: 6
4: 12
5: 2
6: 1
7: 6
8: 3
9: 4
10: 3
11: 11
12: 11
13: 2

They are the same. Bummer.
So yeah, I'm completely out of ideas.
If anyone has suggestions or ideas, or possibly even solutions, I would be a very happy man.
Thank you in advance.
  • 0

Advertisements


#2
Raikia

Raikia

    Member

  • Member
  • PipPip
  • 17 posts
Read "EDIT" at bottom of post


I have personally run into this problem before in the past as well (however, it was a project I was working in C++ for). To break down the issue, you need some way for the script to remember what random numbers have already been generated so it is not generated again (if I misunderstood the problem, please correct me). There are multiple solutions to this problem, so I will outline two possibilities below.

1) The first way to do this is to create an array of 1s and 0s. Let me explain. If you need to generate random numbers 1 through 13, that is 13 random numbers (obviously). Make an array of 13 numbers, all starting with the value of 1 (1 meaning that the number is not generated yet, 0 meaning that it has been generated):
// The easiest way to do it in PHP is:
$randomMemory = array_fill(0, 13, 1);

Now, each time the random number is generated, you can compare it to the array $randomMemory. Because arrays are zero indexed, you must subtract one from the generated number to compare to the array. Lets do an example with some code:
$continue = true;
while ($continue)
{
   $randomNumber = rand(1,13);
   if ($randomMemory[$randomNumber-1] == 1)
   {
      $randomMemory[$randomNumber-1] = 0; // Make sure the script remembers the number generated
      $continue = false;
   }
}
The above code generates one number that has not been computed yet. However, if you noticed, this is very inefficient. Lets say that it was generating the 13th number instead of just the first, and lets say that that remaining number that it needs to generate is 7. The loop will continually execute until 7 is generated (which takes unnecessary time). One way to eliminate this problem is by altering the code to the following:
$randomNumber = rand(1,13);
while (true)
{
   if ($randomNumber > 13)
      $randomNumber = 1; // Read the rest of the code to understand why
   if ($randomMemory[$randomNumber-1] == 1) // If it found a number that has not been used, get out of the loop
      break;
   $randomNumber++;
}
$randomMemory[$randomNumber-1] = 0;
This way, if the numbers 5,2,7, and 9 have already been generated, and the next generated number is 7, it would add 1 to that number until it finds a number that has not yet been used. This eliminates the time of regenerating numbers as we get closer to the end of the amount needed. The random function would only execute 13 times.



2) The second way may be slightly more memory efficient in PHP due to the way PHP handles array binding. It has the same basic idea as #1 above, but instead of an array of 1s and 0s, it has an array of the numbers previously generated (if you want to get more complicated, you can put a sorting algorithm in as well). I won't go into code specifics like I did above unless you request it, but instead of directly accessing the index of a premade array as done in the above example, it would search the array for the generated number to see if it is in the array. Don't be fooled by functions such as "in_array()". Using in_array() is just as inefficient as looping through the entire array to check to see if the value is found (in fact, it does exactly that). While this method is (arguably negligibly) more memory efficient, it has its drawbacks with respect to speed and CPU efficiency. Personally, I would recommend solution #1.



If I didn't accurately understand your predicament or if you would like a more in depth explanation, I would be happy to help you further. I hope this helps.


PS: Watch out for copy and pasting my code above. While it may work, I did not test it personally for typo errors, so slight syntax errors may have snuck in. It is 3:30 AM after all.


EDIT:

After thinking about this further, I determined that I decided to give you the methodology of how it works in other languages. Thanks to PHPs extensive library of premade functions, it is extremely simple to do what you are doing in two lines of code.

$randomNumbers = range(1,13);
shuffle($randomNumbers);

This simply makes an array of numbers 1 through 13 (inclusive), and then randomly shuffles them. Therefore, your first random number would be at location $randomNumbers[0], second one at $randomNumbers[1], etc.

My algorithm described above is best used for other programming languages (ones with more strict type binding, or strict memory allocation). This new solution should be a lot easier to use.

Edited by Raikia, 10 January 2011 - 03:49 PM.

  • 0

#3
Coel321

Coel321

    New Member

  • Topic Starter
  • Member
  • Pip
  • 7 posts
Wow, thank you very much!
I will test this tomorrow when I get the chance.
  • 0

#4
Raikia

Raikia

    Member

  • Member
  • PipPip
  • 17 posts
I'm glad I could help. Let me know of the outcome!
  • 0






Similar Topics

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

As Featured On:

Microsoft Yahoo BBC MSN PC Magazine Washington Post HP