array_rand wihout repeating in php - php

I'm working with my code that will allow the user to input a word and each letter of the word will give a meaning.
Example: User inputted a text "APPLE".
Output:
A - arc
P - priest
P - president
L - lion
E - escape
The meaning of every letter will be in array..
I already have my code here but the meaning are repeated.
Example:
A - **Arrow**
L - Love
A - **Arrow**
S - Soul
Here's my code
<?php
$chars = str_split("APPLE");
foreach($chars as $char){
if (substr($char, 0, 1) === 'A')
{
$meaning = array("Angel","Ancient","Arrow");
echo $meaning[array_rand($meaning)];
}
}
?>

You could unset it temporarily inside the loop so that you won't get dups. Example:
$chars = str_split("APPLE");
$words = array(
// its up to you what words you want to map
'A' => array("Angel","Ancient","Arrow"),
'E' => array('Elephat', 'Eardrum'),
'L' => array('Level', 'Laravel', 'Love'),
'S' => array('Sweet', 'Spicy', 'Savy'),
'P' => array('Powerful', 'Predictable', 'Pass', 'piss')
);
foreach($chars as $char){
$random_key = array_rand($words[$char]); // get random key
$key = $words[$char][$random_key]; // get the word
unset($words[$char][$random_key]); // unset it so that it will never be repeated
echo "$char - $key <br/>";
}

You could save a "cache" array of previously used terms. Example:
<?php
$chars = str_split("APPLE");
$used_terms = array();
foreach($chars as $char){
if (substr($char, 0, 1) === 'A') {
$meaning = array("Angel","Ancient","Arrow");
do {
$term = $meaning[array_rand($meaning)];
} while (in_array($term, $used_terms));
$used_terms[] = $term;
echo $term;
}
}
?>

Related

Reverse the position of all letters in each word of a string that may contain multibyte characters

I want to write an application that reverses all the words of input text, but all non-letter symbols should stay in the same places.
What I already have:
function reverse($string)
{
$reversedString = '';
for ($position = strlen($string); $position > 0; $position--) {
$reversedString .= $string[$position - 1]; //.= - concatenation assignment, привязывает b to a;
}
return $reversedString;
}
$name = 'ab1 ab2';
print_r(reverse($name)); //output: 2ba 1ba;
Now I want to add for this function some conclusion, that this function also will reverse text, but without affecting any special characters? It means, that all non-letter symbols should stay in the same places.
Here are some sample input strings and my desired output:
ab1 ab2 becomes ba1 ba2
qwerty uiop becomes ytrewq poiu
q1werty% uio*pl becomes y1trewq% lpo*iu
Привет, мир! becomes тевирП, рим!
Hello, dear #user_non-name, congrats100 points*#! becomes olleH, raed #eman_non-resu, stragnoc100 stniop*#!
My actual project will be using cyrillic characters, so answers need to accommodate multibyte/unicode letters.
Maybe I should use array and '''ctype_alpha''' function?
If I understood your problem correctly, then the solution below will probably be able to help you. This solution is not neat and not optimal, but it seems to work:
//mb_internal_encoding('UTF-8') && mb_regex_encoding('UTF-8'); // <-- if you need
function reverse(string $string): string
{
$reversedStrings = explode(' ', $string);
$patternRegexp = '^[a-zA-Zа-яА-Я]+$';
foreach ($reversedStrings as &$word) {
$chars = mb_str_split($word, 1);
$filteredChars = [];
foreach (array_reverse($chars) as $char) {
if (mb_ereg_match($patternRegexp, $char)) {
$filteredChars[] = $char;
}
}
foreach ($chars as &$char) {
if (!mb_ereg_match($patternRegexp, $char)) {
continue;
}
$char = array_shift($filteredChars);
}
$word = implode('', $chars);
}
return implode(' ', $reversedStrings);
}
$test1 = 'ab1 ab2 ab! ab. Hello!789World! qwe4rty5';
print_r(reverse($test1)."\n"); // => "ba1 ba2 ba! ba. dlroW!789olleH! ytr4ewq5";
$test2 = 'Привет, мир!';
print_r(reverse($test2)."\n"); // => "тевирП, рим!";
In the example, non-alphabetic characters do not change their position within the word. Example: "Hello!789World! qwe4rty5" => "dlroW!789olleH! ytr4ewq5".
In an attempt to optimize for performance by reducing total function calls and reducing the number of preg_ calls, I'll demonstrate a technique with nested loops.
Explode on spaces
Separate letters from non-letters while accommodating multi-byte characters
Iterate the matches array which contains 1 character per row (separated so that letters (movable characters) are in the [1] element and non-letters (immovable characters are in the [2] element.
While traversing from left to right along the array of characters, if an immovable character is encountered, immediately append it to the current output string; if movable, seek out the latest unused movable character from the end of the matches array.
Code: (Demo) (variation without isset() calls)
$names = [
'ab1 ab2', // becomes ba1 ba2
'qwerty uçop', // becomes ytrewq poçu
'q1werty% uio*pl', // becomes y1trewq% lpo*iu
'Привет, мир!', // becomes тевирП, рим!
'Hello, dear #user_non-name, congrats100 points*#!', // olleH, raed #eman_non-resu, stragnoc100 stniop*#!
'a' // remains a
];
function swapLetterPositions($string): string {
$result = [];
foreach (explode(' ', $string) as $index => $word) {
$result[$index] = '';
$count = preg_match_all('/(\pL)|(.)/u', $word, $m, PREG_SET_ORDER);
for ($i = 0, $j = $count; $i < $count; ++$i) {
if (isset($m[$i][2])) { // immovable
$result[$index] .= $m[$i][2]; // append to string
} else { // movable from front
while (--$j >= 0) { // decrement $j and ensure that it represents an element index
if (!isset($m[$j][2])) { // movable from back
$result[$index] .= $m[$j][1]; // append to string
break;
}
}
}
}
}
return implode(' ', $result);
}
foreach ($names as $name) {
echo "\"$name\" => \"" . swapLetterPositions($name) . "\"\n---\n";
}
Output:
"ab1 ab2" => "ba1 ba2"
---
"qwerty uçop" => "ytrewq poçu"
---
"q1werty% uio*pl" => "y1trewq% lpo*iu"
---
"Привет, мир!" => "тевирП, рим!"
---
"Hello, dear #user_non-name, congrats100 points*#!" => "olleH, raed #eman_non-resu, stargnoc100 stniop*#!"
---
"a" => "a"
---

PHP: Sort an array in order of letters in another array

I'm making a little hangman game, and I want to sort the guesses the person makes in order of the actual word; Here is my code:
$word = "peach";
$_SESSION['letters'] = str_split($word);
ˆThat is where I make the word into an array, and I want when correct letters are added to an array, that they be sorted in order of the word. Is there any way I could do this, or another way I could write it? Thank you for your help.
I misunderstood. Try this:
<?php
$guess = 'reach';
$guess_array = str_split($guess);
$word = 'peach';
$word_array = str_split($word);
$result = '';
foreach($word_array as $letter)
{
if(in_array($letter, $guess_array))
{
$result .= $letter;
}
else
{
$result .= '_';
}
}
echo($result);
// outputs: "_each"
?>
I think you're probably going about it wrong. You don't need to sort the array. Just set an array with the letters in the word and another array with the guesses. Then loop over the array with the word and see if the respective value is found in the guesses array. Something like this:
$word = "rumplestiltskin";
$letters = str_split($word);
// Assume the user gets at least 6 guesses:
$guesses = array('r', 's', 't', 'l', 'n', 'e');
// Display the letters guessed correctly
foreach ($letters as $letter) {
// Set both to lower case just in case
if (in_array(strtolower($letter), array_map('strtolower', $guesses)) === true) {
echo " $letter ";
}
else {
echo " _ ";
}
}
// Produces: r _ _ _ l e s t _ l t s _ _ n

Search associative array and print corresponding value in php

I have a dictionary like
UUU F
UUC F
CUU L
CUC L
UUA L
CUA L
UUG L
CUG L
AUU I
AUC I
AUA I
GUU V
GUC V
GUG V
GUA V
So Given a string I want to replace every 3 chars its respective char
I was thinking on using associative arrays:
$d = array();
$d['UUU']='F';
$d['UUC']='F';
$d['UUA']='L';
$d['CUU']='L';
$d['GUC']='V';
$d['GUG']='V';
$d['GUA']='V';
$d['UUG']='L';
$d['CUG']='L';
$s = "UUAGUAUUG";
$temp="";
for($i=0; $i<strlen($s)+1; $i++){
$temp .= $s[$i];
if($i%3==0){
echo $temp;
echo array_search($temp, $d);
$temp = "";
}
}
It should output LVL but have no success
Use str_split:
$s = 'UUAGUAUUG';
$split = str_split($s,3);
$translated = array();
foreach ($split as $bases) {
/**
* # supresses warnings if the array index doesn't exist
*/
$translated []= #$d[$bases];
}
echo join('',$translated);
I think this might work:
$temp = implode(array_map(function($a) { return $d[$a];}, str_split($s, 3)));
The basic solution is:
<?php
$dict = array(
'UUU' => 'F',
'UUC' => 'F',
'UUA' => 'L',
'CUU' => 'L',
'GUC' => 'V',
'GUG' => 'V',
'GUA' => 'V',
'UUG' => 'L',
'CUG' => 'L'
);
$before = "UUAGUAUUG";
$after = strtr($before, $dict);
Although you may be able to write a faster version that takes into account that you are replacing every three letters.
And I'm not 100% sure this will even work, given what kind of combinations can overlap over the 3-char barrier. Which leaves you with this rotten solution:
$after = str_replace('-', '',
strtr(preg_replace('/[A-Z]{3}/', '\0-', $before), $dict));
Seriously, don't try this at home. ;)
You're testing at the wrong time.
Change $i%3 == 0 to $i%3 == 2.
The reason here is that you have added to your temporary string first. That means you immediately check a string of length 1 ("U") and then clear it. Then you go around for another 3 times and you get "UAG", followed by "UAU". Neither of these are in your array.
What I don't understand is that you output the value of $temp each time this happens, so you should have picked up on this.
Change your for loop to this:
for($i=0; $i<strlen($s)+1; $i++){
$temp .= $s[$i];
if(($i+1)%3==0){
echo $d[$temp];
$temp = "";
}
}
Your i value starts from 0. And array_values does not give the expected answer.

Generating random values in PHP

I am quite a newbie when it comes to php and i wanted to try something but i have absolutely no idea how should i do this.. To be honest i am not sure if can explain this to you very clearly either.. Lets get started..
I have couple of letters for example a, b, c, d and e..
and for each one of them i have couples of two-charactered values like this:
a -> fg, dz, gc, bg
b -> zt, hg, oq, vg, gb
c -> lt, pr, cs, sh, pr
d -> kt, nt, as, pr
e -> zd, ke, cg, sq, mo, ld
Here comes the question:
I would like to get a random value for each time for example: dcbae
and for this the ultimate output should be something like this: ntshztdzld or asltvggcmo..
(After generating a random string with the charachters above (between a-e), i should generate another string that contains random values those are related with the each character..
This is not a homework or something similar.
Thanks in advance for your understanding..
Well, you would first create a map:
$map = Array(
"a" => Array("fg","dz","gc","bg"),
"b" => Array("zt","hg","oq","vg","gb"),
"c" => Array("lt","pr","cs","sh","pr"),
"d" => Array("kt","nt","as","pr"),
"e" => Array("zd","ke","cg","sq","mo","ld")
);
I notice that you have the same pair "pr" several times - if you want this encoding to be reversible, avoid duplicates.
Anyway, once you have that it's easy enough to loop through your input string and get a random output:
$input = "dcbae";
$len = strlen($input);
$output = "";
for( $i=0; $i<$len; $i++) {
$entry = &$map[$input[$i]];
if( isset($entry)) $output .= $entry[mt_rand(0,count($entry)-1)];
else $output .= "??";
}
$output is the result.
<?php
// Setup matching values
$encpairs[ 'a' ] = array( 'fg', 'dz', 'gc', 'bg' );
$encpairs[ 'b' ] = array( 'zt', 'hg', 'oq', 'vg', 'gb' );
$encpairs[ 'c' ] = array( 'lt', 'pr', 'cs', 'sh', 'pr' );
// etc. etc.
// Define input string
$my_string = 'abc';
// To randomly build input string
$my_string = '';
$last_key = '';
$key = '';
$keys = array_keys( $encpairs );
$ttl_keys = count( $keys ) -1;
// Generate the input string at random; change "5" to length you desire
for ( $j=0; $j < 5; $j++ ){
// Randomly select a key from $encpairs array (giving you one letter at random)
// The while loop ensures no two letters are used consecutively
while ( $key == $last_key ) {
$key =$keys[ rand(0, $ttl_keys ) ];
}
$last_key = $key;
$my_string .= $key;
}
// Determine input string length
$length = strlen( $my_string );
// Loop through each letter
$output = '';
for( $i=0; $i < $length; $i++ ){
shuffle( $encpairs[ $my_string[$i] ] );
$output.= $encpairs[ $my_string[$i] ][0]; // Added [0]
}
Start by initializing a second string outside of the loop. Convert your original string (to be encrypted) into an array, and then loop through the whole array and append to the second string.
So you get
$splitstr=str_split($original);
$final_string="";
$map=Array(/**/);
foreach($splitstr as $char)
{
$final_string.=$map[$char][rand(0,count($map[$char])-1)];
}
return $final_string;

"Unfolding" a String

I have a set of strings, each string has a variable number of segments separated by pipes (|), e.g.:
$string = 'abc|b|ac';
Each segment with more than one char should be expanded into all the possible one char combinations, for 3 segments the following "algorithm" works wonderfully:
$result = array();
$string = explode('|', 'abc|b|ac');
foreach (str_split($string[0]) as $i)
{
foreach (str_split($string[1]) as $j)
{
foreach (str_split($string[2]) as $k)
{
$result[] = implode('|', array($i, $j, $k)); // more...
}
}
}
print_r($result);
Output:
$result = array('a|b|a', 'a|b|c', 'b|b|a', 'b|b|c', 'c|b|a', 'c|b|c');
Obviously, for more than 3 segments the code starts to get extremely messy, since I need to add (and check) more and more inner loops. I tried coming up with a dynamic solution but I can't figure out how to generate the correct combination for all the segments (individually and as a whole). I also looked at some combinatorics source code but I'm unable to combine the different combinations of my segments.
I appreciate if anyone can point me in the right direction.
Recursion to the rescue (you might need to tweak a bit to cover edge cases, but it works):
function explodinator($str) {
$segments = explode('|', $str);
$pieces = array_map('str_split', $segments);
return e_helper($pieces);
}
function e_helper($pieces) {
if (count($pieces) == 1)
return $pieces[0];
$first = array_shift($pieces);
$subs = e_helper($pieces);
foreach($first as $char) {
foreach ($subs as $sub) {
$result[] = $char . '|' . $sub;
}
}
return $result;
}
print_r(explodinator('abc|b|ac'));
Outputs:
Array
(
[0] => a|b|a
[1] => a|b|c
[2] => b|b|a
[3] => b|b|c
[4] => c|b|a
[5] => c|b|c
)
As seen on ideone.
This looks like a job for recursive programming! :P
I first looked at this and thought it was going to be a on-liner (and probably is in perl).
There are other non-recursive ways (enumerate all combinations of indexes into segments then loop through, for example) but I think this is more interesting, and probably 'better'.
$str = explode('|', 'abc|b|ac');
$strlen = count( $str );
$results = array();
function splitAndForeach( $bchar , $oldindex, $tempthread) {
global $strlen, $str, $results;
$temp = $tempthread;
$newindex = $oldindex + 1;
if ( $bchar != '') { array_push($temp, $bchar ); }
if ( $newindex <= $strlen ){
print "starting foreach loop on string '".$str[$newindex-1]."' \n";
foreach(str_split( $str[$newindex - 1] ) as $c) {
print "Going into next depth ($newindex) of recursion on char $c \n";
splitAndForeach( $c , $newindex, $temp);
}
} else {
$found = implode('|', $temp);
print "Array length (max recursion depth) reached, result: $found \n";
array_push( $results, $found );
$temp = $tempthread;
$index = 0;
print "***************** Reset index to 0 *****************\n\n";
}
}
splitAndForeach('', 0, array() );
print "your results: \n";
print_r($results);
You could have two arrays: the alternatives and a current counter.
$alternatives = array(array('a', 'b', 'c'), array('b'), array('a', 'c'));
$counter = array(0, 0, 0);
Then, in a loop, you increment the "last digit" of the counter, and if that is equal to the number of alternatives for that position, you reset that "digit" to zero and increment the "digit" left to it. This works just like counting with decimal numbers.
The string for each step is built by concatenating the $alternatives[$i][$counter[$i]] for each digit.
You are finished when the "first digit" becomes as large as the number of alternatives for that digit.
Example: for the above variables, the counter would get the following values in the steps:
0,0,0
0,0,1
1,0,0 (overflow in the last two digit)
1,0,1
2,0,0 (overflow in the last two digits)
2,0,1
3,0,0 (finished, since the first "digit" has only 3 alternatives)

Categories