mirror of
https://github.com/sigmasternchen/php-chess
synced 2025-03-15 07:58:54 +00:00
feat: Add dead positions to game system
This commit is contained in:
parent
b15e5fc922
commit
51d01b0953
3 changed files with 143 additions and 1 deletions
|
@ -33,7 +33,7 @@ class Game {
|
|||
}
|
||||
|
||||
public function getPieces(Side $side): array {
|
||||
return array_filter($this->pieces, fn($p) => $p->getSide() == $side);
|
||||
return array_values(array_filter($this->pieces, fn($p) => $p->getSide() == $side));
|
||||
}
|
||||
|
||||
private function &findPiece(Piece $needle): Piece {
|
||||
|
@ -312,6 +312,46 @@ class Game {
|
|||
$this->history->add($this);
|
||||
}
|
||||
|
||||
private function isDeadPosition(): bool {
|
||||
$ownPieces = $this->getPieces($this->current);
|
||||
$opponentPieces = $this->getPieces($this->current->getNext());
|
||||
|
||||
$getRemaining = function (array $pieces): Piece {
|
||||
return ($pieces[0] instanceof King ? $pieces[1] : $pieces[0]);
|
||||
};
|
||||
|
||||
if (count($ownPieces) > 2) {
|
||||
return false;
|
||||
} else if (count($opponentPieces) > 2) {
|
||||
return false;
|
||||
} else if (count($ownPieces) == 1 && count($opponentPieces) == 1) {
|
||||
return true;
|
||||
} else if (count($ownPieces) == 1) {
|
||||
$opponentRemaining = $getRemaining($opponentPieces);
|
||||
return !(
|
||||
$opponentRemaining instanceof Queen ||
|
||||
$opponentRemaining instanceof Rook ||
|
||||
$opponentRemaining instanceof Pawn
|
||||
);
|
||||
} else if (count($opponentPieces) == 1) {
|
||||
$ownRemaining = $getRemaining($ownPieces);
|
||||
return !(
|
||||
$ownRemaining instanceof Queen ||
|
||||
$ownRemaining instanceof Rook ||
|
||||
$ownRemaining instanceof Pawn
|
||||
);
|
||||
} else { // both have 1 piece left besides king
|
||||
$ownRemaining = $getRemaining($ownPieces);
|
||||
$opponentRemaining = $getRemaining($opponentPieces);
|
||||
|
||||
return (
|
||||
$ownRemaining instanceof Bishop &&
|
||||
$opponentRemaining instanceof Bishop &&
|
||||
$ownRemaining->getPosition()->getSquareColor() == $opponentRemaining->getPosition()->getSquareColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getGameState(bool $onlyIsLegal = false): GameState {
|
||||
$allOccupied = $this->getAllOccupied();
|
||||
|
||||
|
@ -327,6 +367,10 @@ class Game {
|
|||
return GameState::THREEFOLD_REPETITION;
|
||||
}
|
||||
|
||||
if ($this->isDeadPosition()) {
|
||||
return GameState::DEAD_POSITION;
|
||||
}
|
||||
|
||||
$legalMoves = $this->getLegalMoves();
|
||||
|
||||
if ($this->isCheck($allOccupied)) {
|
||||
|
|
|
@ -17,6 +17,10 @@ class Position {
|
|||
$this->rank >= 0 && $this->rank < 8;
|
||||
}
|
||||
|
||||
public function getSquareColor(): Side {
|
||||
return ($this->rank % 2) ^ ($this->file % 2) ? Side::WHITE : Side::BLACK;
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return ["a", "b", "c", "d", "e", "f", "g", "h"][$this->file] . ($this->rank + 1);
|
||||
}
|
||||
|
|
|
@ -140,6 +140,7 @@ final class GameTest extends TestCase {
|
|||
[
|
||||
new King(new Position(1, 1), Side::BLACK, true),
|
||||
new King(new Position(7, 6), Side::WHITE, true),
|
||||
new Pawn(new Position(3, 6), Side::WHITE, true), // to avoid dead position
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
@ -257,6 +258,99 @@ final class GameTest extends TestCase {
|
|||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_onlyKings() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEAD_POSITION, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingVsKingAndBishop() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Bishop(new Position(1, 0), Side::WHITE),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEAD_POSITION, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingVsKingAndKnight() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Knight(new Position(1, 0), Side::WHITE),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEAD_POSITION, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingAndBishopVsKingAndBishopSameColor() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Bishop(new Position(1, 0), Side::WHITE),
|
||||
new Bishop(new Position(2, 1), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEAD_POSITION, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingAndBishopVsKingAndBishopDifferentColor_notDead() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Bishop(new Position(1, 0), Side::WHITE),
|
||||
new Bishop(new Position(1, 1), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingAndKnightVsKing_notDead() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Bishop(new Position(1, 0), Side::WHITE),
|
||||
new Knight(new Position(1, 1), Side::BLACK),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testGameState_deadPosition_kingAndPawnVsKing_notDead() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(0, 5), Side::WHITE),
|
||||
new Pawn(new Position(1, 1), Side::BLACK, true),
|
||||
],
|
||||
Side::BLACK
|
||||
);
|
||||
|
||||
$this->assertEquals(GameState::DEFAULT, $subject->getGameState());
|
||||
}
|
||||
|
||||
public function testLegalMoves_pawnPinnedBecauseOfCheckKingRestrictedByQueenAndPawn() {
|
||||
$subject = new Game(
|
||||
[
|
||||
|
|
Loading…
Reference in a new issue