feat: Add fifty-move-rule

This commit is contained in:
overflowerror 2024-01-07 16:40:54 +01:00
parent 78f6ba6ef2
commit 1d9f6f5736
2 changed files with 136 additions and 0 deletions

View file

@ -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)) {

View file

@ -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(
[