How to divide items equally in 4 boxes? [closed] - php

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Suppose i have 7 bags with different weight. Actually a php array contains this data.
Bag A 60 Kg
Bag B 80 Kg
Bag C 20 Kg
Bag D 10 Kg
Bag E 80 Kg
Bag F 100 Kg
Bag G 90 Kg
In php it will look like this
Array
(
[30] => 60
[31] => 120
[32] => 120
[33] => 60
[35] => 180
)
Now i have to divide all 7 bags in 4 container equally by balancing there weight.
But i cannot break the bag to manage weight. How to do this please suggest me. How can i build a formula or php function which will distribute all bags balancing there weight.
There is no limitation in container capacity. And its also not necessary to have all containers weight equal after distribution. I just need a load balancing.
Thanks in advance.

Calculate the sum of the weight of your bags then divide it by the number of containers. Then use a bin packaging algorithm to distribute the bags to the individual containers. E.g. take one bag at a time from your array and put it in the first container where the weight of the container plus the weight of your bag is less than the maximally possible container weight.
http://en.wikipedia.org/wiki/Bin_packing_problem
Update:
example written in Ruby. Should be not to hard to rewrite it in PHP. It distributes the bags to the containers relatively evenly (There might be a solution that is more accurate).
# A list of bags with different weights
list_of_bags = [11, 41, 31, 15, 15, 66, 67, 34, 20, 42, 22, 25]
# total weight of all bags
weight_of_bags = list_of_bags.inject(0) {|sum, i| sum + i}
# how many containers do we have at our disposal?
number_of_containers = 4
# How much should one container weight?
weight_per_container = weight_of_bags / number_of_containers
# We make an array containing an empty array for each container
containers = Array.new(number_of_containers){ |i| [] }
# For each bag
list_of_bags.each do |bag|
# we try to find the first container
containers.each do |container|
# where the weight of the container plus the weigth of the bag is
# less than the maximum allowed (weight_per_container)
if container.inject(0) {|sum, i| sum + i} + bag < weight_per_container
# if the current container has space for it we add the bag
# and go to the next one
container.push(bag)
break
end
end
end
# output all containers with the number of items and total weight
containers.each_with_index do |container, index|
puts "container #{index} has #{container.length} items and weigths: #{container.inject(0) {|sum, i| sum + i}}"
end
example result:
container 0 has 3 items and weigths: 83
container 1 has 3 items and weigths: 96
container 2 has 2 items and weigths: 87
container 3 has 2 items and weigths: 76

Create a function that gets a product weight and returns a bag number - the one which has the least free space that's still enough to fit. Put it in the bag. Repeat until done.
$bags = array(60,80,20,10,80,100,90);
$containers = array(1=>100,2=>100,3=>100,4=>100); // number -> free space
$placement = array();
rsort($bags); // biggest first - usually it's better
function bestContainerFor($weight) {
global $containers;
$rest = 0;
$out = 0; // in it won't change $weight fits nowhere
foreach($containers as $nr=>$space) {
if($space<$weight) continue; // not enough space
if($space-$weight<$rest) continue; // we have a better case
$rest = $space-$weight;
$out = $nr;
}
if($out) $containers[$out]-=$weight; // occupy the space
return $out;
}
foreach($bags as $nr=>$w) {
$p = bestContainerFor($w);
$placement[$nr] = $p; // for later use; in this example it's not needed
if( $p) print "Bag $nr fits in $p<br>";
if(!$p) print "Bag $nr fits nowhere<br>";
}
It's not tested. If you give me some details of your code I'll try to adapt. This just shows the principle of it.
Note that
it works with variable container sizes,
it gives you the placement of each bag, not the sum weight,
it's not optimal for equal distribution, just gives a good case

Related

Calculation of ever rising value [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I will like to be able to make a calculation in php using a number of experience points (XP) as base to return a level value. I want it to be increasingly more difficult for each level to rise. Like this:
0-49 XP = Level 1
50-104 XP = Level 2
105-164 XP = Level 3
165-229 XP = Level 4 etc.
To reach level 2 50 XP is needed. To reach level 3 a further 55 XP is needed. To reach level 4 a further 60 XP is needed and so forth.
Even more I would like to be able to display the amount of XP needed to reach the next threshold.
I have no idea what to search for to solve my challenge. I hope you can help.
Thank you in advance.
Your point structure does not match up with your sentence.
So I'll answer:
To reach level 2 50 XP is needed. To reach level 3 a further 55 XP is
needed. To reach level 4 a further 60 XP is needed and so forth.
<?php
$get_level = function () {
foreach (range(0, 300, 50) as $difficulty => $base) {
yield [$base + ($difficulty * 5) => 'Level '.($base / 50)];
}
};
foreach ($get_level() as $base => $level) {
echo print_r($level, true);
}
Result:
Array
(
[0] => Level 0
)
Array
(
[55] => Level 1
)
Array
(
[110] => Level 2
)
Array
(
[165] => Level 3
)
Array
(
[220] => Level 4
)
Array
(
[275] => Level 5
)
Array
(
[330] => Level 6
)
The Math for the XP calculation is pretty simple:
XP = ∑50+5*(level-1)
= 5*∑10+(level-1)
= 5*∑9+level
= 5*(∑9 + ∑level)
= 5*(9*level + ∑level)
The sum over the natural numbers can be looked up in every math book or even Wikipedia.
In Python (as I don't know PHP very well:( ):
levelBoundaries = []
for i in range(number_of_levels_you_want): ## Loop through for all levels
level = len(levelBoundaries) + 1 ## Get the Level Number
levelArr = [] ## Create the list for the level boundary
## The formula for your list is 2.5n^2 + 42.5n - 45
## The level boundary for level n is [Term n, (Term (n+1)) - 1]
## This is what has been done below
levelArr.append((2.5 * (level ** 2)) + (42.5 * level) - 45)
level += 1
levelArr.append( (2.5 * (level ** 2)) + (42.5 * level) - 45 - 1)
levelBoundaries.append(levelArr)

PHP Random value in array ponderated [duplicate]

This question already has an answer here:
Generate a random number with bias result in PHP
(1 answer)
Closed 5 years ago.
I have the following script:
$domain = ['gmail.com', 'yahoo.com', 'hotmail.com'];
$domain = $domain[mt_rand(0, count($domain) - 1)];
It is possible to set a percentual value for each item coresponding to chances of being chosen.
For example, i want to have 75% chances to have a $domain='gmail.com';.
There are many ways to achieve the desired result.
My method doesn't demand that the total "chances" be 100; you can make your own decision on the value of the highest key.
The basis of my method is that the result ($domain) will be the array value with the lowest key that is not greater than the randomized number ($pick).
Here is an example to give gmail a 75% chance, and give yahoo & hotmail equal chances with the remaining 25%.
*Notice that mt_rand() starts at 1 versus 0 as commented under the question.
$domain_perc=array(
750=>'gmail.com', // between 1 & 750 = 75% chance
875=>'yahoo.com', // between 751 & 875 = 12.5% chance
1000=>'hotmail.com' // between 876 & 1000 = 12.5% chance
);
$pick=mt_rand(1,max(array_keys($domain_perc)));
foreach($domain_perc as $p=>$v){
if($pick<=$p){
$domain=$v;
break;
}
}
Or you can replace the foreach() code block with this one-liner:
$domain=current(array_filter($domain_perc,function($v,$k)use($pick){return $pick<=$k;},ARRAY_FILTER_USE_BOTH));
As for customizing the input array, a simple way of expressing a 50%-25%-25% split would be:
$domain_perc=array(
2=>'gmail.com', // 1 and 2 of 4 = 50% chance
3=>'yahoo.com', // 3 of 4 = 25% chance
4=>'hotmail.com' // 4 of 4 = 25% chance
);
To set up a two-value array with a ~33% -vs- ~66% split:
$domain_perc=array(
1=>'gmail.com', // 1 of 3 = ~33% chance
3=>'yahoo.com' // 2 & 3 of 3 = ~66% chance
);

Generate random numbers with weighted probabilites [duplicate]

This question already has answers here:
Generating random results by weight in PHP?
(13 answers)
Closed 9 years ago.
I want to select a number randomly, but based on probability from a group of numbers; for example (2-6).
I'd like the following distribution:
6's probability should be 10%
5's probability should be 40%
4's probability should be 35%
3's probability should be 5%
2's probability should be 5%
This is very easy to do.
Watch for the comments in the code below.
$priorities = array(
6=> 10,
5=> 40,
4=> 35,
3=> 5,
2=> 5
);
# you put each of the values N times, based on N being the probability
# each occurrence of the number in the array is a chance it will get picked up
# same is with lotteries
$numbers = array();
foreach($priorities as $k=>$v){
for($i=0; $i<$v; $i++)
$numbers[] = $k;
}
# then you just pick a random value from the array
# the more occurrences, the more chances, and the occurrences are based on "priority"
$entry = $numbers[array_rand($numbers)];
echo "x: ".$entry;
Create a number between 1 and 100.
If it's <= 10 -> 6
Else if it's <= 10+40 -> 5
Else if it's <= 10+40+35 -> 4
And so on...
Note: your probabilities don't add up to 100%.
The best you can do is generate a number between 0 and 100, and see in what range the number is:
$num=rand(0,100);
if ($num<10+40+35+5+5)
$result=2;
if ($num<10+40+35+5)
$result=3;
if ($num<10+40+35)
$result=4;
if ($num<10+40)
$result=5;
if ($num<10)
$result=6;
Be careful, your total probability isn't equal to 1, so sometimes $result is undefined
See #grigore-turbodisel 's answer if you want something that you can configure easily.

Best Approach to Getting Adjustment from Raw Number

I would like advice on the best/most efficient way to get an adjusted score for a team based on a raw score. Let me explain.
The teams are contract bridge teams and the raw score for the winner is from 0 (tie) to any number, but greater than 100 would be rare. The raw score is called IMPS and the adjusted score is called VPs, but that is just for clarity.
The adjustment table is:
IMPs VPs
1 thru 2 16 to 14
3 thru 4 17 to 13
5 thru 7 18 to 12
8 thru 11 19 to 11
12 thru 15 20 to 10
16 thru 20 21 to 9
21 thru 26 22 to 8
27 thru 33 23 to 7
34 thru 41 24 to 6
42 thru 50 25 to 5
51 thru 60 26 to 4
61 thru 71 27 to 3
72 thru 83 8 to 2
84 thru 95 29 to 1
96+ 30 to 0
Here is my code. It works fine:
PHP
$teamArawScore = 20; //Actual result will come from form input
if ($teamArawScore >95 )
{
$teamAadjScore = 30;
$teamBadjScore = 0;
}
else
{
$adjustmentArray = array
(15,
16,16,
17,17,
18,18,18,
19,19,19,19,
20,20,20,20,
21,21,21,21,21,
22,22,22,22,22,22,
23,23,23,23,23,23,23,
24,24,24,24,24,24,24,24,
25,25,25,25,25,25,25,25,25,
26,26,26,26,26,26,26,26,26,26,
27,27,27,27,27,27,27,27,27,27,27,
28,28,29,29,28,28,28,28,28,28,28,28,
29,29,29,29,29,29,29,29,29,29,29,29);
$teamAadjScore = $adjustmentArray[$teamArawScore];
$teamBadjScore = 30 - $teamAadjScore;
}
echo "TeamA won by $teamArawScore so it won $teamAadjScore VPs and TeamB won $teamBadjScore VPs.";
My approach just seems inefficient. Since the array is small, I doubt there is any performance issues, but I would like to do the conversion as efficiently as possible.
What do you suggest?
Since there's no consistency in the table you described you will always be populating a lookup array containing the actual logic. You could also structure this differently, with a shorter array containing the sequential amount of points leading to a given score etc., but in the end those would all result in having to loop over the array to see where you end up - swapping memory for CPU cycles.
Effectively, you need a lookup table anyway because there appears to be no algorithm that can reliably map the contents of the lookup table, and your implementation is now O(1) in big-O notation. As such it can by definition not be made more efficient.
For reference on lookup tables (emphasis added in quote):
In computer science, a lookup table is an array that replaces runtime
computation with a simpler array indexing operation. The savings in
terms of processing time can be significant, since retrieving a value
from memory is often faster than undergoing an 'expensive' computation
or input/output operation. The tables may be precalculated and
stored in static program storage, calculated (or "pre-fetched") as
part of a program's initialization phase (memoization), or even stored
in hardware in application-specific platforms.
There's nothing 'bad practice' about using them. Back in the days when CPUs didn't have floating point units on board we'd have entire sine and sqrt tables embedded in programs to circumvent computationally expensive calculations at runtime.
I got a little something for you.Even though I'm not sure it would actualy optimize the execution speed.
Looping through an array, knowing the base value being 16 if we have a positive score (higher than one) from the A team.
This is not optimized at all (mainly because of the $a == 0 condition), but here it is:
<?php
$teamArawScore = 30;
$a = $teamArawScore;
$teamAfinalScore = 16;
$scoreArray = array(3,5,8,12,16,21,27,34,42,51,61,72,84,10000000000);
$count = 0;
foreach($scoreArray as $elem)
{
if($a < $elem)
{
$teamAfinalScore += $count;
break;
}
$count++;
}
if($a ==0)
{
$teamAfinalScore = 15;
$teamBfinalScore = 30 - $teamAfinalScore;
}
echo "Team A: ".$teamAfinalScore. "<br />Team B:".$teamBfinalScore;
?>
<?php
$teamArawScore = 1000; //Actual result will come from form input
if ($teamArawScore >95 )
{
$teamAadjScore = 30;
$teamBadjScore = 0;
}
else
{
$adjustmentArray = array('1'=>16,'3'=>17,'5'=>18,'8'=>19,'12'=>20,'16'=>21,'21'=>22,'27'=>23,'34'=>24,'42'=>50,'51'=>60,'61'=>27,'72'=>83,'84'=>95);
$base_score=array(1,3,5,8,12,16,21,27,34,42,51,61,72,84);
$count=count($base_score);
$adjustment_value=$adjustmentArray['1'];
for($i=1; $i<$count-1; $i++){
if($teamArawScore < $base_score[$i+1]){
$adjustment_value=$adjustmentArray[$base_score[$i]];
break;
}
else{
$adjustment_value=$adjustmentArray[$base_score[$i]]; // for values greater than 84
}
}
$teamAadjScore = $adjustment_value;
$teamBadjScore = 30 - $teamAadjScore;
}
echo "TeamA won by $teamArawScore so it won $teamAadjScore VPs and TeamB won $teamBadjScore VPs." ;

php game, formula to calculate a level based on exp

Im making a browser based PHP game and in my database for the players it has a record of that players total EXP or experience.
What i need is a formula to translate that exp into a level or rank, out of 100.
So they start off at level 1, and when they hit say, 50 exp, go to level 2, then when they hit maybe 125/150, level 2.
Basically a formula that steadily makes each level longer (more exp)
Can anyone help? I'm not very good at maths :P
Many formulas may suit your needs, depending on how fast you want the required exp to go up.
In fact, you really should make this configurable (or at least easily changed in one central location), so that you can balance the game later. In most games these (and other) formulas are determined only after playtesting and trying out several options.
Here's one formula: First level-up happens at 50 exp; second at 150exp; third at 300 exp; fourth at 500 exp; etc. In other words, first you have to gather 50 exp, then 100 exp, then 150exp, etc. It's an Arithmetic Progression.
For levelup X then you need 25*X*(1+X) exp.
Added: To get it the other way round you just use basic math. Like this:
y=25*X*(1+X)
0=25*X*X+25*X-y
That's a standard Quadratic equation, and you can solve for X with:
X = (-25±sqrt(625+100y))/50
Now, since we want both X and Y to be greater than 0, we can drop one of the answers and are left with:
X = (sqrt(625+100y)-25)/50
So, for example, if we have 300 exp, we see that:
(sqrt(625+100*300)-25)/50 = (sqrt(30625)-25)/50 = (175-25)/50 = 150/50 = 3
Now, this is the 3rd levelup, so that means level 4.
If you wanted the following:
Level 1 # 0 points
Level 2 # 50 points
Level 3 # 150 points
Level 4 # 300 points
Level 5 # 500 points etc.
An equation relating experience (X) with level (L) is:
X = 25 * L * L - 25 * L
To calculate the level for a given experience use the quadratic equation to get:
L = (25 + sqrt(25 * 25 - 4 * 25 * (-X) ))/ (2 * 25)
This simplifies to:
L = (25 + sqrt(625 + 100 * X)) / 50
Then round down using the floor function to get your final formula:
L = floor(25 + sqrt(625 + 100 * X)) / 50
Where L is the level, and X is the experience points
It really depends on how you want the exp to scale for each level.
Let's say
LvL1 : 50 Xp
Lvl2: LvL1*2=100Xp
LvL3: LvL2*2=200Xp
Lvl4: LvL3*2=400Xp
This means you have a geometric progression
The Xp required to complete level n would be
`XPn=base*Q^(n-1)`
In my example base is the inital 50 xp and Q is 2 (ratio).
Provided a player starts at lvl1 with no xp:
when he dings lvl2 he would have 50 total Xp
at lvl3 150xp
at lvl4 350xp
and so forth
The total xp a player has when he gets a new level up would be:
base*(Q^n-1)/(Q-1)
In your case you already know how much xp the player has. For a ratio of 2 the formula gets simpler:
base * (2^n-1)=total xp at level n
to find out the level for a given xp amount all you need to do is apply a simple formula
$playerLevel=floor(log($playerXp/50+1,2));
But with a geometric progression it will get harder and harder and harder for players to level.
To display the XP required for next level you can just calculate total XP for next level.
$totalXpNextLevel=50*(pow(2,$playerLevel+1)-1);
$reqXp=$totalXpNextLevel - $playerXp;
Check start of the post:
to get from lvl1 -> lvl2 you need 50 xp
lvl2 ->lvl3 100xp
to get from lvl x to lvl(x+1)
you would need
$totalXprequired=50*pow(2,$playerLevel-1);
Google gave me this:
function experience($L) {
$a=0;
for($x=1; $x<$L; $x++) {
$a += floor($x+300*pow(2, ($x/7)));
}
return floor($a/4);
}
for($L=1;$L<100;$L++) {
echo 'Level '.$L.': '.experience($L).'<br />';
}
It is supposed the be the formula that RuneScape uses, you might me able to modify it to your needs.
Example output:
Level 1: 0
Level 2: 55
Level 3: 116
Level 4: 184
Level 5: 259
Level 6: 343
Level 7: 435
Level 8: 536
Level 9: 649
Level 10: 773
Here is a fast solution I used for a similar problem. You will likely wanna change the math of course, but it will give you the level from a summed xp.
$n = -1;
$L = 0;
while($n < $xp){
$n += pow(($L+1),3)+30*pow(($L+1),2)+30*($L+1)-50;
$L++;
}
echo("Current XP: " .$xp);
echo("Current Level: ".$L);
echo("Next Level: " .$n);
I take it what you're looking for is the amount of experience to decide what level they are on? Such as:
Level 1: 50exp
Level 2: 100exp
Level 3: 150exp ?
if that's the case you could use a loop something like:
$currentExp = x;
$currentLevel;
$i; // initialLevel
for($i=1; $i < 100; $i *= 3)
{
if( ($i*50 > $currentExp) && ($i < ($i+1)*$currentExp)){
$currentLevel = $i/3;
break;
}
}
This is as simple as I can make an algorithm for levels, I haven't tested it so there could be errors.
Let me know if you do use this, cool to think an algorithm I wrote could be in a game!
The original was based upon a base of 50, thus the 25 scattered across the equation.
This is the answer as a real equation. Just supply your multiplier (base) and your in business.
$_level = floor( floor( ($_multipliter/2)
+ sqrt( ($_multipliter^2) + ( ($_multipliter*2) * $_score) )
)
/ $_multipliter
) ;

Categories