diff --git a/src/FEN.php b/src/FEN.php index 221297c..ce7cf52 100644 --- a/src/FEN.php +++ b/src/FEN.php @@ -266,9 +266,15 @@ public function set_castling(string $castling) : void $rooks_file = strtolower($castling_right); if ($rooks_file < $new_kings_file) { $castling_type = ctype_upper($castling_right)? 'Q' : 'q'; + if ($new_queens_rook_file && $new_queens_rook_file != $rooks_file) { + throw new ParseException("Multiple queen's rook castling rights in string '$castling'."); + } $new_queens_rook_file = $rooks_file; } else { $castling_type = ctype_upper($castling_right)? 'K' : 'k'; + if ($new_kings_rook_file && $new_kings_rook_file != $rooks_file) { + throw new ParseException("Multiple king's rook castling rights in string '$castling'."); + } $new_kings_rook_file = $rooks_file; } } @@ -293,10 +299,6 @@ public function set_castling(string $castling) : void private function validate_castling(array $castling_rights, $kings_file, $kings_rook_file, $queens_rook_file) : void { - if ($kings_file === null || $kings_rook_file === null || $queens_rook_file === null) - { - throw new ParseException("Invalid castling string."); - } if ($castling_rights['K'] || $castling_rights['Q']) { @@ -353,7 +355,6 @@ private function validate_castling(array $castling_rights, $kings_file, $kings_r */ private function get_castling_availability(string $type) : bool { - self::validate_castling_type($type); return $this->castling_rights[$type]; } @@ -370,17 +371,9 @@ private function get_castling_availability(string $type) : bool */ private function set_castling_availability(string $type, bool $avalability) : void { - self::validate_castling_type($type); $this->castling_rights[$type] = $avalability; } - private static function validate_castling_type(string $type) : void - { - if (!in_array($type, ['K', 'Q', 'k', 'q'])) { - throw new ParseException("Invalid castling type '$type'."); - } - } - /** * Get En Passant target square. * @@ -844,7 +837,7 @@ private function standard_move(Move &$move) : void $this->validate_move_target_square($move); $origin = $this->get_move_origin($move); $new_board = $this->get_new_board($move, $origin); - $this->set_new_board($new_board); + $this->set_board($new_board); $move->set_origin($origin); } @@ -870,15 +863,6 @@ private function get_new_board(Move $move, Square $origin) : Board return $new_board; } - private function set_new_board(Board $new_board) : void - { - $active_color = $this->get_active_color(); - if ($new_board->is_check($active_color)) { - throw new RulesException('King is in check. ' . $new_board->export() . ' ' . $active_color); - } - $this->set_board($new_board); - } - /** * Perform a move. */ diff --git a/tests/unit/FENTest.php b/tests/unit/FENTest.php index 0f55abd..6fa3b5e 100644 --- a/tests/unit/FENTest.php +++ b/tests/unit/FENTest.php @@ -139,66 +139,138 @@ public function testCastling() : void $this->assertEquals('-', $fen->get_castling()); } - public function testSetCastlingInvalid1() : void + public function testSetCastlingInvalidString() : void { $fen = new FEN; $this->expectException(ParseException::class); + $this->expectExceptionMessage("Invalid castling right 'K' in string 'KQxq'."); + // this is Shredder FEN and the first invalid castling right is 'K' $fen->set_castling('KQxq'); } - public function testSetCastlingInvalid2() : void + public function testSetCastlingInvalidStringMixShredder() : void { $fen = new FEN; $this->expectException(ParseException::class); - $fen->set_castling('KQah'); + $this->expectExceptionMessage("Invalid castling right 'k' in string 'AHkq'."); + // this is Shredder FEN and the first invalid castling right is 'k' + $fen->set_castling('AHkq'); } - public function testSetCastlingInvalid3() : void + public function testSetCastlingInvalidStringMixFiles1() : void + { + $fen = new FEN; + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Multiple queen's rook castling rights in string 'AHbh'."); + $fen->set_castling('AHbh'); + } + + public function testSetCastlingInvalidStringMixFiles2() : void + { + $fen = new FEN; + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Multiple queen's rook castling rights in string 'BHah'."); + $fen->set_castling('BHah'); + } + + public function testSetCastlingInvalidStringMixFiles3() : void + { + $fen = new FEN; + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Multiple king's rook castling rights in string 'AHag'."); + $fen->set_castling('AHag'); + } + + public function testSetCastlingInvalidStringMixFiles4() : void + { + $fen = new FEN; + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Multiple king's rook castling rights in string 'AGah'."); + $fen->set_castling('AGah'); + } + + public function testSetCastlingInvalidBlackQueenRookPosition() : void + { + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Invalid castling string. Black queen's rook not in initial position."); + $fen = new FEN('nrbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHah - 0 1'); + } + + public function testSetCastlingInvalidWhiteQueenRookPosition() : void + { + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Invalid castling string. White queen's rook not in initial position."); + $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/NRBQKBNR w AHah - 0 1'); + } + + public function testSetCastlingInvalidInvalidBlackKingRookPosition() : void + { + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Invalid castling string. Black king's rook not in initial position."); + $fen = new FEN('rnbqkbrn/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHah - 0 1'); + } + + public function testSetCastlingInvalidInvalidWhiteKingRookPosition() : void + { + $this->expectException(ParseException::class); + $this->expectExceptionMessage("Invalid castling string. White king's rook not in initial position."); + $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBRN w AHah - 0 1'); + } + + public function testSetCastlingInvalidBlackQueenRookPosition2() : void { $this->expectException(ParseException::class); - $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHbh - 0 1'); + $this->expectExceptionMessage("Invalid castling string. Black queen's rook not in initial position."); + $fen = new FEN('nrbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'); } - public function testSetCastlingInvalid4() : void + public function testSetCastlingInvalidWhiteQueenRookPosition2() : void { $this->expectException(ParseException::class); - $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHag - 0 1'); + $this->expectExceptionMessage("Invalid castling string. White queen's rook not in initial position."); + $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/NRBQKBNR w KQkq - 0 1'); } - public function testSetCastlingInvalid5() : void + public function testSetCastlingInvalidInvalidBlackKingRookPosition2() : void { $this->expectException(ParseException::class); - $fen = new FEN('rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKqBNR w KQkq - 0 1'); + $this->expectExceptionMessage("Invalid castling string. Black king's rook not in initial position."); + $fen = new FEN('rnbqkbrn/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'); } - public function testSetCastlingInvalid6() : void + public function testSetCastlingInvalidInvalidWhiteKingRookPosition2() : void { $this->expectException(ParseException::class); - $fen = new FEN('nrbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/NRBQKBNR w KQkq - 0 1'); + $this->expectExceptionMessage("Invalid castling string. White king's rook not in initial position."); + $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBRN w KQkq - 0 1'); } - public function testSetCastlingInvalid7() : void + public function testSetCastlingInvalidWhiteKingPosition() : void { $this->expectException(ParseException::class); - $fen = new FEN('rnbqkbrn/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBRN w KQkq - 0 1'); + $this->expectExceptionMessage("Invalid castling string. White king not in initial position."); + $fen = new FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w KQkq - 0 1'); } - public function testSetCastlingInvalid8() : void + public function testSetCastlingInvalidBlackKingPosition() : void { $this->expectException(ParseException::class); - $fen = new FEN('rnbqkbrn/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBRN w AHah - 0 1'); + $this->expectExceptionMessage("Invalid castling string. Black king not in initial position."); + $fen = new FEN('rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'); } - public function testSetCastlingInvalid9() : void + public function testSetCastlingInvalidKingsNotBetweenRooks() : void { $this->expectException(ParseException::class); + $this->expectExceptionMessage("Multiple queen's rook castling rights in string 'ADad'."); $fen = new FEN('rnbrkbqn/pppppppp/8/8/8/8/PPPPPPPP/RNBRKBQN w ADad - 0 1'); } - public function testSetCastlingInvalid10() : void + public function testSetCastlingInvalidKingsNotBetweenRooks2() : void { $this->expectException(ParseException::class); - $fen = new FEN('qnbnkbrr/pppppppp/8/8/8/8/PPPPPPPP/qNBNKBRR w GHgh - 0 1'); + $this->expectExceptionMessage("Multiple king's rook castling rights in string 'GHgh'."); + $fen = new FEN('qnbnkbrr/pppppppp/8/8/8/8/PPPPPPPP/QNBNKBRR w GHgh - 0 1'); } public function testFiftyMove() : void