I am currently trying to make a poker algorithm that creates all possible poker combinations with 2 cards. I know that there are 1,326 combinations of starting hands.
So I created my starting deck like this:
$startingDeck = array();
for($i=1; $i <= 13; $i++)
{
for($x=0; $x <= 3; $x++)
{
array_push($startingDeck, array("Value" => $i ,"Color" => $x, "key"=> $i.$x));
}
}
I want now to loop through all the cards and get all possible combinations with 2 cards for example
: value 1 color 1 and value 1 color 2
: value 1 color 1 and value 1 color 3
... etc
: value 2 color 0 and value 1 color 1
: value 2 color 0 and value 1 color 2
... etc
I want to do this for all the combinations that are possible but how.
You have your starting deck already. The idea is to generate all permutations:
E.g.
CARD NUMBER
1 2 3 4 5 6 7 8 9 10 11 12 13 ... 52
1 o x x x x x x x x x x x x x
2 - o x x x x x x x x x x x x
3 - - o x x x x x x x x x x x
4 - - - o x x x x x x x x x x
5 - - - - o x x x x x x x x x
6
7 ......... and so on .........
8
9
10
11
12
13
...
52
We have 52 cards in the deck (that's what you generated in $startingDeck):
The x denote the combination that we want to generate. Note that we don't have to generate the lower part of the matrix as the order does not matter in poker as you receive both cards at the same time. We also don't generate the axis as you can't have the same card twice (unless you cheat :)).
The idea now is to use two loops, but let the second loop start depending on the first initial $j depends on $i. That way we do not generate e.g. 2-1, 3-2, 3-1, ... again as we already generated 1-2, 1-3, 2-3, ....
So let's start:
for ($i = 0; i < count($startingDeck); $i++) {
// Ignore e.g. 2-1, 3-2, as we already generated 1-2, 2-3, and so on...
for ($j = $i+1; $j < count($startingDeck); $j++) {
$firstCard = $startingDeck[$i];
$secondCard = $startingDeck[$j];
// print my stuff
}
}
This generates the top matrix. The $i+1 makes sure that we don't generate the diagonal.
I hope that helps.
Related
Let’s say I have a series of numbers like:
12345678910111213141516... (until unlimited)
Then I would like to get a number from it by given digit. For example:
Digit 10th: 1
Digit 17th: 3
...
I have tried to make the algorithm to do it by using PHP but it always showed me an error due to the looping that I made was out of memory size if the given digit that I gave is more than 10.000.000. Allowed Memory Size of 134217728 Bytes Exhausted
How do I deal with this without having to modify memory_limit on php.ini file?
Here are what I have tried to figure the algorithm out: I benchmark the maximum of upper limit of the loop that my local machine could handle, and I found out it's 10.000.000, then I assumed I need to make a separate loop if the given digit/parameter is more than 10.000.000. But in the end I still got that error of out of memory size. Really grateful in advance.
<?php
/*
* benchmark result:
* max digit = 10.000.000
*/
$benchmarkedDigit = 10000000;
$digit = 1000000000000; // it could be dynamically assigned, i.e. a parameter. In this case will show an error since the given digit is 10 trillion
$s = '';
if ($digit > $benchmarkedDigit) {
$mod = fmod($digit, $benchmarkedDigit);
$div = $digit / $benchmarkedDigit;
for ($x = 1; $x <= $div; $x++) {
$upperLimit = ($x * $benchmarkedDigit);
for ($y = ($upperLimit - $benchmarkedDigit + 1); $y <= $upperLimit; $y++) {
$s .= $y;
}
// so it could be:
// 1 - 10.000.000
// 10.000.001 - 20.000.000
// 20.000.001 - 30.000.000
// ...
}
// loop for the rest of the fmod(), if its result is not 0
for ($i = ($upperLimit + 1); $i <= ($upperLimit + $mod); $i++) {
$s .= $i;
}
} else {
for ($x = 1; $x <= $digit; $x++) {
$s .= $x;
}
}
echo substr($s, ($digit - 1), 1);
You can use the fact that there's always 10^n - 10^(n-1) number of n-digit long numbers (even 1 digit, because I see 0 is not there).
With this knowledge, you can skip potentially huge number of numbers.
You start with n=1, and check if the number of n digit numbers is lower than the desired digit. If it is, then reduce the number of n digit numbers from the desired number, increase n by one and start again.
For example: you want to know the 512th digit in that number
Is the number of 1 digit numbers (10) lower than the desired digit (512)?
Yes, so the desired digit should be reduced by that many (512 - 9).
Is the number of 2 digit numbers (90) lower than the desired digit (503 now)?
Yes, so the desired digit should be reduced by that many (503 - 90).
Is the number of 3 digit numbers (900) lower than the desired digit(413 now)?
No, so the desired digit is one of the digits of a 3 digit number.
413 / 3 is 137 (rounded down), so it's one of the digits of the 137th 3 digit numbers (so 237).
413 % 3 (modulo) is 2, so it's the 2nd digit, so it's supposed to be 3.
There can be miscalculations in this, but the overall logic should not be far.
Edit: you could also use a generator, but this can increase the runtime for big numbers
function getNthDigit() {
for ($i = 0;; ++$i) { // Start with 0, which is the 0-th digit
foreach (str_split((string)$i) as $digit) {
yield $digit;
}
}
}
$desiredDigit = 512;
foreach (getNthDigit() as $number => $digit) {
if ($number == $desiredDigit) {
break;
}
}
// $digit should be the desired digit
<?php
function getDigit($Nth){
if($Nth < 10) return $Nth;
$no_of_digits = 1;
$current_contribution = 9;
$actual_length = 9;
$prev_length = 0;
$starting_number = 1;
$power_of_10 = 1;
while($actual_length < $Nth){
$no_of_digits++;
$current_contribution *= 10;
$prev_length = $actual_length;
$actual_length += ($current_contribution * $no_of_digits);
$power_of_10 *= 10;
$starting_number *= 10;
}
$Nth = $Nth - $prev_length;
$offset = $Nth % $no_of_digits === 0 ? intval($Nth / $no_of_digits) - 1 : intval($Nth / $no_of_digits);
$number = strval($starting_number + $offset);
for($i=1;$i<=$no_of_digits;++$i){
if(($Nth - $i) % $no_of_digits === 0){
return $number[$i-1];
}
}
}
// first 100 Digits
for($i=1;$i<=100;++$i){
echo getDigit($i),PHP_EOL;
}
Demo: https://3v4l.org/3l0I7
Algorithm:
To find the nth digit, we will first find the number and then which digit of that number to choose as an answer.
Find the number:
If we carefully observe, the series increases in a sequential manner, such as shown in the table.
Table:
| Digits| Total numbers(of current digit)| Total Digits | Total digits of whole string |
|-------|--------------------------------|--------------|-------------------------------|
| 1 | 9 | 9 | 9 |
| 2 | 90 | 180 | 189 |
| 3 | 900 | 2700 | 2889 |
| 4 | 9000 | 36000 | 38889 |
The above table shows us that if we want to find, let's say 500th digit, then it's some digit of 3 digit number. If we go for 17th digit, then it's some digit of a 2 digit number and so on.
Now, let's take 200th digit as an example. Since it's less than 2889 and greater than 189, it's from a 3 digit number.
What we would do is breakdown the 200 into a smaller number such as 200 - 189 = 11. This 11 means that it's 11th digit of some 3 digit number which started with initial 3 digit number of 100(the starting number for 3 digit).
Now, we do 11 / 3(where 3 is number of digits) and get the quotient as 3. This 3 means that it's 3 numbers past the starting number 100, which we can say as 100 + 3 = 103(since it's 100,101,102 and then the 4th one as 103).
Now, we came to know that the number is 103. All is left to find out is which digit from 103.
Note that sometimes we come across a corner case of even divisibility such as 12 / 3. In this case, we subtract 1 from the quotient since our series of 3 digits starts from 100 and not 101( and so on and so forth for other digits).
Find out the digit:
Now, we know that the number is 103 for a 200 th digit( a.k.a 11 as we calculated above). To find out which one, we write down numbers of 3 digits in sequence and closely observe them.
Sequence:
1 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
If you observe, you can understand that the most MSB digit follows a sequence of 1,4,7,10,13 etc. Second most MSB follows a sequence of 2,5,8,11,14 etc and the last MSB(which is LSB) follows a sequence of 3,6,9,12,15 etc.
So, from th above sequence, it's pretty evident that 11(which we got after breaking down 200 initially) belongs to a sequence of the 2nd most MSB digit.
So, the final answer from 103 is 0 (the 2nd digit from left).
$num = '12345678910111213141516';
echo $num[16];
Result: 3
I want to make the calculation of personal number by date of birth.
The calculation is done in this manner:
Ex. 8 (day) +12 (month) + 1 + 9 + 7 + 1 (year) = 38 = 3 + 8 = 11 = 1 + 1 = 2
(the final number)
This final number must not be greater than nine.
So:
The first number comes is 38 greater than 9 and it should make 3 + 8
The second number comes is 11 greater than 9 it should make 1 + 1
The third number comes is 2 less than 9 so it is the final number.
Taking all these calculations should let out the number 2.
How can I get it with php calculation?
I suppose, you can split date to array. Then
$arr = array(8,12,1,9,7,1);
// sum array, split sum to array per digit untill more than 1 digit in sum
while (count($arr = str_split(array_sum($arr))) != 1) {}
echo $arr[0]; // 2
Imagine that squares in a TicTacToe grid are numbered in a linear fashion from 1 to 9. A player puts an X on the grid by calling a class method:
$game->putX(1, 1); (the method accepts only integers from 0 to 2).
How do I calculate the linear value of the field where X was placed (here the linear value is 5)?
Your help will be much appreciated.
It's actually just x*3 + y+1. Assuming the games state is saved in an array (indexed 1-9, according to your question), your code could look like this:
// the board: examples:
// x 0 1 2 0 0 -> 1
// y 1 1 -> 5
// 0 1 2 3 2 2 -> 9
// 1 4 5 6
// 2 7 8 9
putX ($x, $y) {
$this->state[$x*3+$y+1] = 'X';
}
I've got a grid of 10 square list items. A bit like a gallery. If the user adds another item there will be 11. However this will look strange as the 11th item will be on its own in a new row. How can I use PHP to round up to the nearest 5 and add in the some blank/dummy list items?
You could use the modulo operator to identify the remainder of a division:
10 % 5 = 0
11 % 5 = 1
12 % 5 = 2
13 % 5 = 3
14 % 5 = 4
15 % 5 = 0
With that you can identify if (and how large) such an uncomplete row would be. Knowing how many elements are in that last uncomplete row oviously allows you to calculate the number of remaining cells to fill the row.
($y+(($y%$x)?($x-($y%$x)):0))
...where $y is the number of items(e.g. 11) and $x is the number of items in a row(e.g. 5)
I have an array like
$keywords = array('apple'=>10,'orange'=>2,'grape'=>12);
I want to randomly pick one of the "Key" from the array. However the probability distribution should be such that probability of picking an element should be proportional to it's value.
Add all values (10+2+12 is 24); get a random number in the range [0, 24), and pick the corresponding element depending on whether the number lies in [0, 10), [10, 12), or [12, 24).
I'd do it like this:
$probabilities = array('apple'=>50, 'orange'=>20, 'banana'=>10);
function random_probability($probabilities) {
$rand = rand(0, array_sum($probabilities));
do {
$sum = array_sum($probabilities);
if($rand <= $sum && $rand >= $sum - end($probabilities)) {
return key($probabilities);
}
} while(array_pop($probabilities));
}
An O(log(n)) approach (this is ripped directly from an answer to a very similar question):
The usual technique is to transform the array into an array of cumulative sums:
[10 60 5 25] --> [10 70 75 100]
Pick a random number in the range from zero up to the cumulative total (in the example: 0 <= x < 100). Then, use bisection on the cumulative array to locate the index into the original array:
Random variable x Index in the Cumulative Array Value in Original Array
----------------- ----------------------------- ----------------------
0 <= x < 10 0 10
10 <= x < 70 1 60
70 <= x < 75 2 5
75 <= x < 100 3 25
For example, if the random variable x is 4, bisecting the cumulative array gives a position index of 0 which corresponds to 10 in the original array.
And, if the random variable x is 72, bisecting the cumulative array gives a position index of 2 which corresponds to 5 in the original array.