PHP scale number up/down based on input? - php

Using the length of a string, I want to scale the font size up/down based on that.
So, lower string length, higher number. Higher string length, lower number.
But I don't want to do dozens upon dozens of if/else or a switch statement. Ideally I'd programmatically scale the output based on the input.
Something like...
text_length = strlen($full_text)
size_range = range(0, 5)
// if text_length = 1 then 100% of size_range
// if text_length = 280 then 0% of size_range
In this case, the maximum text length is 280 (they're tweets).

If the plot of y = 1/-279x + 280/279 reflects what you want.
I did the following script in Ruby that should be easy to translate to PHP:
require "bundler/inline"
gemfile do
gem "rspec"
end
require "rspec/autorun"
MAX_SIZE_PERCENTAGE = 1.0
def size_it(text_length, maximum_length)
alpha = - MAX_SIZE_PERCENTAGE / (maximum_length - MAX_SIZE_PERCENTAGE)
beta = maximum_length / (maximum_length - MAX_SIZE_PERCENTAGE)
((alpha * text_length) + beta).round(2)
end
RSpec.describe "dynamic size calculation" do
it "100% when minimal size" do
text_length = 1
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(1)
end
it "75% when almost too short" do
text_length = 70
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.75)
end
it "50% when half point" do
text_length = 140
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.5)
end
it "25% when almost too long" do
text_length = 210
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0.25)
end
it "0% when maximum size" do
text_length = 280
maximum_size = 280
expect(size_it(text_length, maximum_size)).to eq(0)
end
end
The math is intuitive, a few landmines:
integer division, e.g 1/280 resulting in 0 instead of 0.0003, I prevented this by calling .to_f, Ruby way to cast to float.
rounding errors, expecting 0.25 and getting 0.2503213, I adjusted this by calling round(2), Ruby way to round to nearest decimal point.

Related

Calculating the percentage of a slider

Say i have a slider with the Minimum value of -1, and the maximum value of 1. If the user puts the slider handle in the middle, then we would have a value of 0. I just don't know how to calculate that into the 50% of -1 to 1
I then need to do the same thing i reverse, first get the percentage of the slider (say it's 50%). I now need to calculate how much 50% is of -255 to 255 (which should return 0). I've been stuck with this one for a while now, and would appreciate any help i could get.
Thanks in advance!
Well you have two scales, one going from 0 to 100, the other going from -255 to 255. The formula to go from one to the other is quite simple :
progress = (position - min)/range
new_pos = new_min + new_range * progress
Note that a percentage already represents this "progress" value, as 20% = (20 - 0)/100. Also note that the range can be defined as max - min.
So assuming you go from -255 to 255 included, that's 511 discrete values (counting the 0, assuming you use int's), and assuming percentage is a value between 0 and 100 (as opposed to between 0 and 1) :
from percentage to pixels : -255 + 511 * percentage / 100
from pixels to percentage : 0 + 100 * (pixel + 255) / 511
The same goes for your scale from -1 to 1, which I guess uses continuous values, thus has a range the size of the interval [-1, 1], i.e. min = -1 and range = 2
This should do the trick:
function percentage($slider){
return ($slider + 1) * 50;
}
function slider($percentage){
return ($percentage/100) * 510 - 255;
}

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
) ;

How to find the % of a value on a Y axis of a LOG graph?

Wow, this one is though!
I'm trying to find in PHP the % of a value relative to the Y axis. If we refer to this graph : http://en.wikipedia.org/wiki/Semi-log_graph (2009 outbreak of influenza A), let's say that I want to find what % is a value "256" on the chart.
Visually, it's easy : it's a bit more than a 1/3 or 33%. If we look at the 1024 value, it's around 50% of the height of the Y axis. 131072 would be 100%.
So how do I calculate this with PHP?
Let's take this graph and take X = day 0 and Y = 256. What is 256 as a % of Y ?
Thanks a lot to anyone can compute this baby :)
percent = 100 * ( log(y) - log(y1) ) / ( log(y2) - log(y1) )
where
y = value
y1 = smallest value in y-axis
y2 = largest value in y-axis.
when y1 = 1.0 then you can simplify the other answers given here (since log(1)=0 by definition)
percent = 100 * log(y)/log(y2)
Note that not all log charts have 1.0 as the lowest value.
ln(131072) = 11.783 is 100%
ln(1024) = 6.931 is 58.824%
in PHP, that function is called log()
no need to set the base, as you are dividing them to find the relative value.
Alex got it, but to generalize for you and PHPize
logPercent = log(x) / log(top) * 100;
If you take the log of your max y value (131072 in your case) and the log of your y value (256), you end up with a height and a y value which is linear in relation to your drawn axis. you can divide them to get a decimal of the height and times by 100 for %:
using log base 2 seen as it gives integers (though any base should be fine).
log(256) / log(131072) = 8/17 = 0.47 = 47%
in php:
(log(256, 2) / log(131072, 2))*100;

Adding number should depend on current value

I want to add a number to a var. This number should be bigger when var is small and smaller when var is big. I have calculate the optimum values: when var=1, function should add 125. When var=50 function should add 420. I was thinking about sin function, but I have no idea how to "personalize" this function to work with it. (I am using php)
For a function with the form:
f[x_] := x + Sin[y*x + z]
Subject to the constraints
f[1] == 1 + 125 && f[50] == 50 + 420
You have
{{y -> 1/49 (-ArcSin[125] + ArcSin[420]),
z -> 1/49 (50 ArcSin[125] - ArcSin[420])}}
which is approximately
{{y -> 0. - 0.0247338 I, z -> 1.5708 - 5.49671 I}}
Between 0 and 70, this gives:
An approximate function, using only real values, is:
f(x) = x + 121.94629730754633 cosh(0.02473378688005212 x) +
121.94219707312345 sinh(0.02473378688005212 x)
The sine function is periodic and probably not suitable for the task.
Your example is not clear: you say add 'bigger number when var is small and smaller number when var is bigger', but add 125 to 1 and 420 to 50, which contradicts the text.
One possibility is the reciprocal function - it meets your stated requirements but not your example requirements.
Given just 2 data points, we can deduce a linear relationship:
y = 125 + (420 - 125) / (50 - 1) * (x - 1)
which is approximately:
y = 119 + 6x
Check:
x = 1; y = 125
x = 50; y = 419
The approximate factor 6 is a rounding of 6.0204081632 ... which is an intriguing sequence in the fractional part.
Try to make a linear equation projection.
VarAdd = Var*Slop+Start; eq [1]
125=1*Slop+Start ---1
420=50*Slop+Start –2
Solve Slop and Start then apply eq[1] any time.

Generate random player strengths in a pyramid structure (PHP)

For an online game (MMORPG) I want to create characters (players) with random strength values. The stronger the characters are, the less should exist of this sort.
Example:
12,000 strength 1 players
10,500 strength 2 players
8,500 strength 3 players
6,000 strength 4 players
3,000 strength 5 players
Actually, I need floating, progressive strength values from 1.1 to 9.9 but for this example it was easier to explain it with integer strengths.
Do you have an idea how I could code this in PHP? Of course, I would need mt_rand() to generate random numbers. But how can I achieve this pyramid structure?
What function is it? Root function, exponential function, power function or logarithm function?
Thanks in advance!
It should look like this in a graph:
Pyramid graph http://img7.imageshack.us/img7/107/pyramidy.jpg
You can simulate a distribution such as the one you described using a logarithmic function. The following will return a random strength value between 1.1 and 9.9:
function getRandomStrength()
{
$rand = mt_rand() / mt_getrandmax();
return round(pow(M_E, ($rand - 1.033) / -0.45), 1);
}
Distribution over 1000 runs (where S is the strength value floored):
S | Count
--+------
1 - 290
2 - 174
3 - 141
4 - 101
5 - 84
6 - 67
7 - 55
8 - 50
9 - 38
Note:
This answer was updated to include a strength value of 1.1 (which wasn't included before because of the rounding) and to fix the name of the mt_getrandmax() function
The simplest way to do this would be to provide 'bands' for where a random number should go. In your example, you have 15 players so you could have:
rand < 1/15, highest strength
1/15 < rand < 3/15, second highest
3/15 < rand < 6/15, third highest
6/15 < rand < 10/15, fourth highest
10/15 < rand < 15/15, lowest strength
You could also parameterise such a function with a 'max' number of each band that you allow and when the band is filled, it is subsumed into the next lowest existing band (apart from the bottom band, which would be subsumed into the next highest) to ensure only a certain number of each with a random distribution.
Edit adding from my comments:
To get a floating range pyramid structure the best function would most likely be a logarithm. The formula:
11 - log10(rand)
would work (with log10 being a logarithm with base 10) as this would give ranges like:
1 < rand < 10 = 9 < strength < 10
10 < rand < 100 = 8 < strength < 9
100 < rand < 1000 = 7 < strength < 8
etc.
but rand would need to range from 1 to 10^10 which would require a lot of randomness (more than most random generators can manage). To get a random number in this sort of range you could multiply some together. 3 random numbers could manage it:
11 - log10(rand1 * rand2 * rand3)
with rand1 having range 1-10000 and rand2 and rand3 having range 1-1000. This would skew the distribution away from a proper pyramid slightly though (more likely to have numbers in the centre I believe) so it may not be suitable.
workmad3 has the start of it down, I think, but there's a catch - you need to track your bucket sizes and whether or not they're full. A random number generator won't guarantee that. You'll need to assign your bucket values (strenghs) and sizes (number of people), and let your random generator tell you which bucket to drop the player into - if that one is full, 'overflow' to the next lower.
As to assigning the bucket sizes for a given strength value, that's the tricky bit (and I think what you're really working at). The characteristics of your desired distribution are critical. If you want a linear drop (which the pyramid shape hints at), a line of the form
strength = max_strength - m(number_characters)
would work. Varying the value of m would change the speed at which the line drops off, and will basically limit your max number of total characters. If you're looking for a more sophisticated way for the strength values to drop off, you could use a parabolic or hyperbolic curve - these are a bit more complex, but give you very different characteristics.
something like this
<?php
$rand = rand(1,10);
switch ($rand) {
case 1:
echo "band 1";
break;
case 2:
case 3:
echo "band 2";
break;
case 4:
case 5:
case 6:
echo "band 3";
break;
default:
echo "band 4";
break;
}
?>
Band 1 being the strongest, band 4 being the weakest.
Ofcourse this is basic, you would want to refactor this to use loops instead of hardcoded switches, but you get the idea :)
It's probably easiest to use percentages in this case.
From your examples would approximately be (converted to an array for ease of use later):
$strength[1] = .3; // start with a key of 1
$strength[2] = .26;
$strength[3] = .21;
$strength[4] = .15;
$strength[5] = .08;
That way, you can generate a random number using mt_rand() and divide by the maximum possible value to get a number between 0 and 1:
$rand = mt_rand() / mt_getrandmax(); // rand is some random value between 0 and 1
Then you can use a foreach statement to isolate each case:
$comparisonPercentage = 1;
$selectedLevel = count($strength); // covers the case where mt_rand() returns 0
foreach($strength as $level => $currentPercentage)
{
$comparisonPercentage -= $currentPercentage;
if ($rand > $comparisonPercentage)
{
$selectedLevel = $level;
break;
}
}
// $selectedLevel contains the level you need...
If you do it this way, you only have to change the $strength array if you need to fiddle with the percentages.
generate a random number between 0 and 40000, if its between 0 and 12000, assign strength 1, between 12000 and 22500 assign 2 etc.
Edit: for progressive values between 0 and 10 use the square root of a random number between 0 and 100, then substract if from 10
rand -> strengh
0-1 -> 9.9 -> 9 (1%)
2-4 -> 9 -> 8 (2%)
...
81 - 100 -> 1 - 0 (19%)
For results between 1.1 and 9.9 the formula would be in pseudocode)
strength = 10 - sqrt(rand(1..79))

Categories