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)
Related
I have a a list of data that has a value attached to it that constantly gets doubled as it goes up:
0 = value 0
1 = value 1
2 = value 2
4 = value 3
8 = value 4
16 = value 5
32 = value 6
64 = value 7
128 = value 8
256 = value 9
512 = value 10
I have also been given the number x
say x = 76.
Visually, I can see that value 7 (64), value 4 (8), and value 3 (4) all sum up to 76.
What I need to be able to do, is take x, run it through a function, and return an array of the values.
I've tried looping through all the numbers in reverse and taking off what value has been used, but i got confused with lots of if statements.
Is there a built in PHP function to do this? Or am I looking at it the wrong way?
Thanks
May be you are looking for this-
function getArray($x){
$ar = array();
for($i = 0 ; $i < 16; $i++){
if( ($x&(1<<$i)) != 0 ){
array_push($ar, (1<<$i));
// if you need positions; you should use it instead of above line
//array_push($ar, ($i+1));
}
}
return $ar;
}
print_r( getArray(76) );
Output:
Array (
[0] => 4
[1] => 8
[2] => 64
)
The alternate output will be (if you use array_push($ar, ($i+1));)-
Array
(
[0] => 3
[1] => 4
[2] => 7
)
Explanation:
In binary 76 presents 00000000 01001100 in 16 bit. I ran a loop from Least Significant Bit (LSB) to Most Significant Bit (MSB) (0-16). In each loop, I'm generating a new number which contains only i'th bit as 1 and rest of the bits are 0. To generate it I used shifting operator (1 << i) which is actually 2^i. Now I did a bit wise AND operation between x and the new number. If this operation returns any nonzero number that means i'th bit of x is 1 and I'm pushing that position/value inside the array. Finally I'm returning that arry.
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
What I need is to create five random integer (say rand(1,5)). Then, I generate a score based on these numbers. For instance, if I get a result of 1,2,3,4,5 then that would equal a zero score, but if I got 1,1,3,4,5 that would be 1 as we have a pair. Similar to a poker kind of scoring, so five of the same number would be a "full house" thus resulting in the highest score.
How would I go about the scoring system, even if it is just the mathematical equation?
More detail:
1-5 will hold separate images and then will be fought against "The House" which will have identical code to the user to determine the winner. Here's some example draws and the score they would receive:
1,2,3,4,5 = score 0
1,1,2,3,4 = score 1 (1 pair)
1,1,2,2,4 = score 2 (2 pair)
1,1,1,3,4 = score 3 (3 of a kind)
1,1,1,1,5 = score 4 (4 of a kind)
1,1,1,3,3 = score 5 (full house)
1,1,1,1,1 = score 6 (5 of a kind)
The combination of numbers is irreverent if they score 6 and the house scores 6, it's a tie.
if (isset($_POST['play'])) {
$rand1 = rand(1, 5);
$rand2 = rand(1, 5);
$rand3 = rand(1, 5);
$rand4 = rand(1, 5);
$rand5 = rand(1, 5);
if ($_POST['bet'] <= $user_data['coins']) {
if ($_POST['bet'] < 999999999) {
if ($_POST['bet'] > 0.99) {
if ($user_data['coins'] >= 1) {
$array = array($rand1,$rand2,$rand3,$rand4,$rand5);
print_r(array_count_values($array));
echo $rand1.', '.$rand2.', '.$rand3.', '.$rand4.', '.$rand5;
Array( // Here I don't understand
1 => 3,//
2 => 1,//
3 => 1 //
);
}
}
}
}
}
This outputs ; Array ( [5] => 2 [4] => 2 [1] => 1 ) 5, 5, 4, 4, 1
Use array_count_value function for this.
$array = array(1,1,1,2,5);
print_r(array_count_values($array));
Array(
1 => 3,
2 => 1,
3 => 1
);
Here's the approach I would consider, building on #Lele's answer. Warning: this is a bit confusing, so sit down with a cup of tea for this one.
Build a set of five buckets, [1] to [5], and scan a player's numbers, so that the count for each number is stored in the corresponding bucket
Then count the numbers you are left with into a new bucket system, with each position representing the number of counts you have for something.
So, if your score is this:
1 1 2 2 4
Then your first buckets are:
2 2 0 1 0
That's because you have two ones, two twos, and one four. And your second buckets are:
1 2 0 0 0
That's because you have two two-counts, and one one-count. Here, you disregard the first position (since a one-count for something does not score anything) and score for the others. So, test for two twos, and score that two.
If you score is this:
5 5 5 5 1
Then your first buckets are:
1 0 0 0 4
That's one one and four fives. So your second buckets are:
1 0 0 1 0
Your lookup table for this could be:
x 1 0 0 0 -> one pair
x 2 0 0 0 -> two pairs
x 0 1 0 0 -> three of a kind
x 1 1 0 0 -> full house
x 0 0 1 0 -> four of a kind
x 0 0 0 1 -> five of a kind
The 'x' means that you don't match on this. So, your lookup table matches four numbers to a score.
I was rather interested in this problem, so I have written some code to do the above. You'll still need to do the lookup table, but that is relatively trivial, and will be good practice for you. Here is a demo, with comments (run code here):
<?php
function counting(array $array) {
// Input figures
print_r($array);
// Run the figures twice through the bucket-counter
$firstBuckets = bucketCounter($array);
$secondBuckets = bucketCounter($firstBuckets);
// Ignore counts of 1
array_shift($secondBuckets);
// Output, just need to do the lookup now
echo ' converts to ';
print_r($secondBuckets);
echo "<br />";
}
/**
* Bucket counter
*/
function bucketCounter(array $array) {
$result = array(0, 0, 0, 0, 0, );
foreach($array as $value) {
if ($value > 0) {
$result[$value - 1]++;
}
}
return $result;
}
// Try some demos here!
counting(array(1, 2, 3, 4, 5));
counting(array(1, 1, 2, 4, 2));
counting(array(1, 1, 1, 1, 1));
?>
The demos I've included seem to work, but do hunt for bugs!
If the range is quite small, you can use counting sort approach. For each number, provide a "bucket" to count how many times a number appear. Scan once to fill in the buckets. Then another scan, but this time against the bucket to get the highest value. That's your score.
Given an array of any size (from 1 to 4 rounds) with ranks numbering from 1 to 8 (or more), how can I take that array and sort it bracket style, so rank 1 is first, rank 2 is last, then rank 8 is next, then rank 7 is second to last... like
Then the next round ..
1, 4, 3, 2
I am trying to sort tournament brackets but not having much luck when it comes to sorting the ranking, and also in a way that scales well so the display does not break.
Edit:
Some clarification, each bracket size needs to break down like so:
If the bracket has 8 games, the game numbers are 1 through 8, so that round needs to arrange itself like:
Game 1
Game 8
Game 5
Game 4
Game 6
Game 3
Game 7
Game 2
So then, on the next round, it has 4 games, which would come out as:
Game 1
Game 4
Game 3
Game 2
And so on:
Game 1
Game 2
Finally,
Game 1
It also needs to work if the starting bracket had 16 games instead of 8, or 32, or more. The idea is that the winner of Game 1 and Game 8 play each other in Game 1 on the next round. The first game and second game are always the first and last on each bracket. Then it works it's way inward.
This isn't sorting the list. Unless you really need to sort the list, indices may be faster and more efficient.
The match ups will be set up like (current_rank), (total ranks) - (current_rank) + 1
Since there are 8 ranks,
1, 8 -1 +1 = 8
2, 8 -2 +1 = 7
3, 8 -3 +1 = 6
4, 8 -4 +1 = 5
So the code would look something like
<?php
$rankscount = count($ranks);
for ($i = 1; $i <= $rankscount / 2; $i++) {
echo "matchup will be: rank " . $i . " , rank " . $rankscount - $i + 1;
}
?>
After each round, reseed the function with the new sorted list, and you'll get 1vs4. 2vs3.
I'm not a professional at PHP, but hopefully this helps.
The following function sorts an array of ['r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8'] into an order of ['r1', 'r8', 'r2', 'r7', 'r3', 'r6', 'r4', 'r5'].
An array of ['r1', 'r2', 'r3', 'r4'] will be rearranged into ['r1', 'r4', 'r2', 'r3']
function rearranged($array) {
sort($array);
$result = array();
$length = count($array);
$offset = 0;
// Handling two elements at once, therefore just do $lenght/2 iterations
for ($i = 0; $i < $length/2; $i++) {
// $i + $offset: The current element in the original array
// + the offset of fields already filled in the results array
$result[$i + $offset] = $array[$i];
// $i + 1 + $offset: The next element in the results array
$result[$i + 1 + $offset] = $array[$length - $i -1];
// Increment offset
$offset++;
}
return $result;
}
I am not using any inbuilt sort function since they compare all keys to each others, assuming that your array already is in order just iterating and swapping positions should be much faster. If the keys are not ordered you can call a inbuilt sort function such as sort(sorts by value) or ksort (sorts by key).
To note is as well, that this function only works properly for arrays with an even amount of elements. If the number of elements is uneven the last element will be dropped from the results array.
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
) ;