Php apply function in array if next entry is integer (Concatenate a valid FEN string) - php

Trying to build a valid FEN string.
Given this 8*8 array example, symbolizing a checker board, ("1" are empty squares):
$checkerboard = [["r","n","b","q","k","b","n","r"],["p","p","p","p","p","p","p","p"],["1","1","1","1","1","1","1","1"],["1","1","1","1","1","1","1","1"],["1","1","1","1","P","1","1","1"],["1","1","1","1","1","1","1","1"],["P","P","P","P","1","P","P","P"],["R","N","B","Q","K","B","N","R"]]
In situ, this is the position:
The valid result I am looking for is:
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR
And by now my output is:
rnbqkbnr/pppppppp/11111111/11111111/1111P111/11111111/PPPP1PPP/RNBQKBNR
Obviously, any integer entry in the array should be sum to the next, only if the next entry is an integer, and if so the next entry should be discarded till the end.
By iterating the array, I am not sure how to apply something like array_walk() or array_map() here in a simple way. Maybe a simple string operation is enough?
$FEN = "";
for ($i = 0;$i < 8;$i++){
for ($j = 0;$j < 8;$j++){
if ($checkerboard[$i][$j] === "1"){
if ($checkerboard[$i][$j + 1] === "1"){
/* How to iterate till the end */
$FEN .= (int)$checkerboard[$i][$j] + (int)$checkerboard[$i][$j+1];
}
} else {
$FEN .= $checkerboard[$i][$j];
}
}
$FEN .= "/";
}
Any insights?
Example online: https://3v4l.org/tuqqo

$checkerboard = [["r","n","b","q","k","b","n","r"],["p","p","p","p","p","p","p","p"],["1","1","1","1","1","1","1","1"],["1","1","1","1","1","1","1","1"],["1","1","1","1","P","1","1","1"],["1","1","1","1","1","1","1","1"],["P","P","P","P","1","P","P","P"],["R","N","B","Q","K","B","N","R"]];
$parts = array();
foreach ($checkerboard as $innerArray) {
$num = null;
$str = '';
foreach($innerArray as $innerval){
if(is_numeric($innerval)){
$num += (int) $innerval;
}
else{
if(!is_null($num)){
$str .=$num;
$num = null;
}
$str .=$innerval;
}
}
if(!is_null($num)){
$str .=$num;
}
array_push($parts,$str);
}
$result = implode('/',$parts);
above code will generate required output and store it on the $result.

Related

Get nearest sequence result from an array and given pattern with PHP

I am trying to get year and month from the letters using established sequence. I know that the sequence is based on the following letters:
$letters = array('B','C','D','F','G','H','J','K','L','M','N','P','R','S','T','V','W','X','Y','Z');
It started with 0000BBB and when it reaches 9999 it becomes BBC, BBD etc. So I don't need the numbers in that case and only letters as I have a list of last registered sequence per year and month like this:
$plates = array(
array('2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'),
array('2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'),
array('2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'),
array('2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'),
array('2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'),
array('2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'),
array('2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'),
array('2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'),
array('2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'),
array('2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'),
array('2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'),
array('2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'),
array('2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'),
array('2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'),
array('2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'),
array('2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'),
array('2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'),
array('2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'),
array('2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR')
);
That means that array index 0 is the year and from 1 to 12 would be month. I am trying to find a match but then realize I can not search exact value and need to look for nearest value based on letters.
I would deeply appreciate if anyone could direct me in right direction what would be the best method of doing this.
This is a test so far but this will just return an exact match, I would have to search any possible letters such as KHW as an example that would have to match as nearest value to KHX
foreach ($plates as $key => $val) {
$search = array_search('KHX', $plates[$key]);
if($search){
echo $search."\n";
echo $plates[$key][0];
break;
}
}
You can solve it with O(log n) with a binary search. But in a more straightforward solution, you can solve it with O(n).
You can calculate the difference between each word with the below algorithm.
‍‍
<?php
function strToInt($str)
{
$result = 0;
for ($i = 0; $i < strlen($str); $i++) {
$result = $result * 100 + ord($str[$i]);
}
return $result;
}
function find($searchStr)
{
$plates = [
['2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'],
['2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'],
['2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'],
['2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'],
['2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'],
['2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'],
['2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'],
['2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'],
['2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'],
['2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'],
['2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'],
['2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'],
['2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'],
['2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'],
['2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'],
['2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'],
['2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'],
['2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'],
['2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR']
];
$minYear = null;
$minKey = null;
$minDiff = strToInt('ZZZ');
$searchInt = strToInt($searchStr);
for ($i = 0; $i < count($plates); $i++) {
for ($j = 1; $j < 13; $j++) {
if(abs($searchInt - strToInt($plates[$i][$j])) < $minDiff) {
$minDiff = abs($searchInt - strToInt($plates[$i][$j]));
$minYear = $plates[$i][0];
$minKey = $plates[$i][$j];
}
}
}
return [$minYear, $minKey];
}
print_r(find('KHW'));
The code down below is by no means optimized, but it's rather a concept of how you might solve your problem.
//Flatten out array (one dimension without years and ----)
$flatten = array();
foreach($plates as $platevalues) {
foreach($platevalues as $pv) {
if ($pv != '---' && $pv != '----' && intval($pv) == 0) {
//Create a string only if valid letters included in the $letters-array
//This string is then added to the new array that is flattened out
$pv2 = '';
for($i=0;$i<strlen($pv);$i++) {
$letter = substr($pv,$i,1);
if (in_array($letter, $letters) !== false) {
$pv2 .= $letter;
}
}
$flatten[] = $pv2;
}
}
}
//Do the search
$search = 'GWN';
$search_result = '';
//Create a new search string based on first found in flattened
//plates array (first G, then GW, then GWN)
for($i=0;$i<strlen($search);$i++) {
foreach($flatten as $key=>$f) {
if (substr($search,0,$i+1) == substr($f,0,$i+1)) {
$search_result .= substr($search,$i,1);
break;
}
}
}
/*
$search_result is: GW
*/
//Create a new array where all items that begins with GW are included
$result = [];
foreach($flatten as $key=>$item) {
if (substr($search_result,0,strlen($search_result)) ==
substr($item,0,strlen($search_result))) {
$result[] = $item;
}
}
/*
$result =
array (size=2)
0 => string 'GWC' (length=3)
1 => string 'GWV' (length=3)
*/
//Create an array with total ASCII-value for each item
//in the $result array above
$result_o = [];
foreach($result as $item) {
$o = 0;
for($i=0;$i<strlen($item);$i++) {
$o += ord(substr($item,$i,1));
}
$result_o[]= $o;
}
/*
$result_o =
array (size=2)
0 => int 225
1 => int 244
*/
//Get the total ASCII-value for the original search string
$search_o = 0;
for($i=0;$i<strlen($search);$i++) {
$search_o += ord(substr($search,$i,1));
}
/*
$search_ o = 236
*/
//Find closest value in the $result_o (ASCII) - array compared (225,244)
//to the original $search_o ASCII value above (236)
$closest = 0;
$use_key = 0;
foreach($result_o as $key=>$item) {
if ($closest == 0 || abs($search_o - $closest) > abs($item - $search_o)) {
$closest = $item;
$use_key = $key;
}
}
/*
$closest = 244 (it's closer to 236 than 225 is)
$use_key = 1
*/
To get the result you have:
/*
$result =
array (size=2)
0 => string 'GWC' (length=3)
1 => string 'GWV' (length=3)
*/
//This should print out GWV
echo 'result=' . $result[$use_key];

How to remove elements of an array from an array with equal interval

I am working on taxi app, after ride completes i have to draw map for which i use google map apis. let suppose my way-points are
array($coordinates1,$coordinates2,$coordinates3,$coordinates4,$coordinates5,$coordinates6,.........,$coordinates40)
the problem is that google map api accept only maximum of 23 way-points, for this purpose I have to skip many coordinates to pass, here my idea is to unset elements of array with equal intervals so that the route remain same. Please someone guide me how to remove many number of elements from an array with equal interval, just like i need 23 and total elements are 40 so that i need like
array($coordinates1,$coordinates4,$coordinates7,$coordinates9,$coordinates13,$coordinates16,.........,$coordinates39)
I have found a possible way, its a little bit lengthy but i got exact required result
$required_elements = 23;
$way = array();
for($ini=1;$ini<=78;$ini++)
{
$way[] = "Co-Ordinated:".$ini;
}
$total_elements = count($way);
list($way1, $way2) = array_chunk($way, ceil(count($way) / 2));
$differrence_element = $total_elements-$required_elements;
$skip_element = ceil($total_elements/$differrence_element);
$output = array();
if($total_elements > $required_elements)
{
$i=1;$j=0;
foreach($way as $x)
{
if($i == $skip_element)
{
$i=1;$j++;
continue;
}
else
{
$output[] = $way1[$j];
if(count($output) >= $required_elements) break;
$output[] = $way2[$j];
if(count($output) >= $required_elements) break;
$i++;$j++;
}
}
}
else
{
$output = $way;
}
$output1 = array();
$output2 = array();
$i=0;
foreach($output as $g)
{
if($i%2 == 0)
$output1[] = $g;
else
$output2[] = $g;
$i++;
}
$result = array_merge($output1,$output2);
print_r($way);
echo "<br><br><pre>";
print_r($result);
echo '</pre>';

Why is strlen calculating the length is two higher than the length actually is?

I have the following code:
<?php
if (!isset($_SESSION["word"])) {
$dictionary_file = new SplFileObject("dictionary.txt");
$dictionary_file->seek(rand(0, 80367));
$_SESSION["word"] = $dictionary_file->current();
$_SESSION["word_progress"] = "";
for ($i = 0; $i < strlen($_SESSION["word"]); $i++) {
$_SESSION["word_progress"] .= "_";
}
echo strlen($_SESSION["word"]);
echo $_SESSION["word"];
}
else {
if (isset($_GET["guess"])) {
// If their guessed letter is in the word
if (stripos($_SESSION["word"], $_GET["guess"]) !== false) {
$occurrence_points = strposall($_SESSION["word"], $_GET["guess"]);
$progress = $_SESSION["word_progress"];
foreach ($occurrence_points as $values) {
$progress[$values] = $_GET["guess"];
}
$_SESSION["word_progress"] = $progress;
}
}
}
?>
I randomly generate a word from a file. Say it generates "bubble". The length is 6, but it will report 8, even after printing it out and confirming the word is indeed bubble. Why is this?
the randomly generated word might be adding whitespace. do a trim()
$_SESSION["word"] = trim($dictionary_file->current());

Feature like FB's "X, Y and Z other people like this"

I'm trying to implement something like facebook's like widget which says something like:
You, Name1, Name2 and 20 other people like this
I fetched all my data to be able to display this HTML, but I can't seem to find the right algo to form the HTML string.
My main problem is that I don't know when to put the and string or the , (comma) string. If I just had to put names, it would work, but the problem is that the You string always has to be first.
I'm going to paste my code here and the output I'm getting for some special cases (it's PHP).
$current_user = 0;
$html = "";
$count = count($result);
$key = 0;
foreach($result as $liked){
if($key + 1 > $limit)
break;
if($liked->uid == $user->uid){
$current_user = 1;
continue;
}
$html .= "<a href='".$liked->href."'>".$liked->name."</a>";
if($key < $count - 2)
$html .= ", ";
elseif($key == $count - 2 && $key + 1 != $limit)
$html .= " and ";
$key++;
}
if($current_user){
$userHtml = "You";
if($count > 2)
$userHtml .= ", ";
elseif($count > 1)
$userHtml .= " and ";
$html = $userHtml.$html;
}
$html = "♥ by ".$html;
if($count > $limit){
$difference = $count - $limit;
$html .= " and ".$difference." ".format_plural($difference,"other","others");
}
return $html;
And in the special case where the current user is the last one to like this, it will show:
♥ by You, admin, edu2004eu and
Notice the and word doesn't have anything after it, because You should have been after it, but I put it at the beginning. Any help? I just need the logic, not the actual code.
You can try something like this:
$likedBy = array('admin', 'eduard', 'jeremy', 'someoneelse');
// check if I like it and if so move me to the front
if (in_array($currentUsername, $likedBy)) {
$me = array_search($currentUsername, $likedBy);
unset($likedBy[$me]);
array_unshift($likedBy, 'You');
}
// remove anything after the limit
$extra = array_splice($likedBy, 3);
// the comma list
$html = implode(', ', $likedBy);
// any extras? if so, add them here, if not rewrite the list so
// it's "You, Eduard and admin"
if (!empty($extra)) {
$html .= ' and '.count($extra);
} else {
$lastguy = array_splice($likedBy, 1);
$html = implode(', ', $likedBy).' and '.$lastguy;
}
$html .= ' like this';
Eduard,
You can fix this simply by putting $key++; at the top of the loop and taking out all the places where you have $key + 1 in the loop.
I think what's happening is that $key + 1 is assuming that there is a current user.
This line would also not display the current user if they are not in the first $limit number of entries
if($key + 1 > $limit)
break;
You can fix this by putting this after the code that looks for the current user.
In Java (I know, but its what I had running) it would look something like:
List<String> users = Arrays.asList("Brian","Tom","Jack","John");
int key = 0;
String html = "";
String currentUser = "Brian";
int limit = 3;
boolean foundCurrentUser = false;
for (String user : users) {
key ++;
if (currentUser == user) {
foundCurrentUser = true;
continue;
}
if (key > limit) {
continue;
}
html += user;
if (key < users.size() - 1) {
html += ",";
} else if (key == users.size() - 1 && key != limit) {
html += " and ";
}
}
if (foundCurrentUser) {
String userHTML = "You";
if (key > 2) {
userHTML += ", ";
} else if (key == 1) {
userHTML += " and ";
}
html = userHTML + html;
}
html = "Likeed by " + html;
if (users.size() > limit ) {
html += " and 3 other people";
}
System.out.println(html);

Print Array if Condition Exists

I'm working on a printing a baseball team lineup, via php. I want to print a place holder for a missing Player 6 (or any missing position)
So if Player 1 -> Player 5 is OK print, NO Player #6 print place holder, Player 7 -> Player 9 is OK print. I tried to simplify the code. I have tried solving this every which way but I keep getting stuck.
CODE:
$rot = array();
$pos = array();
$jn = array();
$x = 1;
// loads up the arrays from the db
while ( $rot[$x], $pos[$x], $jn[$x])= $r->fetch_row() ) {
$x++;
}
// counts the actual number of players in linuep
// used for validation and error display
$num_players = mysqli_num_rows($r);
// controls the lineup position
for ($i = 1; $i <= 15; $i++){
if($rot[$i] == $i) {
//prints player
$lineup .= "<div data-fp='" . $pos[$i] . "'>" .$jn[$i]. "</div>";
} else {
// prints place holder
$text = "This Position needs to be filled before the next game.";
$lineup .= "<div id='pid' data-rel='".$text."' data-fp='' data-pid='' data-jn='' title=''>x</div>";
}
}
I also tried this to iterate through the array rot[] to find the matching position and print the line but it actually prints the holder repeatedly.
// controls the lineup position
for ($x = 1; $x <= 15; $x++){
for ($i = 1; $i <= ($num_players+1); $i++) {
if ($x == $i) {
//prints player
$lineup .= "<div data-fp='" . $pos[$i] . "'>" .$jn[$i]. "</div>";
} else {
// prints place holder
$text = "This Position needs to be filled before the next game.";
$lineup .= "<div id='pid' data-rel='".$text."' data-fp='' data-pid='' data-jn='' title=''>x</div>";
}
}
}
What about:
# index all players by position while taking them from the database
$players = array();
while ( $row = $r->fetch_row() ) {
list($rot, $pos, $jn) = $row;
$players[$pos] = compact(array('rot', $pos, $jn);
}
...
# line-up players
for ($pos = 1; $pos <= 15; $pos++)
{
$playerExists = isset($players[$pos]);
if ($playerExists)
{
# do this ...
}
else
{
# do that ...
}
}
I think you are creating an array where all numerical elements are filled (i.e. you'll always have a 1 thru 15) and your mistake is in the
if($rot[$i] == $i) {
When populating the arrays from the database, add this line:
$playertoid = array_flip($pos); # pos is the player number array?
i.e.
while ( ($rot[$x], $pos[$x], $jn[$x])= $r->fetch_row() ) {
$x++;
}
$playertoid = array_flip($pos);
Now you've created a reverse lookup table where the index is the player number.
Replace the
if($rot[$i] == $i) {
line with:
if (isset($playertoid[$i])) {

Categories