Move 7 random elements from one array to another - php

In a word game with 2 players I would like to give 7 random letters to each player in the PHP 5.3 function creating a new game:
$LETTERS = array( '*', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' );
$NUMBERS = array( 2, 10, 3, 5, 3, 5, 9, 2, 2, 8, 4, 6, 4, 5, 8, 10, 6, 6, 6, 5, 3, 1, 2, 1, 2, 1, 1 );
function createGame($dbh, $uid) {
global $LETTERS, $NUMBERS;
$letters = array();
$letters1 = array();
$letters2 = array();
for ($i = 0; $i < count($LETTERS); $i++) {
$letter = $LETTERS[$i];
$number = $NUMBERS[$i];
for ($n = 0; $n < $number; $n++) {
array_push($letters, $letter);
}
}
for ($i = 0; $i < 7; $i++) {
/* TODO move random letter from $letters to $letter1 */
/* TODO move random letter from $letters to $letter2 */
}
$sth = $dbh->prepare('insert into games (player1, stamp1, stamp2, letters1, letters2, letters, board) values (?, unix_timestamp(now()), 0, ?, ?, ?, space(225))');
$sth->execute(array($uid, join('', $letters1), join('', $letters2), join('', $letters)));
return $dbh->lastInsertId();
}
I know that array_rand() can be used to select a random element from an array.
But how to use it here in a most effective way to move a letter from the $letters array?
UPDATE:
I've tried the following, but the first 7 letters are not removed from the beginning of the source array, why?
shuffle($letters);
$letters1 = array_slice($letters, 0, 7);
$letters2 = array_slice($letters, 0, 7);

I would shuffle the array of letters and remove the first element of the shuffeld array to get one random letter.
shuffle($letters); // Mix alle array elements
for ($i = 0; $i < 7; $i++) {
$letters1[] = array_shift($letters); // get first array element, removing it from $letters
$letters2[] = array_shift($letters); // get first array element, removing it from $letters
}

You can use array_diff:
$letters = array_diff($letters, $letter1);
$letters = array_diff($letters, $letter2);

Related

Return multiple value of array in PHP

$array = [
'H',
'E',
'L',
'L',
'O',
];
This is my array. I want to print this array like this :
H
HE
HEL
HELL
HELLO
I want to do this dynamically .
For example, write a function to receive the array and do this with the array. Any array is possible.
You can use nested for loops to print the pattern as follows:
$array = [
'H',
'E',
'L',
'L',
'O',
];
echo printPattern($array);
function printPattern($array){
$ret = '';
for($i = 0; $i < count($array); $i++){
$str = '';
for($j = 0; $j < $i+1; $j++){
$str .= $array[$j];
}
$ret .= $str.'<br>';
}
return $ret;
}
Convert the array to a string, then iterate over the length of the string (either count the array or use strlen(), they'll be the same) and use substr() to get the given length, which will be the same as the number of the iteration.
$array = [
'H',
'E',
'L',
'L',
'O',
];
$string = implode("", $array);
for ($i = 0; $i <= count($array); $i++) {
echo substr($string, 0, $i)."\n";
}
Live demo at https://3v4l.org/ibXpK

Create pairs with 2 array, so that there is no repeated pairs?

I'm trying to create a script to create pairs from 2 different arrays. For example I have two array given below:
<?php
//Array 1
$arr1 = array('A', 'B', 'C', 'D');
//Array 2
$arr2 = array('X', 'Y', 'Z');
And I need output in such a manner so that it match with each element and didn't repeat pair and sequence also. Here is expected output:
$output = array(
0 => array('A', 'X'),
1 => array('B', 'Y'),
2 => array('C', 'Z'),
3 => array('D', 'X'),
4 => array('A', 'Y'),
5 => array('B', 'Z'),
6 => array('C', 'X'),
7 => array('D', 'Y'),
8 => array('A', 'Z'),
9 => array('B', 'X'),
10 => array('C', 'Y'),
11 => array('D', 'Z')
)
**Note: 2 arrays can differ with number of count and values.
This is Cartesian Product. Could be achieved with
//Array 1
$arr1 = array('A', 'B', 'C', 'D');
//Array 2
$arr2 = array('X', 'Y', 'Z');
$output = array();
foreach($arr1 as $i1){
foreach ($arr2 as $i2) {
$output[] = array($i1, $i2);
}
}
echo json_encode($output);
If you want the output to be in the same order as you have mentioned above, following should do that.
$newoutput = array();
$x = 0;
$y = 0;
for($i = 1; $i <= (count($arr1) * count($arr2)); $i++){
$newoutput[] = array($arr1[($x % count($arr1))], $arr2[($y % count($arr2))]);
$x++;
$y++;
}
echo "<br />", json_encode($newoutput);
Output however, is a different order of the same output as previous.
EDIT
The second works only when (count($arrX) % count($arrY)) > 0.
I don't think there is a built in support for that.
You need to loop the arrays nested and build a result array.
$arr1 = array('A', 'B', 'C', 'D');
$arr2 = array('X', 'Y', 'Z');
foreach($arr1 as $item1){
foreach($arr2 as $item2){
$res[] = [$item1, $item2];
}
}
var_dump($res);
https://3v4l.org/CdE8Q
Try This out (This will sort out the same pair if found):
//Array 1
$arr1 = array('A', 'B', 'C', 'D', 'A', 'E'); // Same element will be sort out in pair
//Array 2
$arr2 = array('X', 'Y', 'Z' , 'X', 'Y', 'X'); // Same element will be sort out in pair
$output = array();
$used_pair = array(); // Keeping used pair
$i = 1;
foreach ($arr1 as $each1) {
foreach ($arr2 as $each2) {
if (!in_array($each1.$each2, $used_pair)) {
$output[] = array($each1, $each2);
$used_pair[] = $each1 . $each2;
}
}
}
print_r($used_pair); // array with pair string
print_r($output); // array with pair array
this is an example that ouputs unique values in the same order :
online eval : https://3v4l.org/H2pad
<?php
function cartesian(array $x,array $y): array
{
$result = [];
$size = count($x) * count($y);
$posX = 0;
$posY = 0;
for($i = 0; $i < $size; $i++) {
if (!isset($x[$posX])) {
$posX = 0;
} elseif(!isset($y[$posY])) {
$posY = 0;
}
$result[] = [$x[$posX],$y[$posY]];
$posX++; $posY++;
}
return $result;
}
$x = array('A', 'B', 'C', 'D');
$y = array('X', 'Y', 'Z');
print_r(cartesian($x,$y));
( tbh, it took me a lot of rubber duck debugging )

Merge arrays with control of array position

I have two random arrays merged, everything displaying/functioning beautifully. The one stuck I have is this:
When I merge the two arrays together I need to make sure that every 3 item comes from array2.
array1 (a,b,c,d,e,f,g,h,i,j,k)
array2 (a1,a2,a3,a4)
My desired outcome:
d k c a1 j i g a2 etc.
What I have done so far:
function randomize_blocks($arr, $num = 1) {
shuffle($arr);
$r = array();
for ($i = 0; $i < $num; $i++) {
$r[] = $arr[$i];
}
return $num == 1 ? $r[0] : $r;
}
//gather donor blocks into an array
$donorBlocks = array($blockA, $blockB, $blockC, $blockD, $blockE, $blockF,
$blockG, $blockH, $blockI, $blockJ, $blockK, $blockL, $blockM, $blockN,
$blockO);
//gather value blocks into an array
$valueBlocks = array($valueA, $valueB, $valueC, $valueD);
//shake that shuffler real hard! DT
$shuffled_valueBlocks = randomize_blocks($valueBlocks, 4);
$shuffled_donorBlocks = randomize_blocks($donorBlocks, 15);
//combine our shuffled arrays together
$combinedArrays = array_merge($shuffled_valueBlocks, $shuffled_donorBlocks);
//shuffle them all together!
$shuffled_blocks = randomize_blocks($combinedArrays, 19);
//display bocks on page
foreach ($combinedArrays as $key => $value) {
echo $value;
}
What is the best way to accomplish this?
Here is a way with array_splice to modify the longest of the two arrays into the desired result:
$a = ['a', 'b', 'c', 'd'];
$b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
foreach ($a as $i => $v)
array_splice($b, $i*4+3, 0, [$v]);
$b will be:
[1, 2, 3, 'a', 4, 5, 6, 'b', 7, 8, 9, 'c', 10, 11, 12, 'd', 13, 14, 15]
What about something like this?
$a1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'];
$a2 = ['a1', 'a2', 'a3', 'a4'];
$a = [];
shuffle($a1);
foreach ($a1 as $k => $v) {
$a[] = $v;
if (($k + 1) % 3 === 0 && $a2) $a[] = array_shift($a2);
}
This is based on the assumption that you want both arrays shuffled as well as placed in your desired pattern:
$array_one = array('a','b','c','d','e','f','g','h','i','j','k');
$array_two = array('a1','a2','a3','a4');
function merge_random_interval($array_one = array(), $array_two = array(), $interval = 3) {
$return_array = array();
// Shuffle the arrays - that seems to be important?
shuffle($array_one);
shuffle($array_two);
// Go through the first array
$array_two_index = 0;
for ($i = 0; $i < count($array_one); $i++) {
// Every $interval add a value from the second array
if ($i > 0 && $i % $interval == 0) {
// Make sure there is a value in the second array
if (isset($array_two[$array_two_index])) {
$return_array[] = $array_two[$array_two_index];
$array_two_index++;
}
}
$return_array[] = $array_one[$i];
}
// You may want to check if $array_two has more values that weren't added?
// Compare $array_two_index against count($array_two)
return $return_array;
}
$result_array = merge_random_interval($array_one, $array_two, 3);
echo implode(' ', $result_array); // g d c a1 h i j a4 b e a a2 k f

Chunk and transpose a flat array into rows with a specific number of columns

An array of values are provided in the order they should appear in columns. For example, the second value in the array should be displayed on a webpage beneath the first instead of on its right.
Task: Reorder the array so that the values are in the order they will be output in html. The data for the first row must be first in the output.
Example inputs:
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
Example output:
[['A', 'E'], ['B','F'], ...]
Use array_chunk() to break the array up in to $cols:
$chunks = array_chunk($array, ceil(count($array) / $cols));
Which would give you:
array(array('A', 'B', 'C', 'D'), array('E', 'F', 'G'));
Then combine the values from each array where the keys match.
array_unshift($chunks, null);
$chunks = call_user_func_array('array_map', $chunks);
// array(array('A', 'E'), array('B', 'F'), array('C', 'G'), array('D', NULL))
Here's an example
You need to count offset and then iterate over an array:
$input = array('A', 'B', 'C', 'D', 'E', 'F', 'G');
$cols = 2;
$itemsCount = count($input);
$offset = ceil($itemsCount/$cols);
$result = array();
for($i = 0; $i < $itemsCount; ++$i) {
if (isset($input[$i]) && isset($input[$i + $offset])) {
$result[] = array($input[$i], $input[$i + $offset]);
}
}
The modern functional equivalent of #billyonecan's approach uses the spread operator to transpose the data after it has been "chunked" to the correct size. (Demo)
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
var_export(
array_map(
null,
...array_chunk($input, ceil(count($input) / 2))
)
);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D', null]]
A classic loop alternative using a modulus calculation is also attractive because it doesn't generate the extra null element in the final set when the division doesn't come out even: (Demo)
$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
$cols = 2;
$rows = ceil(count($input) / $cols);
$result = [];
foreach ($input as $i => $value) {
$result[$i % $rows][] = $value;
}
var_export($result);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D']]
On this related topic, to more simply chunk and transpose with a finite number of rows, use the following: (Demo)
$rows = 2;
var_export(
array_map(
null,
...array_chunk($input, $rows)
)
);

php how to cut array and add other charactor to it

I have an array like :
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
[5] => f
[6] => g
[7] => h
)
And I want add semicolon(;) every 3 index value and it's read from end of array that result is string like "ab;cde;fgh";
Here's a fun, and kind of obnoxious, one-liner:
$str = ltrim(strrev(chunk_split(implode(array_reverse($arr)), 3, ';')), ';');
Example:
$arr = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
$str = ltrim(strrev(chunk_split(implode(array_reverse($arr)), 3, ';')), ';');
echo $str; //ab;cde;fgh
// More sample output based on different input arrays:
$arr = array('a', 'b', 'c', 'd', 'e'); //ab;cde
$arr = array('a', 'b', 'c', 'd', 'e', 'f'); //abc;def
$arr = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'); //ab;cde;fgh;ijk
See demo
Its an odd way, but since you want it reversed you may need to use some function here:
$array = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
$array = array_reverse($array); // reverse it
$array = array_chunk($array, 3); // cut by threes
$string = '';
foreach ($array as $value) {
$string .= implode($value); // glue them
if(count($value) == 3) { // if still three, add a semi
$string .= ';';
}
}
$string = strrev($string); // then reverse them again
echo $string; // ab;cde;fgh
This works... there's a couple different ways to do this. This was the quickest way off the top of my head without using a second array.
$vars = array("a","b","c","d","e","f","g","h");
print_r(insert_char($vars));
function insert_char($Array, $Delimeter=";", $Count=3) {
for ($i = sizeOf($Array) - $Count; $i > 0; $i -= $Count)
array_splice($Array, $i, 0, $Delimeter);
return implode($Array);
}
Result
ab;cde;fgh
Here's my solution, although it feels inefficient it is pretty clear:
<?php
$myarr=Array('a','b','c','d','e','f','g','h');
$newarr=Array();
$arrsize = sizeof($myarr);
for ($x = 0, $i = 0; $x < $arrsize; $x++, $i++) {
$newarr[$i] = $myarr[$arrsize - $x - 1];
if (($arrsize - $x) % 3 == 0) {
$i++;
$newarr[$i] = ";";
}
}
$newarr = array_reverse($newarr);
print_r($newarr);
?>
Just traversing it from backward and joining the string in reverse too gives that result.
$vars = array("a","b","c","d","e","f","g");
$c = 0; $s = "";
for ($i = sizeof($vars)-1; $i >= 0; $i--)
{
$c++;
$s = $vars[$i].$s;
if ($c == 3) { $c = 0; $s = ";".$s; }
}
echo $s;

Categories