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 "  | A | B | C | D | E | F | G | H |   | "; }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 $c;
if(!$cli){ echo " | "; } } } echo ""; }
echo $board[$r][$c];
if(!$cli){ " | "; }
if($legend){ if($r==7){ if(!$cli){ echo ""; }
echo $c;
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 "&nbsp; | A | B | C | D | E | F | G | H | &nbsp; | \n"; }else if($legend & !$cli){ echo "ABCDEFGH"; }
if(!$cli){ echo " |
";
}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 "Round $roundnum |
";
foreach($round as $key=>$move){
if($key!=""){
$chessgame->play($key,$move);
echo ""; displayBoard($chessgame,$border=1,$legend=1); echo $move; echo " | ";
}
}
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 "
";
}
}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 "
";
}
?>
Here's some output (click for FULL RES):