public function ValidateFENStringStructureAndValues($FEN, &$errors)
 {
     $fields;
     // Stores each field (space delimited item).
     $row;
     // Stores each row of the FEN.
     $nWKingCount = 0;
     $nBKingCount = 0;
     // The number of kings found.
     $errors = "";
     if ($FEN == null) {
         return false;
     }
     // Makes sure all groups and board ranks are available.
     $fields = preg_split('/ /', $FEN);
     if (count($fields) != 6) {
         $errors = "The number of fields in the FEN is not 6.";
         return false;
     }
     // If the board setup field ends with a "/" (PHPChess returned fen) then remove it.
     if (STRING_UTILS::last_char($fields[0]) == "/") {
         $fields[0] = substr($fields[0], 0, count($fields[0]) - 2);
     }
     $row = preg_split('/\\//', $fields[0]);
     if (count($row) != 8) {
         $errors = "The number of ranks in the board setup field is not 8.";
         return false;
     }
     // Now check the values for each group are acceptable.
     // First check that the board characters are acceptable.
     for ($i = 0; $i < strlen($fields[0]); $i++) {
         if (!($fields[0][$i] == 'K' || $fields[0][$i] == 'Q' || $fields[0][$i] == 'R' || $fields[0][$i] == 'B' || $fields[0][$i] == 'N' || $fields[0][$i] == 'P' || $fields[0][$i] == 'k' || $fields[0][$i] == 'q' || $fields[0][$i] == 'r' || $fields[0][$i] == 'b' || $fields[0][$i] == 'n' || $fields[0][$i] == 'p' || $fields[0][$i] == '/' || $fields[0][$i] == '1' || $fields[0][$i] == '2' || $fields[0][$i] == '3' || $fields[0][$i] == '4' || $fields[0][$i] == '5' || $fields[0][$i] == '6' || $fields[0][$i] == '7' || $fields[0][$i] == '8')) {
             $errors = "The FEN string contains an invalid character: \n" + $fields[0][$i];
             return false;
         }
         if ($fields[0][$i] == 'K') {
             $nWKingCount++;
         }
         if ($fields[0][$i] == 'k') {
             $nBKingCount++;
         }
     }
     // Make sure there is one white and one black king
     if ($nWKingCount == 0) {
         $errors .= "No White king.\n";
     }
     if ($nBKingCount == 0) {
         $errors .= "No Black king.\n";
     }
     if ($nWKingCount > 1) {
         $errors .= "There can only be one king for black.\n";
     }
     if ($nBKingCount > 1) {
         $errors .= "There can only be one king for black.\n";
     }
     // Check if the player turn is either w or b.
     if (!($fields[1] == "w" || $fields[1] == "b")) {
         $errors .= "Player turn must be either 'w' or 'b'.\n";
     }
     // Check the castling characters are valid. There must be 1 to 4 characters.
     // If a '-' then no other character should be there. If no '-' then only k,K,q and Q allowed.
     if (strlen($fields[2]) < 1 || strlen($fields[2]) > 4) {
         $errors .= "The castling field of the FEN is invalid.\n";
     }
     if (strstr($fields[2], "-") && strlen($fields[2]) != 1) {
         $errors .= "Cannot have a '-' in the castling field with other characters.\n";
     }
     if (strlen($fields[2]) > 1) {
         for ($i = 0; $i < strlen($fields[2]); $i++) {
             if (!($fields[2][$i] == 'k' || $fields[2][$i] == 'K' || $fields[2][$i] == 'Q' || $fields[2][$i] == 'q')) {
                 $errors .= "The castling field contained an invalid character.\n";
             }
         }
     }
     // The en-passant field can only be '-' or a valid tile (a1 through to h8)
     if ($fields[3] != "-") {
         if ($this->ConvertAlgebraicNotationTileToInteger($fields[3]) == -1) {
             $errors .= "The en passant field must contain a valid tile reference.\n";
         }
     }
     // The 50 move field must be non negative.
     if ($this->IsStringNonNegativeNumber($fields[4]) == false) {
         $errors .= "The 50 move (half move count) field must be non negative.\n";
     }
     // The full move number must be non negative.
     if ($this->IsStringNonNegativeNumber($fields[5]) == false) {
         $errors .= "The full move field must be non negative\n";
     }
     if ($errors == "") {
         return true;
     } else {
         return false;
     }
 }
示例#2
0
 private function ConvertSANtoCoordinates($szMove, &$nStartTile, &$nEndTile, &$promotionType)
 {
     $nTmp;
     if (strlen($szMove) < 2) {
         return false;
     }
     //promotionType = PIECE_TYPE::UNDEFINED;
     // If there is a p in the text then remove it since we don't need to be told the move was en passant
     $nTmp = strpos($szMove, 'ep');
     if ($nTmp !== FALSE) {
         $szMove = substr($szMove, 0, $nTmp) . substr($szMove, $nTmp, strlen($szMove) - $nTmp - 2);
     }
     // Check if the move was check or checkmate and remove the last character
     if (STRING_UTILS::last_char($szMove) == "+") {
         //$szMove.Replace("+", "");
         $szMove = substr($szMove, 0, strlen($szMove) - 1);
     }
     $nTmp = strpos($szMove, '#');
     if ($nTmp !== FALSE) {
         // Extract the move made which caused the checkmate. Note that crafty sends 0-1 {black mates} after the #.
         //$szMove = $szMove.Substring(0, $szMove.Length - 1);
         $szMove = substr($szMove, 0, $nTmp);
     }
     // Determine the type of the move (castle-, check+, mate#, promotion=)
     if ($szMove == "O-O") {
         if ($this->PlayerTurn == 0) {
             $nStartTile = 4;
             $nEndTile = 6;
         } else {
             $nStartTile = 60;
             $nEndTile = 62;
         }
         return true;
     } else {
         if ($szMove == "O-O-O") {
             if ($this->PlayerTurn == 0) {
                 $nStartTile = 4;
                 $nEndTile = 2;
             } else {
                 $nStartTile = 60;
                 $nEndTile = 58;
             }
             return true;
         } else {
             if (strpos($szMove, '=') !== FALSE) {
                 // Get type to promote to
                 if (STRING_UTILS::last_char($szMove) == "N") {
                     $promotionType = PIECE_TYPE::KNIGHT;
                 } else {
                     if (STRING_UTILS::last_char($szMove) == "B") {
                         $promotionType = PIECE_TYPE::BISHOP;
                     } else {
                         if (STRING_UTILS::last_char($szMove) == "R") {
                             $promotionType = PIECE_TYPE::ROOK;
                         } else {
                             if (STRING_UTILS::last_char($szMove) == "Q") {
                                 $promotionType = PIECE_TYPE::QUEEN;
                             }
                         }
                     }
                 }
                 // Get tiles
                 $szMove = substr($szMove, 0, strlen($szMove) - 2);
                 // Check if there is an x to indicate a piece was taken.
                 if ($szMove . Contains("x")) {
                     $nEndTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger($szMove . Substring(2));
                     if ($this->PlayerTurn == 0) {
                         $nStartTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger($szMove . Substring(0, 1) + "7");
                     } else {
                         $nStartTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger($szMove . Substring(0, 1) + "2");
                     }
                 } else {
                     $nEndTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger($szMove);
                     if ($this->PlayerTurn == 0) {
                         $nStartTile = $nEndTile - 8;
                     } else {
                         $nStartTile = $nEndTile + 8;
                     }
                 }
                 if ($nStartTile == -1 || $nEndTile == -1) {
                     return false;
                 }
                 return true;
             } else {
                 if ($szMove[strlen($szMove) - 1] == 'Q' || $szMove[strlen($szMove) - 1] == 'B' || $szMove[strlen($szMove) - 1] == 'N' || $szMove[strlen($szMove) - 1] == 'R') {
                     // Get type to promote to
                     if ($szMove[strlen($szMove) - 1] == 'N') {
                         $promotionType = PIECE_TYPE::KNIGHT;
                     } else {
                         if ($szMove[strlen($szMove) - 1] == 'B') {
                             $promotionType = PIECE_TYPE::BISHOP;
                         } else {
                             if ($szMove[strlen($szMove) - 1] == 'R') {
                                 $promotionType = PIECE_TYPE::ROOK;
                             } else {
                                 if ($szMove[strlen($szMove) - 1] == 'Q') {
                                     $promotionType = PIECE_TYPE::QUEEN;
                                 }
                             }
                         }
                     }
                     // Remove the last char and then continue on finding the start and end tiles for this move.
                     $szMove = substr($szMove, 0, strlen($szMove) - 1);
                     // Make sure the move is valid for further processing.
                     if (strlen($szMove) < 2) {
                         return false;
                     }
                 }
             }
         }
     }
     // Last two chars indicate the end tile. Remove them from the string.
     $nEndTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger(substr(strlen($szMove) - 2));
     if ($nEndTile == -1) {
         return false;
     }
     $szMove = substr($szMove, 0, strlen($szMove) - 2);
     // Check if a piece was taken and remove the x character if so.
     if ($szMove[strlen($szMove) - 1] == 'x') {
         $szMove = substr($szMove, 0, strlen($szMove) - 1);
     }
     // Check the remaining length.
     if (strlen($szMove) == 0) {
         if ($this->PlayerTurn == 0) {
             //if (rgBoard[nEndTile / 8 - 1, nEndTile % 8] > 0) nStartTile = nEndTile - 8;
             //else nStartTile = nEndTile - 16;
             //return true;
             // If the end tile is not rank 4 that means a pawn couldn't have moved two tiles
             // up the rank.
             if ($nEndTile / 8 != 3) {
                 // Check for a single move forward.
                 if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8] == PIECE_TYPE::PAWN) {
                     $nStartTile = $nEndTile - 8;
                 } else {
                     if ($this->nEnPassantSquare == nEndTile) {
                         // Check if there is a white pawn to the left/right one rank down from the end tile
                         if ($nEndTile % 8 == 0) {
                             if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8 + 1] == PIECE_TYPE::PAWN) {
                                 $nStartTile = $nEndTile - 7;
                             } else {
                                 return false;
                             }
                         } else {
                             if ($nEndTile % 8 > 0 && $nEndTile % 8 < 7) {
                                 if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8 - 1] == PIECE_TYPE::PAWN) {
                                     $nStartTile = $nEndTile - 9;
                                 } else {
                                     if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8 + 1] == PIECE_TYPE::PAWN) {
                                         $nStartTile = $nEndTile - 7;
                                     } else {
                                         return false;
                                     }
                                 }
                             } else {
                                 if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8 - 1] == PIECE_TYPE::PAWN) {
                                     $nStartTile = $nEndTile - 9;
                                 } else {
                                     return false;
                                 }
                             }
                         }
                     }
                 }
             } else {
                 // Check for a single move forward.
                 if ($this->Board[$this->floor[$nEndTile] - 1][$nEndTile % 8] == PIECE_TYPE::PAWN) {
                     $nStartTile = $nEndTile - 8;
                 } else {
                     if ($this->Board[$this->floor[$nEndTile] - 2][$nEndTile % 8] == PIECE_TYPE::PAWN) {
                         $nStartTile = $nEndTile - 16;
                     } else {
                         // Check if there is a black pawn to the left/right one rank up from the end tile
                         if ($nEndTile % 8 == 0) {
                             if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8 + 1] == PIECE_TYPE::PAWN + 6) {
                                 $nStartTile = $nEndTile + 9;
                             } else {
                                 return false;
                             }
                         } else {
                             if ($nEndTile % 8 > 0 && $nEndTile % 8 < 7) {
                                 if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8 - 1] == PIECE_TYPE::PAWN + 6) {
                                     $nStartTile = $nEndTile + 7;
                                 } else {
                                     if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8 + 1] == PIECE_TYPE::PAWN + 6) {
                                         $nStartTile = $nEndTile + 9;
                                     } else {
                                         return false;
                                     }
                                 }
                             } else {
                                 if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8 - 1] == PIECE_TYPE::PAWN + 6) {
                                     $nStartTile = $nEndTile + 7;
                                 } else {
                                     return false;
                                 }
                             }
                         }
                     }
                 }
             }
         } else {
             //if ($this->Board[nEndTile / 8 + 1, nEndTile % 8] > 0) nStartTile = nEndTile + 8;
             //else nStartTile = nEndTile + 16;
             //return true;
             // If the end tile is not rank 5 that means a pawn couldn't have moved two tiles
             // down the rank.
             if ($this->floor[$nEndTile] != 4) {
                 if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8] == PIECE_TYPE::PAWN + 6) {
                     $nStartTile = $nEndTile + 8;
                 } else {
                     if ($this->nEnPassantSquare == $nEndTile) {
                         $nStartTile = -1;
                         return false;
                     }
                 }
             } else {
                 if ($this->Board[$this->floor[$nEndTile] + 1][$nEndTile % 8] == PIECE_TYPE::PAWN + 6) {
                     $nStartTile = $nEndTile + 8;
                 } else {
                     if ($this->Board[$this->floor[$nEndTile] + 2][$nEndTile % 8] == PIECE_TYPE::PAWN + 6) {
                         $nStartTile = $nEndTile + 16;
                     } else {
                         $nStartTile = -1;
                         return false;
                     }
                 }
             }
         }
         return true;
     }
     if (strlen($szMove) == 1) {
         if ($szMove == 'a' || $szMove == 'b' || $szMove == 'c' || $szMove == 'd' || $szMove == 'e' || $szMove == 'f' || $szMove == 'g' || $szMove == 'h') {
             if ($this->PlayerTurn == 0) {
                 $nTmp = $nEndTile / 8;
             } else {
                 $nTmp = $this->floor[$nEndTile] + 2;
             }
             $nStartTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger(substr($szMove, 0, 1) . $nTmp);
         } else {
             if ($szMove == 'K') {
                 $nStartTile = $this->ObtainAttackingTileForPieceType(PIECE_TYPE::KING, $nEndTile);
             } else {
                 if ($szMove == 'Q') {
                     $nStartTile = $this->ObtainAttackingTileForPieceType(PIECE_TYPE::QUEEN, $nEndTile);
                 } else {
                     if ($szMove == 'R') {
                         $nStartTile = $this->ObtainAttackingTileForPieceType(PIECE_TYPE::ROOK, $nEndTile);
                     } else {
                         if ($szMove == 'B') {
                             $nStartTile = $this->ObtainAttackingTileForPieceType(PIECE_TYPE::BISHOP, $nEndTile);
                         } else {
                             if ($szMove == 'N') {
                                 $nStartTile = $this->ObtainAttackingTileForPieceType(PIECE_TYPE::KNIGHT, $nEndTile);
                             }
                         }
                     }
                 }
             }
         }
         if ($nStartTile == -1) {
             return false;
         }
         return true;
     }
     if (strlen($szMove) == 2) {
         // Find the piece type for the given file or rank
         if ($szMove[0] == 'K') {
             $nStartTile = $this->FindPieceLocatedInFileOrRank(PIECE_TYPE::KING, $szMove[1]);
         } else {
             if ($szMove[0] == 'Q') {
                 $nStartTile = $this->FindPieceLocatedInFileOrRank(PIECE_TYPE::QUEEN, $szMove[1]);
             } else {
                 if ($szMove[0] == 'R') {
                     $nStartTile = $this->FindPieceLocatedInFileOrRank(PIECE_TYPE::ROOK, $szMove[1]);
                 } else {
                     if ($szMove[0] == 'B') {
                         $nStartTile = $this->FindPieceLocatedInFileOrRank(PIECE_TYPE::BISHOP, $szMove[1]);
                     } else {
                         if ($szMove[0] == 'N') {
                             $nStartTile = $this->FindPieceLocatedInFileOrRank(PIECE_TYPE::KNIGHT, $szMove[1]);
                         } else {
                         }
                     }
                 }
             }
         }
         if ($nStartTile == -1) {
             return false;
         }
         return true;
     }
     if (strlen($szMove) == 3) {
         $nStartTile = $this->ChessUtils->ConvertAlgebraicNotationTileToInteger(substr($szMove, 1));
         if ($nStartTile == -1) {
             return false;
         }
         return true;
     }
     return false;
 }