mirror of
https://github.com/sigmasternchen/php-chess
synced 2025-03-14 23:58:53 +00:00
feat: Add fifty-move-rule
This commit is contained in:
parent
78f6ba6ef2
commit
1d9f6f5736
2 changed files with 136 additions and 0 deletions
|
@ -13,6 +13,9 @@ class Game {
|
|||
|
||||
private ?array $moveCache = null;
|
||||
|
||||
private int $movesSinceLastCapture = 0;
|
||||
private int $movesSinceLastPawnMove = 0;
|
||||
|
||||
public function __construct(array $pieces, Side $current) {
|
||||
$this->pieces = $pieces;
|
||||
$this->current = $current;
|
||||
|
@ -281,6 +284,9 @@ class Game {
|
|||
public function applyInPlace(Move $move): void {
|
||||
$this->tick();
|
||||
|
||||
$this->movesSinceLastPawnMove++;
|
||||
$this->movesSinceLastCapture++;
|
||||
|
||||
if ($move->castleWith) {
|
||||
$king = $this->findPiece($move->piece);
|
||||
$rook = $this->findPiece($move->castleWith);
|
||||
|
@ -294,7 +300,12 @@ class Game {
|
|||
} else {
|
||||
if ($move->captures) {
|
||||
$this->removePiece($move->captures);
|
||||
$this->movesSinceLastCapture = 0;
|
||||
}
|
||||
if ($move->piece instanceof Pawn) {
|
||||
$this->movesSinceLastPawnMove = 0;
|
||||
}
|
||||
|
||||
if ($move->promoteTo) {
|
||||
$this->removePiece($move->piece);
|
||||
|
||||
|
@ -352,6 +363,15 @@ class Game {
|
|||
}
|
||||
}
|
||||
|
||||
public function _testFiftyMoveRule(int $movesSinceLastCapture, int $movesSinceLastPawnMove) {
|
||||
$this->movesSinceLastPawnMove = $movesSinceLastPawnMove;
|
||||
$this->movesSinceLastCapture = $movesSinceLastCapture;
|
||||
}
|
||||
|
||||
private function isFiftyMoveRule(): bool {
|
||||
return $this->movesSinceLastCapture >= 50 && $this->movesSinceLastPawnMove >= 50;
|
||||
}
|
||||
|
||||
public function getGameState(bool $onlyIsLegal = false): GameState {
|
||||
$allOccupied = $this->getAllOccupied();
|
||||
|
||||
|
@ -371,6 +391,10 @@ class Game {
|
|||
return GameState::DEAD_POSITION;
|
||||
}
|
||||
|
||||
if ($this->isFiftyMoveRule()) {
|
||||
return GameState::FIFTY_MOVE_RULE;
|
||||
}
|
||||
|
||||
$legalMoves = $this->getLegalMoves();
|
||||
|
||||
if ($this->isCheck($allOccupied)) {
|
||||
|
|
|
@ -351,6 +351,118 @@ final class GameTest extends TestCase {
|
|||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_fiftyMoveRule() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(2, 7), Side::WHITE, true),
|
||||
new King(new Position(0, 0), Side::BLACK, true),
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
$subject->_testFiftyMoveRule(49, 49);
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
|
||||
$subject->applyInPlace(new Move(
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
new Position(3, 0)
|
||||
));
|
||||
|
||||
echo $subject->visualize();
|
||||
|
||||
$this->assertEquals(GameState::FIFTY_MOVE_RULE, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_fiftyMoveRule_notLongEnoughSincePawnMove() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(2, 7), Side::WHITE, true),
|
||||
new King(new Position(0, 0), Side::BLACK, true),
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
$subject->_testFiftyMoveRule(49, 48);
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
|
||||
$subject->applyInPlace(new Move(
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
new Position(3, 0)
|
||||
));
|
||||
|
||||
echo $subject->visualize();
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_fiftyMoveRule_notLongEnoughSinceCapture() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(2, 7), Side::WHITE, true),
|
||||
new King(new Position(0, 0), Side::BLACK, true),
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
$subject->_testFiftyMoveRule(48, 49);
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
|
||||
$subject->applyInPlace(new Move(
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
new Position(3, 0)
|
||||
));
|
||||
|
||||
echo $subject->visualize();
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_fiftyMoveRule_capture() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(2, 7), Side::WHITE, true),
|
||||
new King(new Position(0, 0), Side::BLACK, true),
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
new Bishop(new Position(3, 0), Side::WHITE),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
$subject->_testFiftyMoveRule(49, 49);
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
|
||||
$subject->applyInPlace(new Move(
|
||||
new Rook(new Position(1, 0), Side::BLACK),
|
||||
new Position(3, 0),
|
||||
new Bishop(new Position(3, 0), Side::WHITE)
|
||||
));
|
||||
|
||||
echo $subject->visualize();
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_fiftyMoveRule_pawnMove() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(2, 7), Side::WHITE, true),
|
||||
new King(new Position(0, 0), Side::BLACK, true),
|
||||
new Pawn(new Position(6, 5), Side::BLACK, true)
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
$subject->_testFiftyMoveRule(49, 49);
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
|
||||
$subject->applyInPlace(new Move(
|
||||
new Pawn(new Position(6, 5), Side::BLACK),
|
||||
new Position(6, 4),
|
||||
));
|
||||
|
||||
echo $subject->visualize();
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testLegalMoves_pawnPinnedBecauseOfCheckKingRestrictedByQueenAndPawn() {
|
||||
$subject = new Game(
|
||||
[
|
||||
|
|
Loading…
Reference in a new issue