fix: En passant only works the move after

This commit is contained in:
overflowerror 2024-01-06 21:43:02 +01:00
parent e965c8b5af
commit c43de25f9e
4 changed files with 153 additions and 9 deletions

View file

@ -171,7 +171,7 @@ class Game {
if ($this->isCapture($target, $captureableForPawn)) {
$candidate->captures = $this->findCapturedPiece($piece, $opponentPieces, $target);
}
if ($piece->canPromote($target)) {
if ($piece instanceof Pawn && $piece->promotes($target)) {
$candidates = array_merge($candidates, $this->generatePromotionMoves($candidate));
} else {
$candidates[] = $candidate;
@ -216,23 +216,35 @@ class Game {
$this->current,
);
$game->applyInPlace($move);
return $game;
}
private function tick(): void {
foreach ($this->pieces as $piece) {
$piece->tick();
}
}
public function applyInPlace(Move $move): void {
$this->tick();
if ($move->captures) {
$game->removePiece($move->captures);
$this->removePiece($move->captures);
}
if ($move->promoteTo) {
$game->removePiece($move->piece);
$this->removePiece($move->piece);
$promoted = $move->piece->promote($move->promoteTo);
$promoted->move($move->target);
$game->pieces[] = $promoted;
$this->pieces[] = $promoted;
} else {
$piece = $game->findPiece($move->piece);
$piece = $this->findPiece($move->piece);
$piece->move($move->target);
}
$game->current = $game->current->getNext();
return $game;
$this->current = $this->current->getNext();
}
public function getGameState(bool $onlyIsLegal = false): GameState {

View file

@ -71,7 +71,7 @@ class Pawn extends Piece {
return $result;
}
public function canPromote(Position $position): bool {
public function promotes(Position $position): bool {
return ($this->side == Side::WHITE) ? ($position->rank == 7) : ($position->rank == 0);
}
}

View file

@ -301,4 +301,103 @@ final class GameTest extends TestCase {
new Queen(new Position(1, 1), Side::WHITE), null,
), $legalMoves);
}
public function testLegalMoves_enPassantNotPossibleBecauseMoveInBetween() {
$subject = new Game(
[
new King(new Position(0, 1), Side::BLACK),
new King(new Position(0, 7), Side::WHITE),
new Queen(new Position(1, 3), Side::WHITE),
new Pawn(new Position(5, 1), Side::WHITE),
new Pawn(new Position(6, 2), Side::WHITE),
new Pawn(new Position(6, 3), Side::BLACK, true),
],
Side::WHITE
);
$subject->applyInPlace(new Move(
new Pawn(new Position(5, 1), Side::WHITE),
new Position(5, 3)
));
$subject->applyInPlace(new Move(
new King(new Position(0, 1), Side::BLACK),
new Position(0, 0)
));
$subject->applyInPlace(new Move(
new Queen(new Position(1, 3), Side::WHITE),
new Position(1, 4)
));
$legalMoves = $subject->getLegalMoves();
$this->assertCount(1, $legalMoves);
$this->assertContainsEqualsOnce(new Move(
new King(new Position(0, 0), Side::BLACK),
new Position(0, 1),
), $legalMoves);
}
public function testLegalMoves_enPassantNotPossibleBecausePawnDidntMove2Squares() {
$subject = new Game(
[
new King(new Position(0, 0), Side::BLACK),
new King(new Position(0, 7), Side::WHITE),
new Queen(new Position(1, 3), Side::WHITE),
new Pawn(new Position(5, 1), Side::WHITE),
new Pawn(new Position(6, 2), Side::WHITE),
new Pawn(new Position(6, 3), Side::BLACK, true),
],
Side::WHITE
);
$subject->applyInPlace(new Move(
new Pawn(new Position(5, 1), Side::WHITE),
new Position(5, 2)
));
$subject->applyInPlace(new Move(
new King(new Position(0, 0), Side::BLACK),
new Position(0, 1)
));
$subject->applyInPlace(new Move(
new Pawn(new Position(5, 2), Side::WHITE),
new Position(5, 3)
));
$legalMoves = $subject->getLegalMoves();
$this->assertCount(1, $legalMoves);
$this->assertContainsEqualsOnce(new Move(
new King(new Position(0, 1), Side::BLACK),
new Position(0, 0),
), $legalMoves);
}
public function testLegalMoves_enPassantPossible() {
$subject = new Game(
[
new King(new Position(0, 0), Side::BLACK),
new King(new Position(0, 7), Side::WHITE),
new Queen(new Position(1, 2), Side::WHITE),
new Pawn(new Position(5, 1), Side::WHITE),
new Pawn(new Position(6, 2), Side::WHITE),
new Pawn(new Position(6, 3), Side::BLACK, true),
],
Side::WHITE
);
$subject->applyInPlace(new Move(
new Pawn(new Position(5, 1), Side::WHITE),
new Position(5, 3)
));
$legalMoves = $subject->getLegalMoves();
$this->assertCount(1, $legalMoves);
$this->assertContainsEqualsOnce(new Move(
new Pawn(new Position(6, 3), Side::BLACK),
new Position(5, 2),
new Pawn(new Position(5, 3), Side::WHITE),
), $legalMoves);
}
}

View file

@ -243,4 +243,37 @@ final class PawnTest extends TestCase {
]))
);
}
public function testPromotes_no() {
$subject = new Pawn(
new Position(3, 4),
Side::WHITE,
);
$this->assertFalse(
$subject->promotes(new Position(3, 5))
);
}
public function testPromotes_white() {
$subject = new Pawn(
new Position(3, 6),
Side::WHITE,
);
$this->assertTrue(
$subject->promotes(new Position(3, 7))
);
}
public function testPromotes_black() {
$subject = new Pawn(
new Position(3, 1),
Side::BLACK,
);
$this->assertTrue(
$subject->promotes(new Position(3, 0))
);
}
}