Currently I have this:
$chance = 5;
#Set the winning chances.
function winningChance($percentage)
{
if ($percentage < 0 || $percentage > 100)
throw new Exception('Invalid percentage');
return rand(0, 100) <= $percentage ? 'won' : 'lost';
}
if(winningChance($chance) == "lost"){
$won = false; //You lost.
}else{
$won = true; //You won.
}
This is really simple. It seems like even though the $chance is set to 5, the winning occur way more often than it should.
Can anyone suggest me how to improve this?
Related
I have a table in a MySQL database that has a list of levels (1-10) and has a XP_NEEDED column, I already have a number and I want to find the level from that number (the number is an XP), I know how to do this in the way below...
Example (Short):
if ($xpLookingFor >= 100 && $xpLookingFor < 200) // Checks if not high as level 2 {
return '1'; // Would be returning Level1
}
else if ($xpLookingFor >= 200 && $xpLookingFor < 300) // Checks if not high as level 3 {
return '2'; // Would be returning Level2
}
So it checks if its higher than the current level but not as high as the level aboves xp_needed, if its as high as the next level the next if statement will handle it.
But this way has a lot of code that could possibly be shortened, what is the best way to do this? is there a built in mysql feature for this?
Im not sure if this is what you need question is not too clear.
<?php
function getLevel($xp, $maxLevel) {
for($check = 1; $check < $maxLevel; $check++)
if ($xp >= ($check*100) AND $xp < ($check*100)+100) return $check;
return $maxLevel;
}
//Param #1 is the xp level and #2 is the max level
echo getLevel(503, 10); // returns 5
echo getLevel(123, 10); //returns 1
echo getLevel(1405, 20); //returns 14
echo getLevel(1405, 10); //returns 10
?>
Because you're using elseif, the first part of the if isn't needed, you could stack them something like this.
function getLevel($xpLookingFor){
if ($xpLookingFor < 100){
return 0;
}
else if ($xpLookingFor < 200){
return 1;
}
else if ($xpLookingFor < 300){
return 2;
}
else if ($xpLookingFor < 375){
return 3;
}
else if ($xpLookingFor < 400){
return 4;
}
else {
return 'MAX!';
}
}
See example on IdeOne
I have a game development project and I have specific character one of the skill of the character is that it has a 10% chance of doubling its attack.
Question: How can I trigger it?
I hope i understand ure question:
<?php
$random = rand(1,10);
if(($random == 1) || ($random == 2) || ($random == 3))
$value += $value;
?>
Here you have a 30% chance to hit 1, 2 or 3.. and if its hit then your value gets doubled.
Ok now for your Update u just need a 10% chance? But okay:
<?php
$random = rand(1,10);
if($random == 1)
$value += $value;
?>
function doubleHit($percentChance = 30)
{
if (mt_rand(1,100) <= $percentChance) {
return true;
}
return false;
}
var_dump(doubleHit(35)); // will return either true / false
Note that this is only pseudorandom. Also note that this is faster / better than rand().
For example this code will double the value theoretically one in three times? It's hard for me to understand you.
$value = 200;
if (rand(1,3)===1) {
$value*=2;
}
Or maybe this, for percents:
$value = 200;
$percent = 30;
$chance = rand(1, 100);
if ($chance <= $percent) {
$value *= 2;
}
function rawtransform{
if ($raw>=500 && $raw<=550){
$score= 1;
}
if ($raw>=550 && $raw<=600){
$score= 2;
}
if ($raw>=600 && $raw<=650){
$score= 3;
}
if ($raw>=700 && $raw<=750){
$score= 4;
}
if ($raw>=750 && $raw<=800){
$score= 5;
}
if ($raw>=800 && $raw<=850){
$score= 6;
}
if ($raw>=850 && $raw<=900){
$score= 7;
}
if ($raw>=900 && $raw<=950){
$score= 8;
}
if ($raw>=950 && $raw<=1000){
$score= 9;
}
}
This seems very basic and not very well coded. (I am only learning php )
Can anyone offer a better way of doing this? maybe a single if statement. I think there is a way just cant get my head round it.
Thanks
How about just using math?
function rawtransform($raw) {
$score = (int)($raw/50)-9;
}
You may want to add a range check for the input, though.
You can create a list of conditions, and loop through the and apply the if.
$conditions = array(
array(500, 550, 1), // greater than value, lesser than value, assignment value
array(550, 600, 2),
array(650, 700, 3) // add the rest of the conditions
);
foreach($conditions as $condition) {
if($raw >= $condition[0] && $raw <= $condition[1]) {
$score = $condition[2];
}
}
if ($raw >= 500 && $raw<= 1000){
$score = ceil(($raw-500)/50);
}
You can use if...else constructs.
if ($raw>=500 && $raw<=550){
$score= 1;
}
elseif ($raw>=550 && $raw<=600){
$score= 2;
}
elseif ($raw>=600 && $raw<=650){
$score= 3;
}
That way, if the script encounters a size of, say, 575 it won't even bother to go through the following conditions.
In your given example, the script can be simplified by:
function rawtransform($raw) { $score = floor(($raw - 450)/50); return $score; }
Your logic seems to be that you are subtracting 450 from raw, then dividing it by 50 and rounding down to the nearest whole number. (There are problems in your implementation however, as if raw is a factor of 50, it will meet the requirements for two of the if statements and there is a condition missing for when it falls between 650 and 700.)
You could do this as follows:
floor(($raw-450)/50)
I'm trying to program my own Sine function implementation for fun but I keep getting :
Fatal error: Maximum execution time of 30 seconds exceeded
I have a small HTML form where you can enter the "x" value of Sin(x) your looking for and the number of "iterations" you want to calculate (precision of your value), the rest is PhP.
The maths are based of the "Series definition" of Sine on Wikipedia :
--> http://en.wikipedia.org/wiki/Sine#Series_definition
Here's my code :
<?php
function factorial($int) {
if($int<2)return 1;
for($f=2;$int-1>1;$f*=$int--);
return $f;
};
if(isset($_POST["x"]) && isset($_POST["iterations"])) {
$x = $_POST["x"];
$iterations = $_POST["iterations"];
}
else {
$error = "You forgot to enter the 'x' or the number of iterations you want.";
global $error;
}
if(isset($x) && is_numeric($x) && isset($iterations) && is_numeric($iterations)) {
$x = floatval($x);
$iterations = floatval($iterations);
for($i = 0; $i <= ($iterations-1); $i++) {
if($i%2 == 0) {
$operator = 1;
global $operator;
}
else {
$operator = -1;
global $operator;
}
}
for($k = 1; $k <= (($iterations-(1/2))*2); $k+2) {
$k = $k;
global $k;
}
function sinus($x, $iterations) {
if($x == 0 OR ($x%180) == 0) {
return 0;
}
else {
while($iterations != 0) {
$result = $result+(((pow($x, $k))/(factorial($k)))*$operator);
$iterations = $iterations-1;
return $result;
}
}
}
$result = sinus($x, $iterations);
global $result;
}
else if(!isset($x) OR !isset($iterations)) {
$error = "You forgot to enter the 'x' or the number of iterations you want.";
global $error;
}
else if(isset($x) && !is_numeric($x)&& isset($iterations) && is_numeric($iterations)) {
$error = "Not a valid number.";
global $error;
}
?>
My mistake probably comes from an infinite loop at this line :
$result = $result+(((pow($x, $k))/(factorial($k)))*$operator);
but I don't know how to solve the problem.
What I'm tring to do at this line is to calculate :
((pow($x, $k)) / (factorial($k)) + (((pow($x, $k))/(factorial($k)) * ($operator)
iterating :
+ (((pow($x, $k))/(factorial($k)) * $operator)
an "$iterations" amount of times with "$i"'s and "$k"'s values changing accordingly.
I'm really stuck here ! A bit of help would be needed. Thank you in advance !
Btw : The factorial function is not mine. I found it in a PhP.net comment and apparently it's the optimal factorial function.
Why are you computing the 'operator' and power 'k' out side the sinus function.
sin expansion looks like = x - x^2/2! + x^3/3! ....
something like this.
Also remember iteration is integer so apply intval on it and not floatval.
Also study in net how to use global. Anyway you do not need global because your 'operator' and power 'k' computation will be within sinus function.
Best of luck.
That factorial function is hardly optimal—for speed, though it is not bad. At least it does not recurse. It is simple and correct though. The major aspect of the timeout is that you are calling it a lot. One technique for improving its performance is to remember, in a local array, the values for factorial previously computed. Or just compute them all once.
There are many bits of your code which could endure improvement:
This statement:
while($iterations != 0)
What if $iterations is entered as 0.1? Or negative. That would cause an infinite loop. You can make the program more resistant to bad input with
while ($iterations > 0)
The formula for computing a sine uses the odd numbers: 1, 3, 5, 7; not every integer
There are easier ways to compute the alternating sign.
Excess complication of arithmetic expressions.
return $result is within the loop, terminating it early.
Here is a tested, working program which has adjustments for all these issues:
<?php
// precompute the factorial values
global $factorials;
$factorials = array();
foreach (range (0, 170) as $j)
if ($j < 2)
$factorials [$j] = 1;
else $factorials [$j] = $factorials [$j-1] * $j;
function sinus($x, $iterations)
{
global $factorials;
$sign = 1;
for ($j = 1, $result = 0; $j < $iterations * 2; $j += 2)
{
$result += pow($x, $j) / $factorials[$j] * $sign;
$sign = - $sign;
}
return $result;
}
// test program to prove functionality
$pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620;
$x_vals = array (0, $pi/4, $pi/2, $pi, $pi * 3/2, 2 * $pi);
foreach ($x_vals as $x)
{
$y = sinus ($x, 20);
echo "sinus($x) = $y\n";
}
?>
Output:
sinus(0) = 0
sinus(0.78539816339745) = 0.70710678118655
sinus(1.5707963267949) = 1
sinus(3.1415926535898) = 3.4586691443274E-16
sinus(4.7123889803847) = -1
sinus(6.2831853071796) = 8.9457384260403E-15
By the way, this executes very quickly: 32 milliseconds for this output.
I got the answer fine, but when I run the following code,
$total = 0;
$x = 0;
for ($i = 1;; $i++)
{
$x = fib($i);
if ($x >= 4000000)
break;
else if ($x % 2 == 0)
$total += $x;
print("fib($i) = ");
print($x);
print(", total = $total");
}
function fib($n)
{
if ($n == 0)
return 0;
else if ($n == 1)
return 1;
else
return fib($n-1) + fib($n-2);
}
I get the warning that I have exceeded the maximum execution time of 30 seconds. Could you give me some pointers on how to improve this algorithm, or pointers on the code itself? The problem is presented here, by the way.
Let's say $i equal to 13. Then $x = fib(13)
Now in the next iteration, $i is equal to 14, and $x = fib(14)
Now, in the next iteration, $i = 15, so we must calculate $x. And $x must be equal to fib(15). Now, wat would be the cheapest way to calculate $x?
(I'm trying not to give the answer away, since that would ruin the puzzle)
Try this, add caching in fib
<?
$total = 0;
$x = 0;
for ($i = 1;; $i++) {
$x = fib($i);
if ($x >= 4000000) break;
else if ($x % 2 == 0) $total += $x;
print("fib($i) = ");
print($x);
print(", total = $total\n");
}
function fib($n) {
static $cache = array();
if (isset($cache[$n])) return $cache[$n];
if ($n == 0) return 0;
else if ($n == 1) return 1;
else {
$ret = fib($n-1) + fib($n-2);
$cache[$n] = $ret;
return $ret;
}
}
Time:
real 0m0.049s
user 0m0.027s
sys 0m0.013s
You'd be better served storing the running total and printing it at the end of your algorithm.
You could also streamline your fib($n) function like this:
function fib($n)
{
if($n>1)
return fib($n-1) + fib($n-2);
else
return 0;
}
That would reduce the number of conditions you'd need to go through considerably.
** Edited now that I re-read the question **
If you really want to print as you go, use the output buffer. at the start use:
ob_start();
and after all execution, use
ob_flush();
flush();
also you can increase your timeout with
set_time_limit(300); //the value is seconds... so this is 5 minutes.