mirror of
https://github.com/sigmasternchen/php-chess
synced 2025-03-15 07:58:54 +00:00
feat: Game recognized castles as valid moves
This commit is contained in:
parent
5c1bab71df
commit
11d9e04f07
3 changed files with 101 additions and 4 deletions
|
@ -152,7 +152,7 @@ class Game {
|
|||
|
||||
private function getCandidateMovesForPiece(
|
||||
Piece $piece,
|
||||
array $opponentPieces,
|
||||
array &$opponentPieces,
|
||||
FieldBitMap $occupied,
|
||||
FieldBitMap $capturableForNonPawn,
|
||||
FieldBitMap $captureableForPawn,
|
||||
|
@ -186,6 +186,33 @@ class Game {
|
|||
return $futureGame->getGameState(true) != GameState::ILLEGAL;
|
||||
}
|
||||
|
||||
private function getCastleMoves(
|
||||
array &$ownPieces,
|
||||
FieldBitMap $occupied,
|
||||
FieldBitMap $capturable,
|
||||
FieldBitMap $threatened
|
||||
): array {
|
||||
$king = $this->getKing($this->current);
|
||||
return array_values(
|
||||
array_map(
|
||||
fn($r) => new Move(
|
||||
$king,
|
||||
new Position(
|
||||
$king->getPosition()->file + 2 * ($r->getPosition()->file <=> $king->getPosition()->file),
|
||||
$king->getPosition()->rank,
|
||||
),
|
||||
null,
|
||||
null,
|
||||
$r,
|
||||
),
|
||||
array_filter(
|
||||
array_filter($ownPieces, fn($p) => $p instanceof Rook),
|
||||
fn($r) => $king->canCastle($occupied, $capturable, $threatened, $r)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function getLegalMovesParameterized(
|
||||
array &$ownPieces,
|
||||
array &$opponentPieces,
|
||||
|
@ -207,7 +234,17 @@ class Game {
|
|||
));
|
||||
}
|
||||
|
||||
return array_values(array_filter($candidates, [$this, "isMoveLegal"]));
|
||||
$candidates = array_values(array_filter($candidates, [$this, "isMoveLegal"]));
|
||||
|
||||
// castle moves should always be legal
|
||||
$candidates = array_merge($candidates, $this->getCastleMoves(
|
||||
$ownPieces,
|
||||
$occupied,
|
||||
$capturableNonPawn,
|
||||
$threatened,
|
||||
));
|
||||
|
||||
return $candidates;
|
||||
}
|
||||
|
||||
public function apply(Move $move): Game {
|
||||
|
|
|
@ -7,12 +7,20 @@ class Move {
|
|||
public Position $target;
|
||||
public ?Piece $captures = null;
|
||||
public ?PieceType $promoteTo = null;
|
||||
public ?Piece $castleWith = null;
|
||||
|
||||
public function __construct(Piece $piece, Position $target, ?Piece $captures = null, ?PieceType $promoteTo = null) {
|
||||
public function __construct(
|
||||
Piece $piece,
|
||||
Position $target,
|
||||
?Piece $captures = null,
|
||||
?PieceType $promoteTo = null,
|
||||
?Piece $castleWith = null,
|
||||
) {
|
||||
$this->piece = $piece;
|
||||
$this->target = $target;
|
||||
$this->captures = $captures;
|
||||
$this->promoteTo = $promoteTo;
|
||||
$this->castleWith = $castleWith;
|
||||
}
|
||||
|
||||
public function equals(Move $move): bool {
|
||||
|
@ -22,7 +30,11 @@ class Move {
|
|||
($this->captures != null && $move->captures != null && $this->captures->equals($move->captures)) ||
|
||||
($this->captures == null && $move->captures == null)
|
||||
) &&
|
||||
$this->promoteTo == $move->promoteTo;
|
||||
$this->promoteTo == $move->promoteTo &&
|
||||
(
|
||||
($this->castleWith != null && $move->castleWith != null && $this->castleWith->equals($move->castleWith)) ||
|
||||
($this->castleWith == null && $move->castleWith == null)
|
||||
);
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
|
|
|
@ -400,4 +400,52 @@ final class GameTest extends TestCase {
|
|||
new Pawn(new Position(5, 3), Side::WHITE),
|
||||
), $legalMoves);
|
||||
}
|
||||
|
||||
public function testLegalMoves_castle() {
|
||||
$subject = new Game(
|
||||
[
|
||||
new King(new Position(0, 7), Side::BLACK),
|
||||
new King(new Position(4, 0), Side::WHITE),
|
||||
new Queen(new Position(2, 1), Side::BLACK),
|
||||
new Rook(new Position(7, 0), Side::WHITE),
|
||||
new Rook(new Position(7, 1), Side::BLACK),
|
||||
],
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$legalMoves = $subject->getLegalMoves();
|
||||
|
||||
echo join("\n", $legalMoves);
|
||||
|
||||
$this->assertCount(5, $legalMoves);
|
||||
|
||||
$this->assertContainsEqualsOnce(new Move(
|
||||
new King(new Position(4, 0), Side::BLACK),
|
||||
new Position(5, 0),
|
||||
), $legalMoves);
|
||||
|
||||
$this->assertContainsEqualsOnce(new Move(
|
||||
new King(new Position(4, 0), Side::BLACK),
|
||||
new Position(6, 0),
|
||||
null,
|
||||
null,
|
||||
new Rook(new Position(7, 0), Side::WHITE),
|
||||
), $legalMoves);
|
||||
|
||||
$this->assertContainsEqualsOnce(new Move(
|
||||
new Rook(new Position(7, 0), Side::WHITE),
|
||||
new Position(6, 0),
|
||||
), $legalMoves);
|
||||
|
||||
$this->assertContainsEqualsOnce(new Move(
|
||||
new Rook(new Position(7, 0), Side::WHITE),
|
||||
new Position(5, 0),
|
||||
), $legalMoves);
|
||||
|
||||
$this->assertContainsEqualsOnce(new Move(
|
||||
new Rook(new Position(7, 0), Side::WHITE),
|
||||
new Position(7, 1),
|
||||
new Rook(new Position(7, 1), Side::BLACK),
|
||||
), $legalMoves);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue