I've got these two functions:
function drawNumber($drawnNumbers){
$unique = true;
while ($unique == true){
$number = mt_rand(10, 69);
if (!in_array($number, $drawnNumbers)){
return $number;
$unique = false;
}
}
}
fillCard(); ?>
It's a bingo game. The card gets filled with random Numbers. But I can't get it like this:
column column column column column column
row 10 13 16 14 16 19
row 24 26 28 29 23 21
row 36 33 39 30 31 35
row 46 48 42 45 43 47
row 59 56 51 52 58 50
row 60 65 68 62 61 67
So I would like to have the first row with numbers from 10 to 19
the second row from 20 to 29 and so on.
I tried like this
<?php drawnNumber(): $number = mt_rand(0,9);
fillArray(): $number = $row . $number; ?>
But that doesn't work, because there are double numbers in the card.
So before that I tried it in a different way,with in_array:
<?php
function fillCard(){
$card = array();
/* fill card with random numbers */
for($i = 0, $min = 10, $max = 19; $i < 6; $i++, $min+=10, $max += 10)
{
for($j = 0; $j < 6; $j++)
{
$number = mt_rand($min,$max) ;
if(!in_array($number, $card){
$card['row' . $i]['column' . $j]['number'] = $number;
$card['row' . $i]['column' . $j]['found'] = 0;
}
}
}
var_dump($card);
return $card;
} ?>
But there are still double random numbers in the card.
I tried a few other thinks in the last two weeks, but I just can't get it to work together.
If one thing succeeds the other thing fails.
I can get the random numbers but not unique random numbers in the card.
I hope someone can help me.
(for extra information: it's a bingo game. So drawnNumber() are the "balls", which get drawn
and stored in the array $drawnNumbers, they also are unique random numbers. fillCard() is the
function that fills the bingo card and checks if $drawNumber is in $card)
I would appreciate some help, if someone can tell me how to get it to work. Maybe in
an algorithm way or else some code?
Thank you in advance.
In general, you draw from some kind of box, right? So do the same, have an array with all available numbers and once you get a random number out of it, remove it, so the next time you search for a number, you will only pick from the remaining ones. Small example:
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
we pick a random number between 0 and 3 inclusive (0 and the length - 1 of a that is). Let's say we picked index 2, then a will look like:
a[0] = 1
a[1] = 2
a[2] = 4
Now if you draw a number between 0 and 2 (note that you take the length - 1 of a!), you won't re-pick the already chosen number in any way thus giving you unique numbers ALL the time.
P.S. this is a simplified version, but now if you can apply that to yourself and, for your example, create several arrays you will pick from.
The simplest way would be to have an additional flat array to keep track, and loop mt_rand
Here's an example of the meat of things:
$drawn = array();
// Loop around until you have a new number in the desired range
do {
$number = mt_rand($min,$max);
} while(in_array($number, $drawn));
// And save it to the $drawn array
$drawn[] = $rand;
To clarify, the above snippet (without the initialization of $drawn) is meant to replace the line
$number = mt_rand($min,$max) ;
in your code.
define('NB_ROWS', 6);
define('NB_COLS', 6);
$rows = range(10, NB_ROWS * 10, 10);
$bingo = array();
foreach($rows as $rowIndex)
{
$availNumbers = range(0, 9);
$line = array();
for($cellIndex = 0; $cellIndex < NB_COLS; $cellIndex++)
{
// pick a random value among remaining ones for current line
$numIndex = rand(0, count($availNumbers)-1);
list($value) = array_splice($availNumbers, $numIndex, 1);
$line[] = $value + $rowIndex;
}
$bingo[] = $line;
}
print_r($bingo);
Related
I am trying to divide number to geners but if after that its less than 16 I want it to add the numbers from the less to 16 to the first gener in foreach.
$geners = explode(",", $post['geners']); // $post['geners'] = 12,26,988
$count = count($geners); // For example : 3
$calc = (16 / $count); / 5.6666
$total_each = number_format($calc, 0); // 5
$total = ( $count * $total_each); // 15
foreach ($geners as $key=>$gener){
$gener_each = $total_each;
if($total < 16){ // if 15 < 16
$minus_16 = 16 - $total; // 15-16 = 1
$gener_each[0]=$gener_each[0]+$minus_16; // First gener need to add $minus_16
}
echo $gener_each; // Need to be 6,5,5
}
It sounds like you need to divide 16 by an arbitrary number, create an array holding the same number of instances of that result as you have geners, round each instance of the divided result down to the nearest whole number, and then apply any remaining difference from a decimal result to the first in the set.
The following is untested, but have a look:
$geners = explode(',', $post['geners']);
$firstGener = current($geners);
$count = count($geners);
$calc = (16 / $count);
$floor = floor($calc);
$decimal = $calc - $floor;
$totals = [];
foreach ($geners as $gener) {
$totals[$gener] = $floor;
$totals[$firstGener] += $decimal;
}
//This is just in case a decimal result of an infinite number of digits, truncated by PHP itself, results in this value erroneously looking something like 5.9999999999999
$totals[$firstGener] = round($totals[$firstGener]);
//Since the value of $totals[$geners[0]] isn't done calculating until the completion of the above loop, presentation of each value needs to be handled in a separate one here:
foreach ($totals as $gener => $totals) {
echo "$gener - $total<br>";
}
The problem statement is as following:
A particular kind of coding which we will refer to as "MysteryCode" is a binary system of encoding in which two successive values, differ at exactly one bit, i.e. the Hamming Distance between successive entities is 1. This kind of encoding is popularly used in Digital Communication systems for the purpose of error correction.
LetMysteryCodes(N)represent the MysteryCode list for N-bits.
MysteryCodes(1) = 0, 1 (list for 1-bitcodes,in this order)
MysteryCodes(2) = 00, 01, 11, 10 (list for 2-bitcodes,in this order)
MysteryCodes(3) =000, 001, 011, 010,110, 111, 101, 100 (list for 3-bitcodes,in this order)
There is a technique by which the list of (N+1) bitcodescan be generated from (N)-bitcodes.
Take the list of N bitcodesin the given order and call itList-N
Reverse the above list (List-N), and name the new reflected list: Reflected-List-N
Prefix each member of the original list (List-N) with 0 and call this new list 'A'
Prefix each member of the new list (Reflected-List-N) with 1 and call this new list 'B'
The list ofcodeswith N+1 bits is the concatenation of Lists A and B.
A Demonstration of the above steps: Generating the list of 3-bitMysteryCodesfrom 2-BitMysteryCodes
2-bit list ofcodes:00, 01, 11, 10
Reverse/Reflect the above list:10, 11, 01, 00
Prefix Old Entries with 0:000, 001, 011, 010
Prefix Reflected List with 1:110, 111, 101, 100
Concatenate the lists obtained in the last two steps:000, 001, 011, 010, 110, 111, 101, 100
Your Task
Your task is to display the last N "MysteryCodes" from the list of MysteryCodes for N-bits. If possible, try to identify a way in which this list can be generated in a more efficient way, than iterating through all the generation steps mentioned above.
More efficient or optimized solutions will receive higher credit.
Input Format
A single integer N.
Output Format
N lines, each of them with a binary number of N-bits. These are the last N elements in the list ofMysteryCodesfor N-bits.
Input Constraints 1 = N = 65
Sample Input 1
1
Sample Output 1
1
Explanation for Sample 1
Since N = 1, this is the (one) last element in the list ofMysteryCodesof 1-bit length.
Sample Input 2
2
Sample Output 2
11
10
Explanation for Sample 2 Since N = 2, these are the two last elements in the list ofMysteryCodesof 2-bit length.
Sample Input 3
3
Sample Output 3
111
101
100
$listN = 25;
$bits = array('0','1');
//check if input is valid or not
if(!is_int($listN))
{
echo "Input must be numeric!";
}
if($listN >= 1 && $listN <=65){
if($listN == 1){
echo '1'; exit;
}
ini_set('memory_limit', -1);
for($i=1; $i<=($listN - 1); $i++){
$reverseBits = array_reverse($bits);
$prefixBit = preg_filter('/^/', '0', $bits);
$prefixReverseBits = preg_filter('/^/', '1', $reverseBits);
$bits = array_merge($prefixBit, $prefixReverseBits);
unset($prefixBit, $prefixReverseBits, $reverseBits);
}
$finalBits = array_slice($bits, -$listN);
foreach($finalBits as $k=>$v){
echo $v."\n";
}
}
else{
echo "Invalid input!";
}
I have tried above solution, but didnt worked for input greater than 20.
for eg. If the input is 21, I got "Couldnt allocate memory" error.
It will be great if somebody figure out the optimized solutions...
The numbers follow a pattern which I transformed to below code.
Say given number is N
then create a N x N matrix and fill it's first column with 1's
and all other cells with 0's
Start from rightmost column uptil 2nd column.
For any column X start from bottom-most row and fill values like below:
Fill 2^(N - X + 1)/2 rows with 0's.
Fill 2^(N - X + 1) rows with 1's and then 0's alternatively.
Repeat step 2 till we reach topmost row.
Print the N x N matrix by joining the values in each row.
<?php
$listN = 3;
$output = [];
for ($i = 0; $i < $listN; $i++) {
$output[$i] = [];
for ($j = 0; $j < $listN; $j++) {
$output[$i][$j] = 0;
}
}
$output[$listN - 1][0] = 1;
for ($column = 1; $column < $listN; $column++) {
$zeroFlag = false;
for ($row = $listN - 1; $row >= 0;) {
$oneZero = 1;
if (!$zeroFlag) {
for ($k = 1; $k <= pow(2, $column) / 2 && $row >= 0; $k++) {
$output[$row][$listN - $column] = 0;
$row--;
$zeroFlag = true;
}
}
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
$oneZero = 0;
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
}
}
for ($i = 0; $i < $listN; $i++) {
$output[$i][0] = 1;
}
for ($i = 0; $i < $listN; $i++) {
print(join('', $output[$i]));
print("\n");
}
I would like to find out what is the most effective PHP script to evenly represent all numbers in a specific combinations subset.
Lottery problem example:
create 10 combinations each consisting of of 6 numbers
from set of number (1,2,3,4,5,6,7,8,9,10,11,12)
I know that from 12 numbers I can create 924 combinations each consisting of 6 numbers.
Since I can't afford to play 924 lines - I want to pick only 10 lines which represent evenly all my selected numbers.
So in this example it would be something like:
1-2-3-4-5-6
7-8-9-10-11-12
and 8 more lines
I'm trying to avoid combinations like:
1-2-3-4-5-6
1-2-3-4-5-7
1-2-3-4-5-8
... etc. which are almost the same; I want to evenly represent each number.
Hope that makes sense.
You can create a "pool" of the numbers you want to use, and randomly draw from that pool. For instance, if you want 10 combinations of 6 numbers each, that's a total of 60 numbers. But you want each of 1-12 represented evenly, so there will be 5 of each number. So start with an array containing 5 of each 1-12, and draw randomly from the array for each set of 6.
$pool = array();
for($i = 0; $i < 5; $i++)
for($x = 1; $x <= 12; $x++)
$pool[] = $x;
$result = array();
for($i = 0; $i < 10; $i++) {
$set = array();
for($x = 0; $x < 6; $x++) {
$key = array_rand($pool);
$set[] = $pool[$key];
unset($pool[$key]);
}
$result[] = $set;
}
// $result now contains 10 sets of 6 numbers each
Demo: http://ideone.com/NpO3h4
// how many numbers are in the set, starting from 1
$numbers = 12;
$set = array();
for ($i=1;$i>=$numbers;$i++)
{
array_push($set, $i);
}
// how many numbers in the subset
$count = 6;
$subSet = array();
while ($count > 0)
{
// get a random number from 1 to numbers in set
$rand=rand(0,$numbers-1);
array_push($subSet, $set[$rand]);
$count--;
}
// $subSet now contains a combination of 6 random numbers from 1 to 12
// keep refreshing
var_dump($subSet);
There you go, with explanations, is this what you wanted?
EDIT: I just noticed you said "the most effective way". This is not the most effective (in terms of memory used) way, but it's close.
I am going nuts here - hope you can help me figure this out! What is supposed to be very simple math is utterly confusing me.
$columns = 3;
$items = range(1,20);
$total = count($items);
$col1 = ???; $col2 = ???; $col3 = ???;
// $col1 must be an array of (1,2,3,4...)
// $col2 must be an array of (8,9,10,11...)
// $col3 must be an array of (15,16,17,18...)
COL1 COL2 COL3
1 8 15
2 9 16
3 10 17
4 11 18
5 12 19
6 13 20
7 14
The above is a visual example of what I am trying to achieve. Basically, for any given number of items in an array and for any given number of columns, how do I produce n number of arrays (equalling number of columns) that are as equal length as possible. If equal length is not possible (as in the example above), they must be spread out as evenly as possible and the last array must be the shortest.
Any guidance on how I construct $col1/2/3 in the example above would be much appreciated!
Please ignore the fact that I used range and integers to generate the array - this is just to simplify the example. Assume the array will contain strings.
Thanks for any help!
You do want to use array_chunk, but you need to calculate the chunk size yourself:
list($col1, $col2, $col3) = array_chunk($items, ceil($total / $columns));
I think you might want array_chunk
list($col1,$col2,$col3)=array_chunk($arrofstrings,$colcount);
$itemsInColumn = ceil($total / $columns);
$columns = 3;
$items = range(1, 20);
$rows = array_chunk($items, $columns);
$columns = array();
foreach ($rows as $row) {
for ($i = 0; $i < $columns; $i++) {
$columns[$i][] = $row[$i];
}
}
assuming I have $rows = 4, and $cols = 4;, How do I create a array with 16 elements in a spiral order, like:
1, 2, 3, 4,
12,13,14,5,
11,16,15,6,
10,9, 8, 7,
My solution is quite verbose, because the intent is for you to examine it and learn how it works.
<?php
/**
* Creates a 2D array with the given dimensions,
* whose elements are numbers in increasing order
* rendered in a 'spiral' pattern.
*/
function createSpiral($w, $h) {
if ($w <= 0 || $h <= 0) return FALSE;
$ar = Array();
$used = Array();
// Establish grid
for ($j = 0; $j < $h; $j++) {
$ar[$j] = Array();
for ($i = 0; $i < $w; $i++)
$ar[$j][$i] = '-';
}
// Establish 'used' grid that's one bigger in each dimension
for ($j = -1; $j <= $h; $j++) {
$used[$j] = Array();
for ($i = -1; $i <= $w; $i++) {
if ($i == -1 || $i == $w || $j == -1 || $j == $h)
$used[$j][$i] = true;
else
$used[$j][$i] = false;
}
}
// Fill grid with spiral
$n = 0;
$i = 0;
$j = 0;
$direction = 0; // 0 - left, 1 - down, 2 - right, 3 - up
while (true) {
$ar[$j][$i] = $n++;
$used[$j][$i] = true;
// Advance
switch ($direction) {
case 0:
$i++; // go right
if ($used[$j][$i]) { // got to RHS
$i--; $j++; // go back left, then down
$direction = 1;
}
break;
case 1:
$j++; // go down
if ($used[$j][$i]) { // got to bottom
$j--; $i--; // go back up, then left
$direction = 2;
}
break;
case 2:
$i--; // go left
if ($used[$j][$i]) { // got to LHS
$i++; $j--; // go back left, then up
$direction = 3;
}
break;
case 3:
$j--; // go up
if ($used[$j][$i]) { // got to top
$j++; $i++; // go back down, then right
$direction = 0;
}
break;
}
// if the new position is in use, we're done!
if ($used[$j][$i])
return $ar;
}
}
/**
* Assumes the input is a 2D array.
*/
function print2DGrid($array) {
foreach ($array as $row) {
foreach ($row as $col) {
print sprintf("% 2d ", $col);
}
print "\n";
}
}
$width = 12;
$height = 8;
print2DGrid(createSpiral($width, $height));
?>
Here it is in action, giving the following output:
0 1 2 3 4 5 6 7 8 9 10 11
35 36 37 38 39 40 41 42 43 44 45 12
34 63 64 65 66 67 68 69 70 71 46 13
33 62 83 84 85 86 87 88 89 72 47 14
32 61 82 95 94 93 92 91 90 73 48 15
31 60 81 80 79 78 77 76 75 74 49 16
30 59 58 57 56 55 54 53 52 51 50 17
29 28 27 26 25 24 23 22 21 20 19 18
Hope this helps.
Use a vector and boolean values. Iterate on the X axis to start with until you reach the end of the row. Set the value to true for each position as you traverse it. Anytime you reach a border or boolean true, turn right.
So on the first row your "vector" would change the X increment to zero and the Y increment to 1. Then you would check the value of the increment at each turn and accommodate the 4 scenarios.
This is the first way I thought of.
The second way would not use booleans, but would instead simply keep track of how many columns or rows are left in front of the cursor on its path, decreasing the X or Y remaining on each turn. The rest of the logic would remain the same.
When you reach the center, you will hit a loop where there are no more iterations possible. You can catch this by verifying the number of possibilities around the square, or simply counting down from N number of total squares from where you began, and stopping when the number hits zero.
You can use the above method for a square of any size.
The algorith is not very dificult. You have to iterate from 1 up to $rows*$cols. During the iteration, you have to calculate the position of the current number in the matrix ($x,$y). The first on will be in (1,1) of course. The following one will be ($x+1,$y) because you are heading east. So, the position of each number is base on the position of the previous one and the currect direction.
The tricky part of the algorith is to calculate the direction. But if you look at it, you will see that the direction changes clockwise each time you bump into a used cell, or you get out of bounds.
All in all, this is going to be ~30 lines of PHP code.
I hope this helps.
There is a similar challenge in PHP golf: http://www.phpgolf.org/challenge/Spiral. Somebody solved it in only 130 characters!