diff --git a/MoveParser.php b/MoveParser.php deleted file mode 100644 index 33e29c2..0000000 --- a/MoveParser.php +++ /dev/null @@ -1,492 +0,0 @@ - '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 "

To many pieces : $notation - $fromFile | $fromRank

"; - echo $this->fenParser->getFen()."
";; - - echo "From file: ". $fromFile."
"; - echo "From rank: ". $fromRank."
"; - echo "Piece type: ". $this->getPieceTypeFromMove($notation)."
"; - - - outputTime(); - die(); - } - - return false; - } - - if(count($availablePieces) === 0){ - if(self::$debugMode){ - $fromFile = $this->getFromFile($notation); - $fromRank = $this->getFromRank($notation); - echo "

No pieces for move - $notation - ". $this->fenParser->getWhoToMove() . "

"; - echo $this->fenParser->getFen()."
";; - echo "Destination square: ". $this->getDestinationSquare($notation)."
"; - echo "Piece type: ". $this->getPieceTypeFromMove($notation)."
"; - echo "From file: ". $fromFile."
"; - echo "From rank: ". $fromRank."
"; - echo "Capture: ". $this->isCaptureMove($notation)."
"; - - 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]; - } - -} \ No newline at end of file