Probability Calculation - php

I have something like this in my website: There are grids, members click them randomly, they view a webpage, then they learn if they won a prize or not. They have limited number of chance daily.
My algorithm to calculate prize win probability:
Randomly select a number between 1 and 10,000
1a. if this number equals to 1 member wins X
1b. if this number =< 5 member wins Y etc.
Is there another way to calculate this or should I control prizes with additional codes (for example: if today x member won y amount prize stop giving prizes)?
Thanks.

Yes, there are several other ways to calculate this, but your idea is good enough. You can use the following pseudocode for assistance also:
int randomnumber = generaterandomnumber();
bool allprizesgone = getinformationfromdatabase();
if ( allprizesgone equals false ) {
if(randomnumber equals 1) {
member wins X
if(checkifallprizesfortodayaretakes() equals true) {
setinformationtodatabase(allprizesgonetrue);
}
} else if (randomnumer is smaller than 5 ){ //because of else if members can't get both prizes
member wins Y
if(checkifallprizesfortodayaretakes() equals true) {
setinformationtodatabase(allprizesgonetrue);
}
}
}

Related

Highest multiplication with multiple and max number set

Not quite sure what to set this title as, or what to even search for. So I'll just ask the question and hope I don't get too many downvotes.
I'm trying to find the easiest way to find the highest possible number based on two fixed numbers.
For example:
The most I can multiply by is, say, 18 (first number). But not going over the resulted number, say 100 (second number).
2 x 18 = 36
5 x 18 = 90
But if the first number is a higher number, the second number would need to be less than 18, like so:
11 x 9 = 99
16 x 6 = 96
Here I would go with 11, because even though the second number is only 9, the outcome is the highest. The second number could be anything as long as it's 18 or lower. The first number can be anything, as long as the answer remains below 100. Get what I mean?
So my question is, how would write this in php without having to use switches, if/then statements, or a bunch of loops? Is there some math operator I don't know about that handles this sort of thing?
Thanks.
Edit:
The code that I use now is:
function doMath($cost, $max, $multiplier) {
do {
$temp = $cost * $multiplier;
if ($temp > $max) { --$multiplier; }
} while ($temp > $max);
return array($cost, $temp, $multiplier);
}
If we look at the 11 * 9 = 99 example,
$result = doMath(11, 100, 18);
Would return,
$cost = 11, $temp = 99, $multiplier = 9
Was hoping there was an easier way so that I wouldn't need to use a loop, being as how there are a lot of numbers I need to check.
If I understood you right, you are looking for the floor function, combining it with the min function.
Both a bigger number c and a smaller number a are part of the problem, and you want to find a number b in the range [0, m] such that a * b is maximal while staying smaller (strictly) than c.
In your example, 100/18 = 5.55555, so that means that 18*5 is smaller than 100, and 18*6 is bigger than 100.
Since floor gets you the integral part of a floating point number, $b = floor($c/$a) does what you want. When a divides c (that is, c/a is an integer already), you get a * b == c.
Now b may be outside of [0,m] so we want to take the smallest of b and m :
if b is bigger than m, we are limited by m,
and if m is bigger than b, we are limited by a * b <= c.
So in the end, your function should be :
function doMath($cost, $max, $multiplier)
{
$div = min($multiplier, floor($max/$cost));
return array($cost, $div * $cost, $div);
}

PHP Pixel Map Group Efficiency

I currently have a map that is 1600 x 1600 stored in MySQL(2,560,000 records). I'm rendering a simple 25x25 map out to users for interaction. Users can "claim" tiles on this map. I'd like to be able to calculate the number of open faces for tiles owned by a given user. I can divide this out by the total tiles owned to determine an arbitrary efficientcy rating.
All map coordinates are simply stored as X/Y values.
I'm looking for something that can potentially process an array of said X/Y values and determine how many open faces are accessible for each owned group. For example...
0 = player
x x x x x
x x 0 x x
x x x x x
4 open faces
x x x x x
x x 0 x x
x x 0 x x
x x x x x
6 open faces
x x x x x
x x x 0 x
x x 0 x x
x x x x x
8 open faces
Right now I'm doing some inefficient array looping to calculate this out. I have a simple counter, then I'm looping through an array of all values and am looking for values +-1 in each direction of X and Y to reduce the count. Each loop either adds 0-4 to the total counter based on the number of finds. The inherent problem with this method is that as a group grows, it will take longer and longer to calculate out. Since it's possible for one group to consume 20,000 points o rmore, it's quite a burden.
Any help is greatly appreciated.
One approach would involve creating a Point class. For example:
class Point {
public $x;
public $y;
public function __construct($x, $y){
$this->x = $x;
$this->y = $y;
}
public function getNeighbors(){
// TODO: What if we are at the edge of the board?
return array(
new Point($x+1, $y+1),
new Point($x+1, $y-1),
new Point($x-1, $y+1),
new Point($x-1, $y-1),
);
}
}
Create instances from that class for each point occupied by a user:
// Generate array of Points from database
$user_points = array(new Point(134, 245), new Point(146, 456));
Iterate through to generate all the neighbors:
// Get a flat array of neighbor Points
$neighbors = array_merge(array_map(function($point){
return $point->getNeighbors();
}, $user_points));
// TOOD: Remove Points that are equal to values in $user_points
Then, lastly, submit a COUNT query for the "neighbor" points to determine how many are occupied by other users and remove those from the total.
(Note: I've added TODOs where more work is to be done.)
The inherent problem with this method is that as a group grows, it will take longer and longer to calculate out.
You should consider using an in-memory key-value store, like Redis. But yes, the look-up time (for occupied blocks), in time complexity, appears linear with regard to the number of entries.
Here's the final block of simple code I came up with to determine the geo efficiency. Some names of things have been changed. :P
I'm running with notices on, and everything's ajax, so I decided to go with single isset checks on a multi-dimensional instead of something else.
$sql = 'SELECT map_x, map_y FROM Map WHERE person_id = :person_id';
$query = $DB->prepare($sql);
$query->execute(array(':nation_id' => $this->person_id));
$counter = 0;
$coords = array();
while($row = $query->fetch())
{
++$counter;
$coords[$row['map_x']][$row['map_y']] = 1;
}
$faces = 0;
foreach($coords as $x => $batch)
{
foreach($batch as $y => $junk)
{
$hits = 4;
if(isset($coords[$x + 1][$y]))
{
--$hits;
}
if(isset($coords[$x - 1][$y]))
{
--$hits;
}
if(isset($coords[$x][$y - 1]))
{
--$hits;
}
if(isset($coords[$x][$y + 1]))
{
--$hits;
}
$faces += $hits;
}
}

PHP radom array values from another array

///PROBLEM SOLVED. SEE MY ANSWER BELLOW.///
I have an array that randomly generates TRUE values throughout it. I
specified the number of TRUE values i want and it works like a charm.
I was toying around with it`s values and generating certain actions
based on wether or not the value is TRUE. Problem is i need to do this
again, this time using the TRUE values to form an array from which i
need a certain number of TRUE values.
I.E. I wanted 3 TRUE values out of 5. The code gave me the 3 TRUE
values on random iterations:
[1]=>1; [1]=>;
[2]=>1; [2]=>1;
[3]=>; [3]=>1;
[4]=>; [4]=>;
[5]=>1; [5]=>1;
This is all fine and dandy. Now i need TRUE values on 2 out of the 3
previous values. Consider i am taking 5 bites out of an apple. On 3
occasions i choke on it, from which in 2 cases i lose 2,3 teeth.
I want to print the outcome.
"Took a bite"
"Took a bite and choked"
"Took a bite"
"Took a bite , choked , lost 1 tooth and got 9 left" (i have a total of 10 teeth)
"Took a bite , choked , lost 2 teeth and got 7 left"
This is what i need to see printed after the 3/5 and 2/3 random
calculations occured. If i took a bite on the [2],[4] and [5]
iterations, i must lose tooth 2 times randomly on those exact
iterations.
Sorry for this example.
///PROBLEM SOLVED. SEE MY ANSWER BELLOW.///
2) Lastly, how can i store what happened after the code ran? Like "After you ate that apple, you choked 3 times lost 3 teeth and still got 7 left".
The way i did it does not work and returns "me loosing 1 tooth and having 9 left despite the fact that my calculated value is 7", not stacking the values of my ordeal.
I know these questions are silly, but i searched everywhere for information, read manuals and stuff and cannot put the pieces together...
The method used in the " random 3/5" case:
$spots = array();
while (count($spots) < number) {
$rand = rand(1,36);
if (!isset($spots[$rand])) {
$spots[$rand] = TRUE;
}
}
$spots = $spots + array_fill(1, number, FALSE);
ksort($spots); /// credits to Nick J.
Then did a foreach($spots as $k => $v)
Then did my code statements, starting with if ($v == 1), do code...
And gave me a random 3/5 list like the one i posted first.
Thank you in advance,
Vlad
Ok, i edited my answer as i have found the solution to problem number 1.
The catch was to scan the array of elements that are FALSE, unset them, work with that further on as it will randomly select elements from the TRUE elements of the original array.
Hope this comes in handy. I will post the code here:
$spots = array();
while (count($spots) < number) {
$rand = rand(1,constant);
if (!isset($spots[$rand])) {
$spots[$rand] = TRUE;
}
}
$spots = $spots + array_fill(1, constant, FALSE);
ksort($spots);
print_r($spots) ;
foreach($spots as $v)
{
if($v != 1)
{
unset($spots[array_search($v,$spots)]);
}
}
print_r($spots);
If example array:
$spots = array("1","2","3","4","5");
And i want 3 random numbers to be picked (TRUE = 1 , FALSE = nothing)
then the output is:
[1]=>1;
[2]=>1;
[3]=>;
[4]=>;
[5]=>1;
If i want 2 random numbers out of the 3 just got, then the final output is:
[1]=>1;
[2]=>1;
[5]=>1;

Controlling likelyhood of randomly generated numbers

If I wanted a random number between one and three I could do $n = mt_rand(1,3).
There is a 33% chance that $n = 1, a 33% chance it's 2, and a 33% chance that it's 3.
What if I want to make it more difficult to get a 3 than a 1?
Say I want a 50% chance that a 1 is drawn, a 30% chance that a 2 is drawn and a 20% chance that a 3 is drawn?
I need a scalable solution as the possible range will vary between 1-3 and 1-100, but in general I'd like the lower numbers to be drawn more often than the higher ones.
How can I accomplish this?
There is a simple explanation of how you can use standard uniform random variable to produce random variable with a distribution similar to the one you want:
https://math.stackexchange.com/a/241543
This is maths.
In your example the just chose a random number between 0 and 99.
Values returned between 0 to 49 - call it 1
Values returned between 50 - 69 - Call it 2
Values returned between 70 - 99 - Call it 3
Simple if statement will do this or populate an array for the distribution required
Assuming a 1 - 10 scale, you can use a simple if statement and have the numbers represent percentages. And just have each if statement set $n to a specific. Only downfall, it isn't universal.
$dummy = mt_rand(1,10);
// represents 50%
if ($dummy <= 5) {
$n = 1;
}
// represents 40%
if ($dummy >= 6 && $dummy <= 9) {
$n = 2;
} else {
// represents 10%
$n = 3;
}

Lowest cost based on case sizes

I'm working on a shipping module for wine, and was wondering if anyone could give me a hand - basically:
The wine can be shipped in cases of 8, 12 or 15 bottles, each with its own price. The module needs to take the total number of bottles in the order, and work out which combination of cases gives the lowest price. Eg in an order of 31 bottles, the lowest price works out to 1 case of 15 and two cases of 8, (rather than 2 cases of 15 and 1 of 8, or 2 of 12 and one of 8). Currently, I have the following, which almost works, but misses a few possible combinations
foreach ($rates as $case_size => $case_price)
{
$price = floor($total_bottles / $case_size) * $case_price;
$rem = $total_bottles % $case_size;
if($rem > 12)
{
//needs to use another case of 15
$price = $price + $rates[15];
}
elseif($rem > 8)
{
//needs an extra case of 12
$price = $price + $rates[12];
}
elseif($rem > 0)
{
//needs an extra case of 8
$price = $price + $rates[8];
}
$quotes[] = $price;
}
return min($quotes);
From your post your saying that the most price-effective system wouldn't just the one that has uses the lowest cost per bottle of the container, but also needs to be the most efficient at filling the containers. However your algorithm is only looking at would use the fewest large boxes possible. You need an algorithm that will completely fill each case possible.
I would do something like this: Use a recursive program to find the combination that would most completely fill each case.
function fit_case($number, $case_size) {
$rem = $number % $case_size;
$next_size=magic_voodo0();
if($rem==0) { //if perfectly fills it you're done
return ($number/$case_size)*$rates[$case_size];
} else if(($rem % $next_size)/$next_size>.5) {
//if over 50% fills the next case add the next smaller case
return floor($number/$case_size)*$rates[$case_size]+fit_case($rem, $next_size);
} else { //otherwise back off 1 of the biggest cases, and fill the rest
return (floor($number/$case_size)-1)*$rates[$case_size]+fit_case($rem, $next_size);
Hope this helps.
Different approach. Use a lookup table that has all combinations of boxes for a specific number of bottles.
1 bottle - 8
...
31 bottle - 15-8-8,15-15-8,8-8-8-8, and so on
and so on
Use another lookup table for the different rates per box per country
In your function
get table row for country prices
get the different combinations for the number of bottles
do a foreach loop on combinations
save the price and combination of first loop to variables
compare the price of the next loop with the saved value
if it is lower, save price and combination/if not, continue
loop through all combinations
return lowest price/box combination

Categories