Solved

Improving my random PHP script

Posted on 2009-03-29
17
454 Views
Last Modified: 2013-11-10
Hey guys. I hope someone can help me out with this script, it has 3 flaws that I would like to improve :-) its a "random PHP code with priorities and maximum weight allowed". I want it to be able to show three 'random' items, but based on: priorities and weight, and a minimum and maximum weight allowed for all 3 combined items it should show.

So fx "Gyn". It could have a priority to show of 50, and a weight of 30. The maximum weight allowed should be 100, and the minimum weight allowed should be 90.
3 items that could show up would be then fx "Gyn" (30 weights, and with a high priority), "hels" (20 weights) and "part" (45 weights). Just as an example.

But there is 3 flaws in this code down below, that I hope someone will be able to help me out with. :-)
1) The priority for an item is the same as its weight, but instead they should be seperate. So it could have a priority of 60 and a weight of 40 fx.
2) This script, once it hits 3 randomly items that a weight greater than 100, stops working. It works fine with a random 3 items with a weight below 100, but when it hits 3 items with a combined weight of over 100 the script just loads and loads until it gives this error
"Fatal error: Maximum execution time of 30 seconds exceeded in /home6/distende/public_html/ran/dodosrangen.php on line 47"
3) The script has no minimum weight allowed at the moment. Its maximum weight allowed is 100, and it's minimum weight could be 80 fx.

Thanks alot for all your time!
0
Comment
Question by:MisterHamper
  • 10
  • 6
17 Comments
 
LVL 28

Expert Comment

by:gamebits
ID: 24012834
Can you post the code?
0
 

Author Comment

by:MisterHamper
ID: 24012962
Oh sorry thought I had posted it!
<?php

function dodosrandgen() {

$show_link = 3;

$separator = "<br />";
 
 

	$links[0]['link'] = "60 gyn";

	$links[0]['priority'] = 60;

	$links[1]['link'] = "30 hels";

	$links[1]['priority'] = 30;

	$links[2]['link'] = "15 mice";

	$links[2]['priority'] = 15;

	$links[3]['link'] = "18 part";

	$links[3]['priority'] = 18;

	$links[4]['link'] = "23 wattaby";

	$links[4]['priority'] = 23;

	$links[5]['link'] = "20 hessa";

	$links[5]['priority'] = 20;

	$links[6]['link'] = "24 boom";

	$links[6]['priority'] = 24;

	$links[7]['link'] = "35 watta";

	$links[7]['priority'] = 35;
 

 

  srand((float)microtime() * 1000000);

  shuffle($links);

  $maximum_weight = 100;

  $current_weight = 0;

 

  if($links) {

    for($i = -1; $i < count($links); $i++) {

      if (($current_weight+$links[$i]['priority'])<$maximum_weight) {

        for($j = 0; $j < $links[$i][priority]; $j++) {

          $newlinksindex = count($newlinks) + 1;

          $newlinks[$newlinksindex] = $links[$i][link];

        }

        $current_weight += $links[$i]['priority'];

      }

    }

  }
 
 
 

$showarray[0] = "";

$showindex = 0;

	do {

		$randindex = rand(0, count($newlinks));

		if(!in_array($newlinks[$randindex], $showarray) && $newlinks[$randindex] != "") {

			$showarray[$showindex] = $newlinks[$randindex];

			$showindex++;

		}

	}while(count($showarray) <= $show_link);
 

	for($i = 0; $i < $show_link; $i++ ) {

		if($show_link == 1 || (($i + 1) == $show_link))

			print $showarray[$i];

		else

			print $showarray[$i].$separator;

	}

	

}

?>

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 24013555
I think you might want this to be a 3-dimensional array so you can process each field separately, but I'm not sure I understand all the issues.

Can you please explain what it is used for, and what the expected outputs might be?

Thanks, ~Ray
// INSTEAD OF THIS

        $links[0]['link'] = "60 gyn";

        $links[0]['priority'] = 60;
 

// MAYBE EASIER TO PROGRAM WITH THIS

        $links[0]['link'] = "gyn";

        $links[0]['weight'] = "60";

        $links[0]['priority'] = 60;

Open in new window

0
 

Author Comment

by:MisterHamper
ID: 24013801
Hey Ray. Yeah it should maybe be a 3-dimensional array. Never heard of those before though. But that code of yours is how I myself imagined it to be, but it haven't quite worked out for me.

A friend of mine needs to use it in order to get an advanced "random calculator" for some of his real-life stuff, that will be able to take into account the weight of an item, while some items is still more favored than others.
So even though one thing might not weight much, it will still have a higher chance of showing up on his homepage than some other things, that might or might not weight more or less. But those things should still be kept close to a maximum weight, only slightly under or over.

http://tinyurl.com/dgmoqp

(If it hangs, just press F5 maybe a couple times) I have uploaded the script here, so you will be able to see what I mean about the 3 issues described above.
If the 3 items weights more than 100 combined, the site just hangs and after 30 seconds gives a "FATAL ERROR"-warning.
There is no minimum weight, so the 3 items combined will often weight alot less than 100. Even as low as 50.
And the script is now completely random. There is no priority in the script anymore, so "gyn" is just as likely to show as any of the other.

I do indeed think it should be something as described in your code above, for the priority-part. Would I be able to just write something like this and insert it on line 42, after adding a ['weight'] to every item and modify the code fromline 30-40 to go after the ['weight']? :

But then there is still the fact that the script hangs when it gets 3 items that weight more than 100, and it has no minimum-value. But I am indeed getting closer now :-) Thanks
if($links) {

	for($i = -1; $i < count($links); $i++) {

		for($j = 0; $j < $links[$i][priority]; $j++) {

			$newlinksindex = count($newlinks) + 1;

			$newlinks[$newlinksindex] = $links[$i][link];

		}

	}

} 

Open in new window

0
 

Author Comment

by:MisterHamper
ID: 24013873
EDIT from above post: I have just tried updating my script with the ['weight'] and the code-snippet I wrote before. It doesn't seem to work. Everything is completely random now with no priority, and even the weight-part doesn't work anymore. There is no difference if the weight is 120 or if it is still under 100. Maybe it have been wrote it incorrectly?

(the link above is still for the old example, that is working somewhat, but has no priorities)
<?php

function dodosrandgen() {

$show_link = 3;

$separator = "<br />";
 
 

	$links[0]['link'] = "60 50 gyn";

	$links[0]['priority'] = 60;

        $links[0]['weight'] = 50;

	$links[1]['link'] = "30 20 hels";

	$links[1]['priority'] = 30;

	$links[1]['weight'] = 20;

	$links[2]['link'] = "15 50 mice";

	$links[2]['priority'] = 15;

	$links[2]['weight'] = 50;

	$links[3]['link'] = "18 30 part";

	$links[3]['priority'] = 18;

	$links[3]['weight'] = 30;

	$links[4]['link'] = "23 40 taby";

	$links[4]['priority'] = 23;

	$links[4]['weight'] = 40;

	$links[5]['link'] = "20 30 hessa";

	$links[5]['priority'] = 20;

	$links[5]['weight'] = 30;

	$links[6]['link'] = "24 20 boom";

	$links[6]['priority'] = 24;

	$links[6]['weight'] = 20;

	$links[7]['link'] = "35 30 watta";

	$links[7]['priority'] = 35;

	$links[7]['weight'] = 30;
 

 

  srand((float)microtime() * 1000000);

  shuffle($links);

  $maximum_weight = 100;

  $current_weight = 0;

 

  if($links) {

    for($i = -1; $i < count($links); $i++) {

      if (($current_weight+$links[$i]['weight'])<$maximum_weight) {

        for($j = 0; $j < $links[$i][weight]; $j++) {

          $newlinksindex = count($newlinks) + 1;

          $newlinks[$newlinksindex] = $links[$i][link];

        }

        $current_weight += $links[$i]['weight'];

      }

    }

  }
 
 

if($links) {

        for($i = -1; $i < count($links); $i++) {

                for($j = 0; $j < $links[$i][priority]; $j++) {

                        $newlinksindex = count($newlinks) + 1;

                        $newlinks[$newlinksindex] = $links[$i][link];

                }

        }

} 
 

$showarray[0] = "";

$showindex = 0;

	do {

		$randindex = rand(0, count($newlinks));

		if(!in_array($newlinks[$randindex], $showarray) && $newlinks[$randindex] != "") {

			$showarray[$showindex] = $newlinks[$randindex];

			$showindex++;

		}

	}while(count($showarray) <= $show_link);
 

	for($i = 0; $i < $show_link; $i++ ) {

		if($show_link == 1 || (($i + 1) == $show_link))

			print $showarray[$i];

		else

			print $showarray[$i].$separator;

	}

	

}

?>

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 24014880
I am having a little trouble following how you want the weights and priorities to control the order of output.  The tinyurl link above hung up and timed out (distended-stomach.com) so I have to assume that the answer is not to be had there.

When I have seen similar weighting schemes in the past, the sort of algorithm that is used involves multiplying a priority - usually a static value, by a weight - usually a dynamic external value.  The "owner" chooses the priority and the audience chooses the weight.  Other similar schemes involve voting, in which the audience gets 25% of the vote and the judges get 75% of the vote.

Can you possibly recast the question with an example and an explanation of how the priorities and weights should be used to determine the order of the output.  Once we can express that in English, it will be easy to express it in PHP!

Bet regards, ~Ray
0
 

Author Comment

by:MisterHamper
ID: 24016306
Okay, thanks, I will try to explain it in detail :) (The site above hangs up when the combined weight is above 100, just F5 a couple times and hope it gets below 100, thats a little bug :-) )

There has to be a minimum and maximum weight-limit. The script has to, (I think this is how it will work inside the computer) : take 1 item first with a look at the priorities (so everyone can be selected, but some is more likely to be selected than others) and then add that items weight to the current weight. Then that item should be removed from the random-pool. Then the script will take 1 more item with a look at everyones priorities and add that new items weights to the current weight. And then remove that weight from the list of the items that can be selected again. Then, if the total weight is between the minimum and maximum weight limit, the script should stop (even if there is only 2 items, and if it gets an item that exceeds the maximum limit it should reroll). If it gets 2 items that is still below the minimum limit, it will take another seemingly random item based on everyones priorities, and then add that weight to the current weight. Then it should display those 3 items, that have been selected and again, reroll if the script gets an item that makes the total weight exceed the maximum weight.

So in summary, what I want the script to do:
Minimum and maximum weight limit
Get random item (some have a higher priority to get selected than others)
Add that items weight to list and remove item from further selection
If that items weight is between minimum and maximum weight limit, stop the script and display output. If it is above maximum weight limit, reroll and get a new random item as item #1.
If total weight is below minimum weight level, get new random item (every item have different priorities)
Add that items weight to list and remove from further selection
Check if those 2 items combined weight is between minimum and maximum. If they are, stop the script and display the 2 items.
If the 2 items exceed the maximum weight, reroll second item.
If the 2 items are below minimum weight, get a new random item (so there is a total of 3).
If those 3 are between minimum and maximum weight, stop the script and display result. If it is still above or below minimum limit or maxmimum weightlimit, reroll 3rd item again and check if it is still above or below minimum or maximum weightlimit. If it is between, stop the script and display the 3 items.

I hope you guys understand now :D
I think that script I showed above might be bad from the ground-up actually :( I hope someone can give me some pointers.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 24018859
Before we go much farther, I've got to ask:  What is this being used for?  

Also, please let me ask this question again... can you give us a simple data set and an example of the expected output?  I'm still having trouble visualizing.  Are there any circumstances when you would have more than three items?  What algorithm do you want to use to select a "random" and "prioritized" element from a list (these are usually mutually exclusive properties)? Thanks, ~Ray
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:MisterHamper
ID: 24019827
It is for my friend and his family, he needs a diet for every day the next long time. He would benefit from having a diet that takes into account what he eats often (fx oatmeal and milk) while still keeping it somewhat random (so some days he could get bread and juice instead), so he doesn't eat the same thing every day. And the "weight" is the calories, so he doesn't exceed his daily needs or eat too little and starve himself.
It is that part of the script I am having trouble with, the backbone of it, because afterwards it will be alot easier to me to toy around with it and expand it to every meal of the day (that script will be the first meal only, a maximum of 3 foodtypes per meal) etc and alot other features I'm thinking of doing, and ofcourse adding all the foodtypes he needs. :) I hope you understand.

Yes I can try to give an expected output of it, just an example.
There is some things he eats often, so they should have a high priority of showing up. But so he doesn't just eat the same things every day, sometimes something else should pop up.
So there could be oatmeals fx, they have 60% of showing up in each of the 3 items spot. And then there is bread, which have a 40% chance of showing up. And juice with a 30% chance. And milk with a 20% chance and bananas with 20% chance.
So most of the time, it will be oatmeal and bread and juice that shows up, because each have the highest percentage of showing up. But sometimes it might be oatmeal and milk and bananas. And other times it might be bread and juice and milk.

If milk then shows up as first place, and (lets say it takes 2/3 of the maximum weight allowed), there won't be much items that will show up. If another item shows up, and that takes 1/2 of maximum allowed weight, those two won't be able to show up together, so the script will have to reroll and try to pick another random item. If that still is too much in combined maximum weight, it will have to reroll again. Lets say it gets milk and bananas (who takes 1/3 of allowed weight), those two will then be able to display together. Because they are taken as much weight as they can. But if it got milk and fx grapes (which take 1/5 of allowed weight) it would have to get a third random item. And if that item exceed or didn't come near the maximum allowed weight of all 3 items combined, it would have to reroll again. And if that came out perfectly, it would display the script.

The output would look like that link in my second post.
Just like this
"Oatmeal
Milk
Bananas"
fx

I hope you understand and can help me, else just ask again and I will gladly answer :-) My friend and I will appreciate it!
0
 

Author Comment

by:MisterHamper
ID: 24020050
"Also, please let me ask this question again... can you give us a simple data set and an example of the expected output?  I'm still having trouble visualizing.  Are there any circumstances when you would have more than three items?  What algorithm do you want to use to select a "random" and "prioritized" element from a list (these are usually mutually exclusive properties)? Thanks, ~Ray"

Oh I forgot this, I think.
There is no circumstances where there would be more than 3 items, but there could be some circumstances where there would be less than 3 (if it already is between the minimum and maximum allowed weight for the 1. or 2. item, it would stop there)
There is no random items per ce. It is all prioritized items, so every item could show up, but some is more likely to / will show up more often, than other.
There is detailed output 3 posts above. I think it is pretty detailed, but I can't know myself :)
0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 24024414
Here is how I would approach it.  Note that it is possible to get four items from this algorithm, and that can happen because of the stated weights of each food item.  IE: if the randomization produces these items:

    [boom] => 20
    [hels] => 20
    [watta] => 30
    [part] => 30

However most of the time it will generate two or three items.  If you want no more than three items, you can either change the weights so no combination of four items equals the max weight, or you can truncate the results in the $my_foods array.

Best regards, ~Ray

<?php // RAY_food.php

error_reporting(E_ALL);

echo "<pre>";
 
 

/* // DATA STRUCTURE FROM THE OP

$links[0]['link'] = "60 50 gyn";

$links[0]['priority'] = 60;

$links[0]['weight'] = 50;

$links[1]['link'] = "30 20 hels";

$links[1]['priority'] = 30;

$links[1]['weight'] = 20;

$links[2]['link'] = "15 50 mice";

$links[2]['priority'] = 15;

$links[2]['weight'] = 50;

$links[3]['link'] = "18 30 part";

$links[3]['priority'] = 18;

$links[3]['weight'] = 30;

$links[4]['link'] = "23 40 taby";

$links[4]['priority'] = 23;

$links[4]['weight'] = 40;

$links[5]['link'] = "20 30 hessa";

$links[5]['priority'] = 20;

$links[5]['weight'] = 30;

$links[6]['link'] = "24 20 boom";

$links[6]['priority'] = 24;

$links[6]['weight'] = 20;

$links[7]['link'] = "35 30 watta";

$links[7]['priority'] = 35;

$links[7]['weight'] = 30;

*/ // END OF DATA FROM THE OP
 
 

// NEW DATA STRUCTURE

$priority["gyn"]   = 60;   $weight["gyn"]   = 50;

$priority["hels"]  = 30;   $weight["hels"]  = 20;

$priority["mice"]  = 15;   $weight["mice"]  = 50;

$priority["part"]  = 18;   $weight["part"]  = 30;

$priority["taby"]  = 23;   $weight["taby"]  = 40;

$priority["boom"]  = 24;   $weight["boom"]  = 20;

$priority["watta"] = 35;   $weight["watta"] = 30;

$priority["hessa"] = 20;   $weight["hessa"] = 30;
 
 

// ASSIGN MAXIMUM TOTAL WEIGHT FOR ITEMS

$max_weight = 100;
 

// COMPUTE MINIMUM WEIGHT FOR THREE ITEMS - SIMULATE $min_weight = $weight[0] + $weight[1] + $weight[2];

$min_weight = 0;

asort($weight);

$kount = 3;

foreach ($weight as $food => $number)

{

   $kount--;

   $min_weight = $min_weight + $number;

   if (!$kount) break;

}
 

// FREQUENCY OF THE FOODS ITEMS BASED ON PRIORITY - A LARGE ARRAY

$foods = array();

foreach ($priority as $food => $number)

{

   while ($number > 0)

   {

      $number--;

      $foods[] = $food;

   }

}
 

// RANDOMIZE THE LARGE ARRAY

shuffle($foods);
 

// CHOOSE THE FOODS

$my_foods  = array();

$my_weight = 0;

foreach ($foods as $food)

{
 

// CHOOSE ONLY UNIQUE FOODS

   if (in_array($food, $my_foods)) continue;
 

// NOT MORE THAN MAX WEIGHT

   $my_weight = $my_weight + $weight["$food"];

   if ($my_weight > $max_weight) break;
 

// SELECT THIS FOOD

   $my_foods["$food"] = $food;

}
 

// ITEMIZE THE WEIGHTS OF THESE FOODS

foreach ($my_foods as $food => $x)

{

   $my_foods["$food"] = $weight["$food"];

}
 

// SHOW THE RESULTS

print_r($my_foods);

Open in new window

0
 

Author Comment

by:MisterHamper
ID: 24025899
Thank you thank you, thats amazing! Works perfectly and exactly as I imagined, with my added minimum-weight too!! I deleted that "DATA STRUCTURE FROM THE OP" and added "function randgen() {" to the top and } to the bottom.
But there is a thing I can't figure out, why it displays the results as
"
Array
(
    [watta] => 30
    [taby] => 40
)
"

Looks like it could be in line 93 in the script you posted, but tried changing it to a couple different things, and didn't result in what I wanted.
It would be best if it showed the results as
"watta
taby"

Thanks again
0
 

Author Comment

by:MisterHamper
ID: 24028317
I have toyed around with the script alot more
I can get it to show it as this though:
"[watta]
[taby]"
too, but I can't figure out how to get rid of the
"Array
(
)"
I can't figure out how to get rid of the [] between every item either though, if this isn't too hard I hope you can help me with it for the last help from you. :)
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 24028697
That's fairly easy to do.  Have a look at the code snippet...
// INSTEAD OF THIS

// SHOW THE RESULTS

print_r($my_foods);
 
 

// TRY THIS

// ECHO EACH FOOD ONE LINE AT A TIME

foreach ($my_foods as $my_food => $my_weight)

{

   echo "<br/>$my_food $my_weight \n";

}

Open in new window

0
 

Author Closing Comment

by:MisterHamper
ID: 31564013
Very nice!
0
 

Author Comment

by:MisterHamper
ID: 24028788
Thanks alot, my good sir! If i could give you 4000 points I would for sure!
Have a nice day :-)
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 24028859
Thanks for the points - it's a great question! ~Ray
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Preface In the first article: A Better Website Login System (http://www.experts-exchange.com/A_2902.html) I introduced the EE Collaborative Login System and its intended purpose. In this article I will discuss some of the design consideratio…
Introduction Since I wrote the original article about Handling Date and Time in PHP and MySQL (http://www.experts-exchange.com/articles/201/Handling-Date-and-Time-in-PHP-and-MySQL.html) several years ago, it seemed like now was a good time to updat…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:
The viewer will learn the benefit of using external CSS files and the relationship between class and ID selectors. Create your external css file by saving it as style.css then set up your style tags: (CODE) Reference the nav tag and set your prop…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now