Added files

This commit is contained in:
DHTMLGoodies
2013-01-17 15:02:46 +01:00
commit 5396570fd6
8 changed files with 2607 additions and 0 deletions

212
Board0x88Config.php Normal file
View File

@@ -0,0 +1,212 @@
<?php
class Board0x88Config{
public static $squares = array(
'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1',
'a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2',
'a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3',
'a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4',
'a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5',
'a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6',
'a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7',
'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8'
);
public static $fenSquares = array(
'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8',
'a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7',
'a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6',
'a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5',
'a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4',
'a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3',
'a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2',
'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1'
);
public static $bitValues = array();
public static $fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
public static $fenPieces = array(
'p' => 'blackPawns', 'b' => 'blackBishops', 'n' => 'blackKnights', 'r' => 'blackRooks', 'q' => 'blackQueens', 'k' => 'blackKing',
'P' => 'whitePawns', 'B' => 'whiteBishops', 'N' => 'whiteKnights', 'R' => 'whiteRooks', 'Q' => 'whiteQueens', 'K' => 'whiteKing'
);
public static $colorAbbreviations = array('w' => 'white', 'b' => 'black');
public static $oppositeColors = array('white' => 'black', 'black' => 'white');
public static $mapping = array(
'a1' => 0, 'b1' => 1, 'c1' => 2, 'd1' => 3, 'e1' => 4, 'f1' => 5, 'g1' => 6, 'h1' => 7,
'a2' => 16, 'b2' => 17, 'c2' => 18, 'd2' => 19, 'e2' => 20, 'f2' => 21, 'g2' => 22, 'h2' => 23,
'a3' => 32, 'b3' => 33, 'c3' => 34, 'd3' => 35, 'e3' => 36, 'f3' => 37, 'g3' => 38, 'h3' => 39,
'a4' => 48, 'b4' => 49, 'c4' => 50, 'd4' => 51, 'e4' => 52, 'f4' => 53, 'g4' => 54, 'h4' => 55,
'a5' => 64, 'b5' => 65, 'c5' => 66, 'd5' => 67, 'e5' => 68, 'f5' => 69, 'g5' => 70, 'h5' => 71,
'a6' => 80, 'b6' => 81, 'c6' => 82, 'd6' => 83, 'e6' => 84, 'f6' => 85, 'g6' => 86, 'h6' => 87,
'a7' => 96, 'b7' => 97, 'c7' => 98, 'd7' => 99, 'e7' => 100, 'f7' => 101, 'g7' => 102, 'h7' => 103,
'a8' => 112, 'b8' => 113, 'c8' => 114, 'd8' => 115, 'e8' => 116, 'f8' => 117, 'g8' => 118, 'h8' => 119
);
public static $pieceAbbr = array(
'Q' => 'queen',
'R' => 'rook',
'N' => 'knight',
'B' => 'bishop'
);
public static $numberToSquareMapping = array(
'0' => 'a1', '1' => 'b1', '2' => 'c1', '3' => 'd1', '4' => 'e1', '5' => 'f1', '6' => 'g1', '7' => 'h1',
'16' => 'a2', '17' => 'b2', '18' => 'c2', '19' => 'd2', '20' => 'e2', '21' => 'f2', '22' => 'g2', '23' => 'h2',
'32' => 'a3', '33' => 'b3', '34' => 'c3', '35' => 'd3', '36' => 'e3', '37' => 'f3', '38' => 'g3', '39' => 'h3',
'48' => 'a4', '49' => 'b4', '50' => 'c4', '51' => 'd4', '52' => 'e4', '53' => 'f4', '54' => 'g4', '55' => 'h4',
'64' => 'a5', '65' => 'b5', '66' => 'c5', '67' => 'd5', '68' => 'e5', '69' => 'f5', '70' => 'g5', '71' => 'h5',
'80' => 'a6', '81' => 'b6', '82' => 'c6', '83' => 'd6', '84' => 'e6', '85' => 'f6', '86' => 'g6', '87' => 'h6',
'96' => 'a7', '97' => 'b7', '98' => 'c7', '99' => 'd7', '100' => 'e7', '101' => 'f7', '102' => 'g7', '103' => 'h7',
'112' => 'a8', '113' => 'b8', '114' => 'c8', '115' => 'd8', '116' => 'e8', '117' => 'f8', '118' => 'g8', '119' => 'h8'
);
public static $numericMapping = array(
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7,
'8' => 16, '9' => 17, '10' => 18, '11' => 19, '12' => 20, '13' => 21, '14' => 22, '15' => 23,
'16' => 32, '17' => 33, '18' => 34, '19' => 35, '20' => 36, '21' => 37, '22' => 38, '23' => 39,
'24' => 48, '25' => 49, '26' => 50, '27' => 51, '28' => 52, '29' => 53, '30' => 54, '31' => 55,
'32' => 64, '33' => 65, '34' => 66, '35' => 67, '36' => 68, '37' => 69, '38' => 70, '39' => 71,
'40' => 80, '41' => 81, '42' => 82, '43' => 83, '44' => 84, '45' => 85, '46' => 86, '47' => 87,
'48' => 96, '49' => 97, '50' => 98, '51' => 99, '52' => 100, '53' => 101, '54' => 102, '55' => 103,
'56' => 112, '57' => 113, '58' => 114, '59' => 115, '60' => 116, '61' => 117, '62' => 118, '63' => 119
);
public static $keySquares = array(',0,', ',1,', ',2,', ',3,', ',4,', ',5,', ',6,', ',7,', ',8,', ',9,', ',10,', ',11,', ',12,', ',13,', ',14,', ',15,',
',16,', ',17,', ',18,', ',19,', ',20,', ',21,', ',22,', ',23,', ',24,', ',25,', ',26,', ',27,', ',28,', ',29,', ',30,', ',31,', ',32,', ',33,', ',34,', ',35,', ',36,', ',37,', ',38,', ',39,', ',40,', ',41,', ',42,', ',43,', ',44,', ',45,', ',46,', ',47,', ',48,', ',49,', ',50,', ',51,', ',52,', ',53,', ',54,', ',55,', ',56,', ',57,', ',58,', ',59,', ',60,', ',61,', ',62,', ',63,', ',64,', ',65,', ',66,', ',67,', ',68,', ',69,', ',70,', ',71,', ',72,', ',73,', ',74,', ',75,', ',76,', ',77,', ',78,', ',79,', ',80,', ',81,', ',82,', ',83,', ',84,', ',85,', ',86,', ',87,', ',88,', ',89,', ',90,', ',91,', ',92,', ',93,', ',94,', ',95,', ',96,', ',97,', ',98,', ',99,', ',100,', ',101,', ',102,', ',103,', ',104,', ',105,', ',106,', ',107,', ',108,', ',109,', ',110,', ',111,', ',112,', ',113,', ',114,', ',115,', ',116,', ',117,', ',118,', ',119,'
);
public static $pieces = array(
'P' => 0x01,
'N' => 0x02,
'K' => 0x03,
'B' => 0x05,
'R' => 0x06,
'Q' => 0x07,
'p' => 0x09,
'n' => 0x0A,
'k' => 0x0B,
'b' => 0x0D,
'r' => 0x0E,
'q' => 0x0F
);
public static $pieceMapping = array(
0x01 => 'P',
0x02 => 'N',
0x03 => 'K',
0x05 => 'B',
0x06 => 'R',
0x07 => 'Q',
0x09 => 'p',
0x0A => 'n',
0x0B => 'k',
0x0D => 'b',
0x0E => 'r',
0x0F => 'q'
);
public static $typeMapping = array(
0x01 => 'pawn',
0x02 => 'knight',
0x03 => 'king',
0x05 => 'bishop',
0x06 => 'rook',
0x07 => 'queen',
0x09 => 'pawn',
0x0A => 'knight',
0x0B => 'king',
0x0D => 'bishop',
0x0E => 'rook',
0x0F => 'queen'
);
public static $notationMapping = array(
0x01 => '',
0x02 => 'N',
0x03 => 'K',
0x05 => 'B',
0x06 => 'R',
0x07 => 'Q',
0x09 => '',
0x0A => 'N',
0x0B => 'K',
0x0D => 'B',
0x0E => 'R',
0x0F => 'Q'
);
public static $typeToNumberMapping = array(
'pawn' => 0x01,
'knight' => 0x02,
'king' => 0x03,
'bishop' => 0x05,
'rook' => 0x06,
'queen' => 0x07
);
public static $colorMapping = array(
'p' => 'black', 'n' => 'black', 'b' => 'black', 'r' => 'black', 'q' => 'black', 'k' => 'black',
'P' => 'white', 'N' => 'white', 'B' => 'white', 'R' => 'white', 'Q' => 'white', 'K' => 'white'
);
public static $castle = array(
'-' => 0,
'K' => 8,
'Q' => 4,
'k' => 2,
'q' => 1
);
public static $numbers = array(
'0' => 1, '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, '6' => 1, '7' => 1, '8' => 1, '9' => 0
);
public static $movePatterns = array(
0X01 => array(16, 32, 15, 17),
0X09 => array(-16, -32, -15, -17),
0x05 => array(-15, -17, 15, 17),
0x0D => array(-15, -17, 15, 17),
0x06 => array(-1, 1, -16, 16),
0x0E => array(-1, 1, -16, 16),
0x07 => array(-15, -17, 15, 17, -1, 1, -16, 16),
0x0F => array(-15, -17, 15, 17, -1, 1, -16, 16),
0X02 => array(-33, -31, -18, -14, 14, 18, 31, 33),
0x0A => array(-33, -31, -18, -14, 14, 18, 31, 33),
0X03 => array(-17, -16, -15, -1, 1, 15, 16, 17),
0X0B => array(-17, -16, -15, -1, 1, 15, 16, 17)
);
public static $distances = array('241' => 1, '242' => 2, '243' => 3, '244' => 4, '245' => 5, '246' => 6, '247' => 7, '272' => 1,
'273' => 1, '274' => 2, '275' => 3, '276' => 4, '277' => 5, '278' => 6, '279' => 7, '304' => 2, '305' => 2,
'306' => 2, '307' => 3, '308' => 4, '309' => 5, '310' => 6, '311' => 7, '336' => 3, '337' => 3, '338' => 3,
'339' => 3, '340' => 4, '341' => 5, '342' => 6, '343' => 7, '368' => 4, '369' => 4, '370' => 4, '371' => 4,
'372' => 4, '373' => 5, '374' => 6, '375' => 7, '400' => 5, '401' => 5, '402' => 5, '403' => 5, '404' => 5,
'405' => 5, '406' => 6, '407' => 7, '432' => 6, '433' => 6, '434' => 6, '435' => 6, '436' => 6, '437' => 6,
'438' => 6, '439' => 7, '464' => 7, '465' => 7, '466' => 7, '467' => 7, '468' => 7, '469' => 7, '470' => 7,
'471' => 7, '239' => 1, '271' => 1, '303' => 2, '335' => 3, '367' => 4, '399' => 5, '431' => 6, '463' => 7,
'238' => 2, '270' => 2, '302' => 2, '334' => 3, '366' => 4, '398' => 5, '430' => 6, '462' => 7, '237' => 3,
'269' => 3, '301' => 3, '333' => 3, '365' => 4, '397' => 5, '429' => 6, '461' => 7, '236' => 4, '268' => 4,
'300' => 4, '332' => 4, '364' => 4, '396' => 5, '428' => 6, '460' => 7, '235' => 5, '267' => 5, '299' => 5,
'331' => 5, '363' => 5, '395' => 5, '427' => 6, '459' => 7, '234' => 6, '266' => 6, '298' => 6, '330' => 6,
'362' => 6, '394' => 6, '426' => 6, '458' => 7, '233' => 7, '265' => 7, '297' => 7, '329' => 7, '361' => 7,
'393' => 7, '425' => 7, '457' => 7, '208' => 1, '209' => 1, '210' => 2, '211' => 3, '212' => 4, '213' => 5,
'214' => 6, '215' => 7, '207' => 1, '206' => 2, '205' => 3, '204' => 4, '203' => 5, '202' => 6, '201' => 7,
'176' => 2, '177' => 2, '178' => 2, '179' => 3, '180' => 4, '181' => 5, '182' => 6, '183' => 7, '175' => 2,
'174' => 2, '173' => 3, '172' => 4, '171' => 5, '170' => 6, '169' => 7, '144' => 3, '145' => 3, '146' => 3,
'147' => 3, '148' => 4, '149' => 5, '150' => 6, '151' => 7, '143' => 3, '142' => 3, '141' => 3, '140' => 4,
'139' => 5, '138' => 6, '137' => 7, '112' => 4, '113' => 4, '114' => 4, '115' => 4, '116' => 4, '117' => 5,
'118' => 6, '119' => 7, '111' => 4, '110' => 4, '109' => 4, '108' => 4, '107' => 5, '106' => 6, '105' => 7,
'80' => 5, '81' => 5, '82' => 5, '83' => 5, '84' => 5, '85' => 5, '86' => 6, '87' => 7, '79' => 5, '78' => 5,
'77' => 5, '76' => 5, '75' => 5, '74' => 6, '73' => 7, '48' => 6, '49' => 6, '50' => 6, '51' => 6, '52' => 6,
'53' => 6, '54' => 6, '55' => 7, '47' => 6, '46' => 6, '45' => 6, '44' => 6, '43' => 6, '42' => 6, '41' => 7,
'16' => 7, '17' => 7, '18' => 7, '19' => 7, '20' => 7, '21' => 7, '22' => 7, '23' => 7, '15' => 7, '14' => 7,
'13' => 7, '12' => 7, '11' => 7, '10' => 7, '9' => 7
);
public static $defaultBoard = array(0=> 0,1=> 0,2=> 0,3=> 0,4=> 0,5=> 0,6=> 0,7=> 0,8=> 0,9=> 0,10=> 0,11=> 0,12=> 0,13=> 0,14=> 0,15=> 0,16=> 0,17=> 0,18=> 0,19=> 0,20=> 0,21=> 0,22=> 0,23=> 0,24=> 0,25=> 0,26=> 0,27=> 0,28=> 0,29=> 0,30=> 0,31=> 0,32=> 0,33=> 0,34=> 0,35=> 0,36=> 0,37=> 0,38=> 0,39=> 0,40=> 0,41=> 0,42=> 0,43=> 0,44=> 0,45=> 0,46=> 0,47=> 0,48=> 0,49=> 0,50=> 0,51=> 0,52=> 0,53=> 0,54=> 0,55=> 0,56=> 0,57=> 0,58=> 0,59=> 0,60=> 0,61=> 0,62=> 0,63=> 0,64=> 0,65=> 0,66=> 0,67=> 0,68=> 0,69=> 0,70=> 0,71=> 0,72=> 0,73=> 0,74=> 0,75=> 0,76=> 0,77=> 0,78=> 0,79=> 0,80=> 0,81=> 0,82=> 0,83=> 0,84=> 0,85=> 0,86=> 0,87=> 0,88=> 0,89=> 0,90=> 0,91=> 0,92=> 0,93=> 0,94=> 0,95=> 0,96=> 0,97=> 0,98=> 0,99=> 0,100=> 0,101=> 0,102=> 0,103=> 0,104=> 0,105=> 0,106=> 0,107=> 0,108=> 0,109=> 0,110=> 0,111=> 0,112=> 0,113=> 0,114=> 0,115=> 0,116=> 0,117=> 0,118=> 0,119=> 0);
public static $fileMapping = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
public static $rankMapping = array(0 => 1, 16 => 2, 32 => 3, 48 => 4, 64 => 5, 80 => 6, 96 => 7, 112 => 8);
public static $files = array('a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5, 'g' => 6, 'h' => 7);
}

131
DGTGameParser.php Normal file
View File

@@ -0,0 +1,131 @@
<?php
class DGTGameParser {
private $remoteUrl;
public function __construct(){
}
public function getPgnFromDGTData($remoteUrl, $toLocalPgnFile, $eventId=null) {
$this->remoteUrl = $this->getCorrectUrl($remoteUrl);
$gameIds = $this->getGameIds();
if(!count($gameIds)){
return array(
'success' => false,
'message' => 'Unable to load data from url ' . $this->remoteUrl
);
}
$contents = '';
foreach($gameIds as $gameId){
$urlPropertyData = $this->remoteUrl . 'game' . $gameId . '.txt';
if(!$dgtGameData = $this->readRemoteFile($urlPropertyData)){
return false;
}
$urlPositionData = $this->remoteUrl . 'pos' . $gameId . '.txt';
if(!$dgtMoveData = $this->readRemoteFile($urlPositionData)){
return false;
}
$contents .= $this->toPgn($dgtGameData, $dgtMoveData);
}
$ret['finished_round'] = false;
return $contents;
}
private function getCorrectUrl($url){
$posQueryString = strpos($url, '?');
if($posQueryString >0){
$url = substr($url, 0,$posQueryString);
}
return $url."/";
}
private function getGameIds(){
$ret = array();
$i = 1;
$content = $this->readRemoteFile($this->remoteUrl . 'tocks.txt');
preg_match_all("/<(.*?)>/s", $content,$matches, PREG_SET_ORDER);
for($i=0,$count = count($matches);$i<$count; $i+=2){
if($matches[$i][1]!='.'){
$ret[] = $matches[$i][1];
}else{
return $ret;
}
}
return $ret;
}
private function readRemoteFile($url) {
$contents = RemoteFileReader::getFromUrl($url);
if(preg_match("/<html/si", $contents) || preg_match("/<h1>/si", $contents) || preg_match("/<body>/si", $contents)){
return '';
}
return $contents;
}
private function toPgn($gameData, $moveData){
return (
$this->getGameProperties($gameData) .
$this->getFenProperty($moveData).
"\n".
$this->getMoves($moveData)).
"\n\n";
}
private function getGameProperties($dgtData){
$ret = '';
$mappingKeys = array(
'u' => 'Event',
'w' => 'White',
'b' => 'Black',
'm' => 'LastMoves'
);
$indexKeys = array(
array('index' => 4, 'property' => 'Result'),
array('index' => 5, 'property' => 'ClockWhite'),
array('index' => 6, 'property' => 'ClockBlack'),
);
foreach($mappingKeys as $key=>$value){
$property = preg_replace("/.*?<".$key . ">(.*?)<.*/si", "$1", $dgtData);
if($property){
$ret.= '['. $value . '" '.$property.'"]' . "\n";
}
}
$items = explode("<", $dgtData);
foreach($indexKeys as $indexKey) {
$ret.= '['. $indexKey['property'] . ' "'.$this->removeTags($items[$indexKey['index']]).'"]' . "\n";
}
return $ret;
}
private function getFenProperty($moveData){
$items = explode("<", $moveData);
return '[FEN "'.$this->removeTags($items[2]).'"]' . "\n";
}
private function removeTags($content){
return preg_replace("/[<>]/", "", $content);
}
private function getMoves($dgtData){
$ret = '';
preg_match_all("/<([a-hO0RQKBN][^\.]{1,4}|[RNBQK][0-8a-h][^\.]{1,4})>/s", $dgtData,$matches);
$moves = $matches[1];
for($i=0, $countMoves = count($moves);$i<$countMoves; $i++){
if($i % 2 == 0){
$ret.= ceil(($i+1) / 2) .". ";
}
$ret.=$moves[$i]." ";
}
return trim($ret);
}
}

1392
FenParser0x88.php Normal file

File diff suppressed because it is too large Load Diff

59
GameParser.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
class GameParser {
private $game;
private $fen;
public function __construct(){
$this->moveParser = new FenParser0x88();
}
public function getParsedGame($game){
$this->game = $game;
$this->fen = $this->getStartFen();
$this->moveParser->newGame($this->fen);
$this->parseMoves($this->game[CHESS_JSON::MOVE_MOVES]);
$this->addParsedProperty();
return $this->game;
}
private function addParsedProperty(){
$this->game[CHESS_JSON::GAME_METADATA][CHESS_JSON::MOVE_PARSED] = 1;
}
private function parseMoves(&$moves){
foreach($moves as &$move){
$this->parseAMove($move);
}
}
private function parseAMove(&$move){
if(!isset($move[CHESS_JSON::MOVE_NOTATION]) || (isset($move[CHESS_JSON::FEN]) && isset($move[CHESS_JSON::MOVE_FROM]) && isset($move[CHESS_JSON::MOVE_TO]))){
return;
}
if(isset($move[CHESS_JSON::MOVE_VARIATIONS])){
$fen = $this->moveParser->getFen();
$this->parseVariations($move[CHESS_JSON::MOVE_VARIATIONS]);
$this->moveParser->setFen($fen);
}
$move = $this->moveParser->getParsed($move);
}
private function parseVariations(&$variations){
foreach($variations as &$variation){
$fen = $this->moveParser->getFen();
$this->parseMoves($variation);
$this->moveParser->setFen($fen);
}
}
private function getStartFen(){
return $this->game[CHESS_JSON::GAME_METADATA][CHESS_JSON::FEN];
}
}

67
MoveBuilder.php Normal file
View File

@@ -0,0 +1,67 @@
<?php
class MoveBuilder {
private $moves = array();
private $moveReferences = array();
private $pointer = 0;
private $currentIndex = 0;
public function __construct(){
$this->moveReferences[0] =& $this->moves;
}
public function addMoves($moveString){
$moves = explode(" ", $moveString);
foreach($moves as $move){
$this->addMove($move);
}
}
private function addMove($move){
if(!$move || $move == '..' || $move == '*' || strstr($move, '1-') || strstr($move, '-1') || strstr($move, '1/2')){
return;
}
$this->moveReferences[$this->pointer][] = array(CHESS_JSON::MOVE_NOTATION => $move);
$this->currentIndex ++;
}
public function addCommentBeforeFirstMove($comment){
$comment = trim($comment);
if(!strlen($comment)){
return;
}
$this->moveReferences[$this->pointer][] = array();
$this->addComment($comment);
}
public function addComment($comment){
$comment = trim($comment);
if(!strlen($comment)){
return;
}
$index = count($this->moveReferences[$this->pointer])-1;
$this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_COMMENT] = $comment;
}
public function startVariation(){
$index = count($this->moveReferences[$this->pointer])-1;
if(!isset($this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_VARIATIONS])){
$this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_VARIATIONS] = array();
}
$countVariations = count($this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_VARIATIONS]);
$this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_VARIATIONS][$countVariations] = array();
$this->moveReferences[] =& $this->moveReferences[$this->pointer][$index][CHESS_JSON::MOVE_VARIATIONS][$countVariations];
$this->pointer++;
}
public function endVariation(){
array_pop($this->moveReferences);
$this->pointer--;
}
public function getMoves(){
return $this->moves;
}
}

492
MoveParser.php Normal file
View File

@@ -0,0 +1,492 @@
<?php
class MoveParser {
const STRICT_VALIDATION = true;
private static $debugMode = false;
private $fenParser;
private $fenBuilder;
private $squareParser;
private $pieceTypes = array(
'K' => 'king',
'Q' => 'queen',
'R' => 'rook',
'B' => 'bishop',
'N' => 'knight'
);
public function __construct(){
$this->fenParser = new FenParser();
$this->fenBuilder = new FenBuilder();
$this->squareParser = new SquareParser();
}
public function isCheckMate(){
$positionParser = new PositionParser($this->getFen());
return $positionParser->isCheckMate($this->fenParser->getWhoToMove());
}
public function getFen(){
return $this->fenParser->getFen();
}
public function newGame($fen){
$this->emptyCache();
$this->setFen($fen);
}
public function setFen($fen){
$this->fenParser->setFen($fen);
$this->fenBuilder->setFen($fen);
}
public function getParsed($move){
$moveProperties = $this->getMoveProperties($move);
$move[CHESS_JSON::MOVE_FROM] = $moveProperties[CHESS_JSON::MOVE_FROM];
$move[CHESS_JSON::MOVE_TO] = $moveProperties[CHESS_JSON::MOVE_TO];
$this->fenBuilder->move($moveProperties);
$move[CHESS_JSON::FEN] = $this->fenBuilder->getFen();
$this->fenParser->setFen($move[CHESS_JSON::FEN]);
return $move;
}
public function isValid($move){
if(!is_array($move)){
$move = array( CHESS_JSON::MOVE_NOTATION => $move);
}
$notation = $this->getNotation($move[CHESS_JSON::MOVE_NOTATION]);
$success = $this->getMovedPiece($notation, self::STRICT_VALIDATION);
return $success ? true : false;
}
public function emptyCache(){
$this->fenParser->emptyCache();
}
private function getMoveProperties($move){
$notation = $this->getNotation($move[CHESS_JSON::MOVE_NOTATION]);
if(isset($move[CHESS_JSON::MOVE_FROM])){
$movedPiece = $move[CHESS_JSON::MOVE_FROM];
}else{
$movedPiece = $this->getMovedPiece($notation);
}
if(isset($move[CHESS_JSON::MOVE_TO])){
$destinationSquare = $move[CHESS_JSON::MOVE_TO];
}else{
$destinationSquare = $this->getDestinationSquare($notation);
}
$ret = array(
CHESS_JSON::MOVE_FROM => $movedPiece['square'],
CHESS_JSON::MOVE_TO => $destinationSquare,
CHESS_JSON::MOVE_NOTATION => $move[CHESS_JSON::MOVE_NOTATION],
CHESS_JSON::MOVE_CAPTURE => $this->getCaptureSquare($notation),
CHESS_JSON::MOVE_PROMOTE_TO => $this->getPromoteTo($notation),
CHESS_JSON::MOVE_CASTLE => $this->getCastle($notation)
);
return $ret;
}
private function getNotation($notation){
return preg_replace("/[!\?+\s]/s", "", $notation);
}
private $castleMoves = array('O-O' => 'O-O', 'O-O-O' => 'O-O-O');
private function getCastle($notation){
if(isset($this->castleMoves[$notation])){
return $this->castleMoves[$notation];
}
return false;
}
private function getCaptureSquare($notation){
if(strstr($notation, 'x')){
$square = $this->getDestinationSquare($notation);
$piece = $this->fenParser->getPieceOnSquare($square);
if($piece){
return $square;
}
if($square === $this->fenParser->getEnPassantSquare()){
$ret = substr($square, 0, 1);
$rank = substr($square, 1,1);
if($this->fenParser->getWhoToMove() === 'white'){
$ret.= $rank-1;
}else{
$ret.= $rank+1;
}
return $ret;
}
}
return '';
}
private function getPromoteTo($notation){
if(preg_match("/=[QRBN]/", $notation)){
$pos = strpos($notation, '=');
return substr($notation, $pos+1,1);
}
return '';
}
private function isCaptureMove($notation){
return strstr($notation, 'x') ? true : false;
}
private function getMovedPiece($notation, $strictValidation = false){
$availablePieces = $this->getAvailablePiecesForMove($notation);
if($strictValidation){
$availablePieces = $this->getPiecesAfterStrictValidation($availablePieces, $notation);
}
if(count($availablePieces) === 1){
return $availablePieces[0];
}
if(count($availablePieces) > 1){
$availablePieces = $this->getAvailablePiecesAfterStrippingPaths($availablePieces, $notation);
if(count($availablePieces) === 1){
return $availablePieces[0];
}
$availablePieces = $this->removePinnedPieces($availablePieces);
if(count($availablePieces) === 1){
return $availablePieces[0];
}
if(self::$debugMode){
$pieceType = $this->getPieceTypeFromMove($notation);
$fromFile = $this->getFromFile($notation);
$fromRank = $this->getFromRank($notation);
echo "<h1>To many pieces : $notation - $fromFile | $fromRank</h1>";
echo $this->fenParser->getFen()."<br>";;
echo "From file: ". $fromFile."<br>";
echo "From rank: ". $fromRank."<br>";
echo "Piece type: ". $this->getPieceTypeFromMove($notation)."<br>";
outputTime();
die();
}
return false;
}
if(count($availablePieces) === 0){
if(self::$debugMode){
$fromFile = $this->getFromFile($notation);
$fromRank = $this->getFromRank($notation);
echo "<h1>No pieces for move - $notation - ". $this->fenParser->getWhoToMove() . "</h1>";
echo $this->fenParser->getFen()."<br>";;
echo "Destination square: ". $this->getDestinationSquare($notation)."<br>";
echo "Piece type: ". $this->getPieceTypeFromMove($notation)."<br>";
echo "From file: ". $fromFile."<br>";
echo "From rank: ". $fromRank."<br>";
echo "Capture: ". $this->isCaptureMove($notation)."<br>";
die();
}
return false;
}
}
private function getPiecesAfterStrictValidation($availablePieces, $notation){
$availablePieces = $this->getAvailablePiecesAfterStrippingPaths($availablePieces, $notation);
$availablePieces = $this->removePinnedPieces($availablePieces);
$availablePieces = $this->removeInvalidPawnPieces($availablePieces, $notation);
$availablePieces = $this->removeInvalidKingMoves($availablePieces, $notation);
return $availablePieces;
}
private function removeInvalidPawnPieces($availablePieces, $notation){
$toSquare = $this->getDestinationSquare($notation);
$pieceOnSquare = $this->fenParser->getPieceOnSquare($toSquare);
if(!$pieceOnSquare){
return $availablePieces;
}
$ret = array();
$file = $toSquare[0];
foreach($availablePieces as $piece){
if($piece['type'] === 'pawn'){
if($piece['square'][0] !== $file){
$ret[] = $piece;
}
}
}
return $ret;
}
private function removeInvalidKingMoves($availablePieces, $notation){
if(count($availablePieces)==0 || $availablePieces[0]['type']!='king'){
return $availablePieces;
}
$toSquare = $this->getDestinationSquare($notation);
$piece = $availablePieces[0];
$fenBuilder = new FenBuilder();
$fenBuilder->setFen($this->getFen());
$fenBuilder->move(array(
'from' => $piece['square'],
'to' => $toSquare,
'capture' => false,
'castle' => null,
'promoteTo' => null,
));
$pieces = $fenBuilder->getPiecesOfAColor($fenBuilder->getWhoToMove());
$king = $fenBuilder->getKing($this->fenParser->getWhoToMove());
$moveParser = new MoveParser();
$moveParser->setFen($fenBuilder->getFen());
$countPieces = 0;
foreach($pieces as $piece){
$not = $this->getShortPieceType($piece) . $piece['square'][0] . $piece['square'][1] . 'x' . $king['square'];
$fromFile = $this->getFromFile($not);
$fromRank = $this->getFromRank($not);
$move = array(
'm' => $not,
'from' => $piece['square'],
'to' => $king['square']
);
$tmpPieces = $moveParser->getAvailablePiecesAfterStrippingPaths(array($piece), $not, $king['square']);
if(count($tmpPieces)){
return array();
}
$countPieces+= count($tmpPieces);
$isValid = $moveParser->isValid($move);
}
return $availablePieces;
}
private $pieceTypesShort = array(
'king' => 'K',
'queen' => 'Q',
'rook' => 'R',
'bishop' => 'B',
'knight' => 'N',
'pawn' => ''
);
private function getShortPieceType($piece){
return $this->pieceTypesShort[$piece['type']];
}
private function removePinnedPieces($pieces){
$ret = array();
foreach($pieces as $piece){
if(!$this->isPinned($piece)){
$ret[] = $piece;
}
}
return $ret;
}
private function isPinned($piece){
$topParser = new FenParser("0" . $this->fenParser->getFen());
$piece = $topParser->getPieceOnSquare($piece['square']);
$fen = $topParser->getFenAfterRemovingPiece($piece);
$parser = new FenParser($fen);
$king = $parser->getKing($piece['color']);
$otherColor = $parser->getPassiveColor();
$pieces = $parser->getPiecesOfAColor($otherColor);
$piecesToCheck = array();
foreach($pieces as $piece){
$squares = $this->squareParser->getAllSquares($piece);
if(in_array($king['square'], $squares)){
$piecesToCheck[] = $piece;
}
}
foreach($piecesToCheck as $piece){
// Pawn on same file is not a threat
if($piece['type'] === 'pawn' && $piece['square'][0] == $king['square'][0]){
continue;
}
$squares = $this->getSquaresOfStrippedPaths($piece, $parser);
if(in_array($king['square'], $squares)){
return true;
}
}
return false;
}
private function getAvailablePiecesAfterStrippingPaths($pieces, $notation, $toSquare = null){
if(!$toSquare){
$toSquare = $this->getDestinationSquare($notation);
}
$ret = array();
$fromFile = $this->getFromFile($notation);
$fromRank = $this->getFromRank($notation);
foreach($pieces as $piece){
if($fromFile && $piece['square'][0] !== $fromFile){
continue;
}
if($fromRank && $piece['square'][1] !== $fromRank){
continue;
}
$squares = $this->getSquaresOfStrippedPaths($piece);
if(in_array($toSquare, $squares)){
$ret[] = $piece;
}
}
return $ret;
}
private function getAvailablePiecesForMove($notation){
$ret = array();
$pieceType = $this->getPieceTypeFromMove($notation);
$whoToMove = $this->fenParser->getWhoToMove();
if($pieceType === 'king'){
return array($this->fenParser->getKing($whoToMove));
}
$toSquare = $this->getDestinationSquare($notation);
$isCapture = $this->isCaptureMove($notation);
$pieces = $this->fenParser->getColoredPiecesOfAType($whoToMove, $pieceType);
foreach($pieces as $piece){
if($piece['type'] === 'pawn' && !$isCapture){
$squares = $this->squareParser->getSquaresInFirstPath($piece);
}else{
$squares = $this->squareParser->getAllSquares($piece);
}
if(in_array($toSquare, $squares)){
$ret[] = $piece;
}
}
return $ret;
}
private function getSquaresOfStrippedPaths($piece, $fenParser = null){
$ret = array();
$paths = $this->squareParser->getAllPaths($piece);
if(!$fenParser){
$fenParser = $this->fenParser;
}
foreach($paths as $path){
for($i=0, $count = count($path); $i<$count; $i++){
$pieceOnSquare = $fenParser->getPieceOnSquare($path[$i]);
$ret[] = $path[$i];
if($pieceOnSquare){
break;
}
}
}
return $ret;
}
private static $fromFileCache = array();
private function getFromFile($notation){
if(!isset(self::$fromFileCache[$notation])){
if(preg_match("/.*?[a-h].*[a-h]/s", $notation)){
self::$fromFileCache[$notation] = preg_replace("/^.*?([a-h]).+?$/s", '$1', $notation);
}else{
self::$fromFileCache[$notation] = '';
}
}
return self::$fromFileCache[$notation];
}
private static $fromRankCache = array();
private function getFromRank($notation){
if(!isset(self::$fromRankCache[$notation])){
if(preg_match("/.*?[1-8].*[1-8]/s", $notation)){
self::$fromRankCache[$notation] = preg_replace("/^.*?([1-8]).*?$/s", '$1', $notation);
}else{
self::$fromRankCache[$notation] = '';
}
}
return self::$fromRankCache[$notation];
}
private function getStartFen(){
return $this->game['metadata'][CHESS_JSON::FEN];
}
private static $pieceTypeCache = array();
private function getPieceTypeFromMove($move){
if(!isset(self::$pieceTypeCache[$move])){
if(strstr($move, 'O-O')){
self::$pieceTypeCache[$move] = 'king';
}else{
$firstChar = substr($move, 0, 1);
if(isset($this->pieceTypes[$firstChar])){
self::$pieceTypeCache[$move] = $this->pieceTypes[$firstChar];
}else{
self::$pieceTypeCache[$move] = 'pawn';
}
}
}
return self::$pieceTypeCache[$move];
}
private static $destinationSquareCache = array();
private function getDestinationSquare($move){
$key = $move."_". $this->fenParser->getWhoToMove();
if(!isset(self::$destinationSquareCache[$key])){
if(strlen($move) === 2){
self::$destinationSquareCache[$key] = $move;
}
else if($move === 'O-O'){
self::$destinationSquareCache[$key] = 'g' . ($this->fenParser->getWhoToMove() === 'white' ? '1' : '8');
}
else if($move === 'O-O-O'){
self::$destinationSquareCache[$key] = 'c' . ($this->fenParser->getWhoToMove() === 'white' ? '1' : '8');
}else{
self::$destinationSquareCache[$key] = preg_replace("/^.*?([a-h][1-8]).*?$/s", "$1", $move);
}
}
return self::$destinationSquareCache[$key];
}
}

126
PgnGameParser.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
class PgnGameParser{
private $pgnGame;
private $defaultFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
private $gameData = array();
public function __construct($pgnGame){
$this->pgnGame = trim($pgnGame);
#echo $this->pgnGame."<br>";
$this->moveBuilder = new MoveBuilder();
}
public function getParsedData(){
$this->gameData = array();
$this->gameData[CHESS_JSON::GAME_METADATA] = $this->getMetadata();
$this->gameData[CHESS_JSON::MOVE_MOVES] = $this->getMoves();
return $this->gameData;
}
private function getMetadata(){
$ret = array();
$lines = explode("\n", $this->pgnGame);
foreach($lines as $line){
$line = trim($line);
if(substr($line, 0, 1) === '[' && substr($line, strlen($line)-1, 1) === ']'){
$metadata = $this->getMetadataKeyAndValue($line);
$ret[$metadata['key']] = $metadata['value'];
}
}
if(!isset($ret[CHESS_JSON::FEN])) {
$ret[CHESS_JSON::FEN] = $this->defaultFen;
}
return $ret;
}
private function getMetadataKeyAndValue($metadataString){
$metadataString = preg_replace("/[\[\]]/s", "", $metadataString);
$metadataString = str_replace('"', '', $metadataString);
$tokens = explode(" ", $metadataString);
$key = $tokens[0];
$value = implode(" ", array_slice($tokens, 1));
$ret = array('key' => $this->getValidKey($key), 'value' => $value );
return $ret;
}
private function getValidKey($key){
$key = strtolower($key);
return $key;
}
private function getMoves(){
$parts = $this->getMovesAndComments();
for($i=0, $count = count($parts); $i<$count; $i++){
$move = trim($parts[$i]);
switch($move){
case '{':
if($i==0){
$this->moveBuilder->addCommentBeforeFirstMove($parts[$i+1]);
}else{
$this->moveBuilder->addComment($parts[$i+1]);
}
$i+=2;
break;
default:
$moves = $this->getMovesAndVariationFromString($move);
foreach($moves as $move){
switch($move){
case '(':
$this->moveBuilder->startVariation();
break;
case ')':
$this->moveBuilder->endVariation();
break;
default:
$this->moveBuilder->addMoves($move);
}
}
}
}
return $this->moveBuilder->getMoves();
}
private function addGameComment($comment){
$this->gameData[CHESS_JSON::GAME_METADATA][CHESS_JSON::MOVE_COMMENT] = $comment;
}
private function getMovesAndComments(){
$ret = preg_split("/({|})/s", $this->getMoveString(), 0, PREG_SPLIT_DELIM_CAPTURE);
if(!$ret[0]){
$ret = array_slice($ret, 1);
}
return $ret;
}
private function getMovesAndVariationFromString($string){
$string = " ". $string;
$string = preg_replace("/[0-9]+?\./s", "", $string);
$string = str_replace(" ..", "", $string);
$string = str_replace(" ", " ", $string);
$string = trim($string);
return preg_split("/(\(|\))/s", $string, 0, PREG_SPLIT_DELIM_CAPTURE);
}
private function getMoveString() {
$tokens = preg_split("/\n\n/s", $this->pgnGame);
if(count($tokens) < 2){
return "";
}
$gameData = $tokens[1];
$gameData = str_replace("\n", " ", $gameData);
$gameData = preg_replace("/(\s+)/", " ", $gameData);
return trim($gameData);
}
}

128
PgnParser.php Normal file
View File

@@ -0,0 +1,128 @@
<?php
class PgnParser {
private $pgnFile;
private $pgnContent;
private $pgnGames;
private $games;
private $gameParser;
public function __construct($pgnFile = ""){
if($pgnFile){
$this->pgnFile = $pgnFile;
}
$this->gameParser = new GameParser();
}
public function setPgnContent($content){
$this->pgnContent = $content;
}
private function readPgn(){
$fh = fopen($this->pgnFile, 'r');
$this->pgnContent = fread($fh, filesize($this->pgnFile));
fclose($fh);
}
private function cleanPgn(){
$c = $this->pgnContent;
$c = preg_replace("/\\$[0-9]+/s", "", $c);
$c = preg_replace("/{(.*?)\[(.*?)}/s", '{$1-SB-$2}', $c);
$c = preg_replace("/\r/s", "", $c);
$c = preg_replace("/\t/s", "", $c);
$c = preg_replace("/\]\s+\[/s", "]\n[", $c);
$c = str_replace(" [", "[", $c);
$c = preg_replace("/([^\]])(\n+)\[/si", "$1\n\n[", $c);
$c = preg_replace("/\n{3,}/s", "\n\n", $c);
$c = str_replace("-SB-", "[", $c);
$this->pgnContent = $c;
}
public static function getArrayOfGames($pgn) {
return self::getPgnGamesAsArray($pgn);
}
private function splitPgnIntoGames(){
$this->pgnGames = $this->getPgnGamesAsArray($this->pgnContent);
}
private function getPgnGamesAsArray($pgn){
$ret = array();
$content = "\n\n" . $pgn;
$games = preg_split("/\n\n\[/s", $content, -1, PREG_SPLIT_DELIM_CAPTURE);
for($i=1, $count = count($games); $i<$count; $i++){
array_push($ret, trim("[". $games[$i]));
}
return $ret;
}
public function getGamesAsJSON(){
return json_encode($this->getGames());
}
private function isLazy(){
return false;
}
public function getUnparsedGames() {
if($this->pgnFile){
$this->readPgn();
}
$this->cleanPgn();
$this->splitPgnIntoGames();
return $this->pgnGames;
}
public function getFirstGame(){
$games = $this->getGames();
if(count($games)){
return $games[0];
}
return null;
}
public function getGames(){
if($this->pgnFile){
$this->readPgn();
}
$this->cleanPgn();
$this->splitPgnIntoGames();
for($i=0, $count = count($this->pgnGames);$i<$count; $i++){
$gameParser = new PgnGameParser($this->pgnGames[$i]);
$this->games[$i] = $gameParser->getParsedData();
if(!$this->isLazy()){
$this->games[$i] = $this->gameParser->getParsedGame($this->games[$i]);
}
}
return $this->games;
}
}
/*
error_reporting(E_ALL);
ini_set('display_errors','on');
require_once("GameParser.php");
require_once("FenParser0x88.php");
require_once("PgnGameParser.php");
require_once("MoveBuilder.php");
require_once("Board0x88Config.php");
require_once("../CHESS_JSON.php");
echo "<p>";
#$parser = new PgnParser('ChessUserRoles/winning-chess-sacrifices-and-combinations.pgn');
$parser = new PgnParser('../ChessUserRoles/alf2.pgn');
echo "<br><br>";
$games = $parser->getGames();
echo json_encode($games[0]);
echo "<br><br>";
#outputTime();
*/