Added files
This commit is contained in:
212
Board0x88Config.php
Normal file
212
Board0x88Config.php
Normal 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
131
DGTGameParser.php
Normal 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
1392
FenParser0x88.php
Normal file
File diff suppressed because it is too large
Load Diff
59
GameParser.php
Normal file
59
GameParser.php
Normal 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
67
MoveBuilder.php
Normal 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
492
MoveParser.php
Normal 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
126
PgnGameParser.php
Normal 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
128
PgnParser.php
Normal 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();
|
||||
|
||||
*/
|
||||
|
Reference in New Issue
Block a user