png-chess library extension

Apr 18, 2019 15:50

i've got some fun code i've been working on.

I found the png-chess library https://github.com/programarivm/pgn-chess/ and decided that it needed to be fleshed out a bit.

I first wrote a displayboard() function that can look at the state of a png-chess Game object and display the board in either HTML or on the command line (sans square colors on the board).

displayboard.php:


function isCLI(){
return (php_sapi_name() === 'cli');
}

function displayBoard($GameObj,$border=0,$legend=0,$cellborder=0){
$whitePieces = $GameObj->pieces("w");
$blackPieces = $GameObj->pieces("b");

if(isCli()=="cli"){
$cli=1;
}else{
$cli=0;
}

if(!$cli){
$space=" ";
}else{
$space=" ";
}

// board and translation arrays

$board=array(
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space),
array("1"=>$space,"2"=>$space,"3"=>$space,"4"=>$space,"5"=>$space,"6"=>$space,"7"=>$space,"8"=>$space));

$letter2key = array("a"=>"0","b"=>"1","c"=>"2","d"=>"3","e"=>"4","f"=>"5","g"=>"6","h"=>"7");
$ident2pieceW = array("R"=>"♖","N"=>"♘","B"=>"♗","Q"=>"♕","K"=>"♔","P"=>"♙");
$ident2pieceB = array("R"=>"♜","N"=>"♞","B"=>"♝","Q"=>"♛","K"=>"♚","P"=>"♟");

// set up white pieces

foreach($whitePieces as $piece){
$pos = $piece->position;
$type = $piece->identity;

$row = $letter2key[substr($pos,0,1)];
$col = substr($pos,1,1);

$board[$row][$col]=$ident2pieceW[$type];
}

// set up black pieces

foreach($blackPieces as $piece){
$pos = $piece->position;
$type = $piece->identity;

$row = $letter2key[substr($pos,0,1)];
$col = substr($pos,1,1);

$board[$row][$col]=$ident2pieceB[$type];
}

// display the board

if(!$cli){
echo "
";
if($legend & !$cli){
echo "";
}else if($legend & !$cli){
echo "ABCDEFGH";
}
}

$blackbg=0;

for($c=8;$c>=1;$c--){

if(!$cli){
echo "";
}

for($r=0;$r<=7;$r++){

if(!$cli){
if($blackbg==1){
$bg="cfcfcf";
$blackbg=0;
}else{
$bg="ffffff";
$blackbg=1;
}
if($legend){
if($r==0){
if(!$cli){
echo "";
}
}
}
echo "";
}

if($legend){
if($r==7){
if(!$cli){
echo "";
}
}
}

} // end of row

if(!$cli & !$legend){
echo "";
}else if(!$cli & $legend){
// no ;
}else{
echo "\n";
}

if(!$cli){
if($blackbg==0){
$blackbg=1;
}else{
$blackbg=0;
}
}

} // end of columns

if($legend & !$cli){
echo "\n";
}else if($legend & !$cli){
echo "ABCDEFGH";
}

if(!$cli){
echo "
&nbsp;ABCDEFGH&nbsp;
";
}

echo $c;

if(!$cli){
echo "
";
}

echo $board[$r][$c];

if(!$cli){
"
";
}

echo $c;

if(!$cli){
echo "
&nbsp;ABCDEFGH&nbsp;
";
}else{
echo "\n";
}
}
?>

next, i had to extend PGN/File/Convert.php

i added a toPHParray() member function that dumps the parsed file to an array for further use.

the following was added to ./vendor/programarivm/pgn-chess/src/PGN/File/Convert.php after the toMySqlScript() function:

public function toPHParray(): array{
$COL_ARY = '';
foreach (Tag::getConstants() as $key => $value) {
// create an array of column names
$COL_ARY .= "\"$value\",";
}

$COL_ARY .= '"movetext")';

$tags = [];
$movetext = '';
$ary=array();

if ($file = fopen($this->filepath, 'r')) {
while (!feof($file)) {
$line = preg_replace('~[[:cntrl:]]~', '', fgets($file));
try {
$tag = PgnValidate::tag($line);
$tags[$tag->name] = $tag->value;
} catch (\Exception $e) {
if ($this->line->startsMovetext($line)) {
$movetext .= $line;
} elseif ($this->line->endsMovetext($line)) {
$ARY_ROW_DEF="\$ary[]=array(";
$tagcount=count($tags);

foreach ($tags as $key => $value) {
$ARY_ROW_DEF.="\"$key\"=>\"$value\",";
}

$movetext = MySql::getInstance()->escape($movetext.$line);

$ARY_ROW_DEF.="\"movetext\"=>\"$movetext\");";

eval($ARY_ROW_DEF)

Tag::reset($tags);
$movetext = '';

} else {
$movetext .= $line;
}
}
}
fclose($file);
}
return $ary;
}

next, i wrote some code to allow selection of a PGN file to display (sorry, i won't be sharing my dropdown.php, but you should get the idea of how this could be used):

showgame.php:


namespace PGNChess\Cli;
include("vendor/autoload.php");

use PGNChess\Game;
use PGNChess\PGN\Symbol;
use PGNChess\PGN\File\Convert as PgnFileConvert;

include("displayboard.php");
include("dropdown.php");

$DEBUG=0;
$GAME_DIR="/www/chess/games";

function showgame(){
global $game;
$title=$game["Event"]." ".$game["White"]." vs. ".$game["Black"]." ".$game["Date"];
echo "
".$title."

";

$tmpmoves=explode(".",$game["movetext"]);

if($DEBUG){
echo ""; var_dump($tmpmoves); echo "";
}

// fix/build moves array
array_shift($tmpmoves); // shift off first element, should be "1"
$i=2; // keep track of array index
$keys=array("w","b"); // keys to add to each move pair

foreach($tmpmoves as $val){
$tmp=explode(" ",$val);
$count=count($tmp);

if($count==4){ // last move might include result and a null string
array_pop($tmp);
array_pop($tmp);
}else if($count==3){ // nothing to do
array_pop($tmp);
}else{ // remove the move number at end of the last string
$tmp[$count-1]=substr($tmp[$count-1],0,-1*strlen($i));
}

$tmp=array_combine($keys,$tmp); // key for each move will be "w" or "b"
$moves[]=$tmp; // add temp array to moves
$i++; // increment index
}

if($DEBUG){
echo ""; var_dump($moves); echo "";
}

// init new game
$chessgame = new Game;

// process the array of moves
$roundnum=1; // keep track of round
foreach($moves as $round){
echo "";
echo "";

foreach($round as $key=>$move){
if($key!=""){
$chessgame->play($key,$move);
echo "";
}
}
echo "
Round $roundnum
";
displayBoard($chessgame,$border=1,$legend=1);
echo $move;
echo "

";
$roundnum++; // next round
}
}

function array_addkey($KEY,$ARY){
foreach($ARY as $val){
$NEW_ARY[]=array($KEY=>$val);
}
return($NEW_ARY);
}

function array_add_id(&$ARY){
// add id key to entire array
$id=0;

foreach($ARY as $KEY=>$val){
$addme=array("id"=>$id++);
$ARY[$KEY]=array_merge($addme,$val);
}
}

function get_games($file){
// get games from selected file

try {
$ary = (new PgnFileConvert($file))->toPHParray();
} catch (PgnFileCharacterEncodingException $e) {
echo $e->getMessage() . PHP_EOL;
exit;
}
return($ary);
}

// END FUNCTIONS

// check superglobals
if(!isset($_POST["file_select"])){
$file_select="";
}else{
$file_select=$_POST["file_select"];
}

if(!isset($_POST["game_select"])){
$game_select="";
}else{
$game_select=$_POST["game_select"];
}

if(isset($_POST["game_select"])){ // if a game is selected
echo $_POST["file_select"];

$file=$GAME_DIR."/".$_POST["file_select"];
$games=get_games($file);
array_add_id($games);

$game=$games[$game_select];

showgame();

}else if(isset($_POST["file_select"])){ // if a file is selected
echo $_POST["file_select"];
$file=$GAME_DIR."/".$_POST["file_select"];

$games=get_games($file);
array_add_id($games);

if(count($games)==1){ // if file contains only one match
$game=$games[0];
showgame();
}else{

// display dropdown of games
echo "
";
make_select($games,"echo \$row[\"White\"].\" vs \".\$row[\"Black\"];","id","game_select","","- select game -","","","SELECT",$game_select);
echo "";
echo "
";
}
}else{

// list files in $GAME_DIR and place into an array

$files=scandir($GAME_DIR);
array_shift($files);
array_shift($files);

$files=array_addkey("file",$files);

// display dropdown of files
echo "
";
make_select($files,"echo \$row[\"file\"];","file","file_select","","- select file -","","","SELECT",$file_select);
echo "
";
}

?>

Here's some output (click for FULL RES):


Previous post
Up