After watching my brother cheating in an iphone game like scrabble I was wondering what was the algotithm behing it.
Given some letters: A B C T E E
And SQL table full of correct words.
How would I create all combinations of letters for making afterwars a select like:
Select * from words where word IN ('A','AT',...), just to take from those combinations the ones that are correct ?¿
Another possible way could be a SQL table with every letter in a column for each word.
But afterwards the system should verify that any word form the select has more time the same letter given.
Ex:
c1 c2 c3 c4
t e e
a i r
This question is just for feeding curiosity, and learning witch algorithm it might be used in for creating all those combinations (with full and partial given letters) to check afterwards if they exist.
Thanks!
font: http://icon.cat/worder/wordsfinder
To find all possible valid word this are the following steps
Find all possible combination
Find each permutation for each word in the combination
Search Database for the words
List the words
Script
$tiles = array( "A", "B", "C", "T", "E", "E") ;
$words = array();
$set = powerSet($tiles,2);
$mysql = new mysqli("localhost","root","","word");
$sql = "SELECT id from dic WHERE word = '%s'" ;
foreach ($set as $key => $value)
{
$word = implode("", $value);
$wordPermutation = permute($word);
foreach($wordPermutation as $keyWord)
{
if(!in_array($keyWord, $words))
{
//if($result = $mysql->query(sprintf($sql,$keyWord)))
//{
//var_dump(sprintf($sql,$keyWord));
//if($result->num_rows > 0)
//{
$words[] = $keyWord ;
//}
//}
}
}
}
print_r($words);
Functions
function powerSet($in, $minLength = 1, $max = 10) {
$count = count ( $in );
$members = pow ( 2, $count );
$return = array ();
for($i = 0; $i < $members; $i ++) {
$b = sprintf ( "%0" . $count . "b", $i );
$out = array ();
for($j = 0; $j < $count; $j ++) {
if ($b {$j} == '1')
$out [] = $in [$j];
}
if (count ( $out ) >= $minLength && count ( $out ) <= $max) {
$return [] = $out;
}
}
return $return;
}
function permute($str) {
if (strlen($str) < 2) {
return array($str);
}
$permutations = array();
$tail = substr($str, 1);
foreach (permute($tail) as $permutation) {
$length = strlen($permutation);
for ($i = 0; $i <= $length; $i++) {
$permutations[] = substr($permutation, 0, $i) . $str[0] . substr($permutation, $i);
}
}
return $permutations;
}
Please note that i commented out the database verification section so that the demo can work
See Demo
http://codepad.viper-7.com/oG6E6w
I would try something like
WHERE (word like '%A%' and not word like '%A%A%')
AND (word like '%B%' and not word like '%B%B%')
and so on. But I'm sure there must be more professional solutions!
I finally got it working.
If someone is ever interested on making a self word generator, this is how I made it.
MySQL, a table with:
[id] , [Word]
a view for each length:
V1 = Select Word from TABLE where LENGTH(Word) = 1
V2 = Select Word from TABLE where LENGTH(Word) = 2
[...]
php side:
Using the functions of baba, I made an array where: array[2] are the combinations of letters that have a length of 2, and so on.
Finally all i had to do is a Select for each array to the view like
Select Word from V3 where Word like ('asd','dsa',....);
There must be a faster way, but with a less than a second (localhost) and word diccionary of 700K made its way.
A better way to achieve unscrambling is to use anagrams. So instead of having a library of all the possible words, use an associative array using the letters that make up the words as the index.
anagram['aer'] = ['are', 'ear', 'era']
To implement this, loop through all of your dictionary words and push each one into an array where the index is the letters of the word in alphabetical order.
for(var i = 0; i < dictionary.length; i++) {
//Loop through dictionary array
var str = words[i].split('').sort().join('');
//break apart the word and sort it alphabetically
if(!anagram[str]) {
//check if there is already an index with that same anagram
anagram[str] = [];
}
anagram[str].push(words[i]);
//Add the word to the anagram array
}
This way allows you to quickly index the library without going through thousands of possible permutations.
An example of this method in javascript: Word Unscrambler
Here is great article about World fastest scrabble program
You just should have some knowledge in Descrete Math(Word Automats). Hope it will help you :)
Related
I am trying to create a basic anagram generator in PHP.
The code below works with whole words, i. e. shuffling n times the chars of an input string ($word) and checking each shuffled string in a dictionary.
Whenever a match is found, the anagram is saved in an array ($out).
// here I read a text file, line by line, containing all the acceptable words
$dictionary = file('./docs/dictionary.txt',FILE_IGNORE_NEW_LINES);
//here I collect the word to make the anagram of
$word = mysql_real_escape_string(strtolower($_POST["word"]));
$times = 100;
// here I create an empty array where I can store all the anagrams of $word
$out = array();
for ($k = 0 ; $k < $times; $k++){
$string = str_shuffle($word);
if (in_array($string, $dictionary)){
array_push($out, $string);
}
}
$out = array_unique($out);
// now I print all the anagrams that have been stored in $out
foreach($out as $key => $value){
echo "I have found the anagram ".$value.".";
}
This trivial approach works using all the chars of the input string.
Now I want to search for partial anagrams too, removing randomly some chars from the initial string and matching these partial strings to the words in my dictionary.
I tried to proceed as follows, but I got lost in the process:
// here I create an empty array where I can later store the partial anagrams
$outpartial = array();
// Here I check how long the initial input string is
$length = strlen($string);
$num = 1;
// now I remove a char from the initial string in every loop and search for anagrams using the other chars which have been kept
while($num < $length){
$letters = $length - $num;
$removed = substr($string,-$num);
$kept = substr($string,0,$letters);
for ($i = 0 ; $i < $times; $i++){
$keptchars = str_shuffle($kept);
if (in_array($keptchars, $dictionary)){
array_push($outpartial, $keptchars);
}
}
$outpartial = array_unique($outpartial);
foreach($outpartial as $k => $v){
echo "Using the chars ".$kept." - ignoring ".$removed." - I have found the partial anagram ".$v.".";
}
$num++;
}
This part does not work as planned: the while loop above does not retrieve partial anagrams. It removes one char only from the initial string.
**You can try this out as per my example**
function funwithAnagrams($text){
for ($i = 0; $i < count($text); $i++) {
for($j = count($text) - 1; $j > $i; $j--) {
$sortedA = str_split(sort($text[$i]));
$sortedB = str_split(sort($text[$j]));
if($sortedA == $sortedB) {
// splice the array at index $j
array_splice($text, $j, 1);
}
}
}
return sort($text);
}
I received this challenge in an interview and I would like some help solving it.
Using the input string: PHP CODING TECH, produce the following output.
PCT
PHCT
PHPCT
PHPCOT
PHPCODT
PHPCODIT
PHPCODINT
PHPCODINGT
PHPCODINGTE
PHPCODINGTEC
PHPCODINGTECH
As I understand it, the logic is to explode the input string on the spaces and then in a loop structure, display the leading letter(s) of each word as a single string. During each iteration (after the first), the earliest incomplete word displays an additional leading letter.
This is my coding attempt:
$str = "PHP CODING TECH";
$a = explode(' ', $str);
for ($i=0; $i < count($a); $i++) {
for ($j=0; $j < strlen($a[$i]) ; $j++) {
//echo "<pre>";
$b[$i][$j] = explode(' ', $a[$i][$j]);
}
}
echo "<pre>";
print_r($b);
Code: (Demo) (or with DO-WHILE())
$input = "PHP CODING TECH";
$counters = array_fill_keys(explode(' ', $input), 1); // ['PHP' => 1, 'CODING' => 1, 'TECH' => 1]
$bump = false; // permit outer loop to run
while (!$bump) { // while still letters to output....
$bump = true; // stop after this iteration unless more letters to output
foreach ($counters as $word => &$len) { // $len is mod-by-ref for incrementing
echo substr($word, 0, $len); // echo letters using $len
if ($bump && isset($word[$len])) { // if no $len has been incremented during inner loop...
++$len; // increment this word's $len
$bump = false; // permit outer loop to run again
}
}
echo "\n"; // separate outputs
}
Output:
PCT
PHCT
PHPCT
PHPCOT
PHPCODT
PHPCODIT
PHPCODINT
PHPCODINGT
PHPCODINGTE
PHPCODINGTEC
PHPCODINGTECH
Explanation:
I am generating an array of words and initial lengths from the exploded input string. $bump is dual-purpose; it not only controls the outer loop, it also dictates the word which gets a length increase within the inner loop. $len is "modifiable by reference" so that any given word's $len value can be incremented and stored for use in the next iteration. isset() is used on $word[$len] to determine if the current word has more available letters to output in the next iteration; if not, the next word gets a chance (until all words are fully displayed).
And while I was waiting for this page to be reopened, I whacked together an alternative method:
$input = "PHP CODING TECH";
$words = explode(' ', $input); // generates: ['PHP', 'CODING', 'TECH']
$master = ''; // initialize for first offset and then concatenation
foreach ($words as $word) {
$offsets[] = strlen($master); // after loop, $offsets = [0, 3, 9]
$master .= $word; // after loop, $master = 'PHPCODINGTECH'
}
$master_offsets = range(0, strlen($master)); // generates: [0,1,2,3,4,5,6,7,8,9,10,11,12]
do {
foreach ($offsets as $offset) {
echo $master[$offset];
}
echo "\n";
} while ($master_offsets !== ($offsets = array_intersect($master_offsets, array_merge($offsets, [current(array_diff($master_offsets, $offsets))])))); // add first different offset from $master_offsets to $offsets until they are identical
I am new to PHP Development and finally with the help of SO I am able to write a program for finding word in a sentence with maximum specific character count.
Below is what I have tried:
<?php
// Program to find the word in a sentence with maximum specific character count
// Example: "O Romeo, Romeo, wherefore art thou Romeo?”
// Solution: wherefore
// Explanation: Because "e" came three times
$content = file_get_contents($argv[1]); // Reading content of file
$max = 0;
$arr = explode(" ", $content); // entire array of strings with file contents
for($x =0; $x<count($arr); $x++) // looping through entire array
{
$array[$x] = str_split($arr[$x]); // converting each of the string into array
}
for($x = 0; $x < count($arr); $x++)
{
$count = array_count_values($array[$x]);
$curr_max = max($count);
if($curr_max > $max)
{
$max = $curr_max;
$word = $arr[$x];
}
}
echo $word;
?>
Question: Since I am new to PHP development I don't know the optimization techniques. Is there anyway I can optimize this code? Also, Can I use regex to optimize this code further? Kindly guide.
I love coding this type of mini-challenges in the minimum lines of code :D. So here is my solution:
function wordsWithMaxCharFrequency($sentence) {
$words = preg_split('/\s+/', $sentence);
$maxCharsFrequency = array_map (function($word) {
return max(count_chars(strtolower($word)));
}, $words);
return array_map(function($index) use($words) {
return $words[$index];
}, array_keys($maxCharsFrequency, max($maxCharsFrequency)));
}
print_r(wordsWithMaxCharFrequency("eeee yyyy"));
//Output: Array ( [0] => eeee [1] => yyyy )
print_r(wordsWithMaxCharFrequency("xx llll x"));
//Output: Array ( [0] => llll )
Update1:
If you want to get only A-Za-z words use the following code:
$matches = [];
//a word is either followed by a space or end of input
preg_match_all('/([a-z]+)(?=\s|$)/i', $sentence, $matches);
$words = $matches[1];
Just a contribution that could inspire you :D!
Good Luck.
I am trying to use a for loop where it looks through an array and tries to make sure the same element is not used twice. For example, if $r or the random variable is assigned the number "3", my final array list will find the value associated with wordList[3] and add it. When the loop runs again, I don't want $r to use 3 again. Example output: 122234, where I would want something along the lines of 132456. Thanks in advance for the help.
for($i = 0; $i < $numWords; $i++){
$r = rand(0, $numWords);
$arrayTrack[$i] == $r;
$wordList[$r] = $finalArray[$i];
for($j = 0; $j <= $i; $j++){
if($arrayTrack[$j] == $r){
# Not sure what to do here. If $r is 9 once, I do not want it to be 9 again.
# I wrote this so that $r will never repeat itself
break;
}
}
Edited for clarity.
Pretty sure you are over complicating things. Try this, using array_rand():
$final_array = array();
$rand_keys = array_rand($wordList, $numWords);
foreach ($rand_keys as $key) {
$final_array[] = $wordList[$key];
}
If $numWords is 9, this will give you 9 random, unique elements from $wordList.
See demo
$range = range(0, $numWords - 1); // may be without -1, it depends..
shuffle($range);
for($i = 0; $i < $numWords; $i++) {
$r = array_pop($range);
$wordList[$r] = $finalArray[$i];
}
I do not know why you want it.. may be it is easier to shuffle($finalArray);??
So ideally "abcdefghi" in some random order.
$letters = str_split('abcdefghi');
shuffle($letters);
var_dump($letters);
ps: if you have hardcoded array $wordList and you want to take first $n elements of it and shuffle then (if this is not an associative array and you do not care about the keys)
$newArray = array_slice($wordList, 0, $n);
shuffle($newArray);
var_dump($newArray);
You can try array_rand and unset
For example:
$array = array('one','two','free','four','five');
$count = count($array);
for($i=0;$i<$count;$i++)
{
$b = array_rand($array);
echo $array[$b].'<br />';
unset($array[$b]);
}
after you have brought the data in the array, you purify and simultaneously removing the memory array
Ok... I have NO idea why you are trying to use so many variables with this.
I certainly, have no clue what you were using $arrayTrack for.
There is a very good chance I am mis-understanding all of this though.
<?php
$numWords=10;
$wordList=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');
$finalArray=array();
for ($i=0; $i<$numWords; $i++) {
start:
$r=rand(0,$numWords);
$wordChoice=$wordList[$r];
foreach ($finalArray as $word) {
if ($word==$wordChoice) goto start;
}
$finalArray[]=$wordChoice;
}
echo "Result: ".implode(',',$finalArray)."\n";
I want to generate test data for testing. What I need:
I will have a list of 30 names. For each name I need to fill in the start and finish position. The position is between 1 and 30.
So I wanted to use RAND() in php but I have a problem what I can't find a good way for.
Every position can only be used once. So if I press on a button "generate data" I want for all 30 names a start and finish position without duplicate position. So in the start i will use 1 - 30 and for the finish 1 - 30 as well.
I need this data in textfield. Is there a simple function for this? Or do you know how I can do this without having to fill in 60 textfields every test.
Something like this might get you started:
$names = array(/*...*/);
$l = count($names);
$rand = array();
for ($i = 0; $i<$l; $i++) {
$rand[] = $i;
}
shuffle($rand);
for ($i = 0; $i < $l; $i++) {
$names[$i]['start'] = $rand[$i];
}
Or:
$names = array(/*...*/);
shuffle($names);
for ($i = 0, $l = count($names); $i < $l; $i++) {
$names[$i]['start'] = $i;
}
I will use shuffle (twice),
something like
$arr = range(1, 30);
$first_numbers_position = shuffle($arr);
$second_numbers_position = shuffle($arr);
if you have already array with the names
you can use this function
Very simple shuffle function preserving key with value
function shuffle_assoc( $array )
{
$keys = array_keys( $array );
shuffle( $keys );
return array_merge( array_flip( $keys ) , $array );
}
If you don't need your code to actually generate the data dynamically you could try something like this site http://www.generatedata.com/