Merge pull request #50 from tom-anders/fix-perft

Fix en passant bugs in Atomic and Crazyhouse to make perft tests pass
This commit is contained in:
Vincent Velociter
2026-02-03 18:40:43 +01:00
committed by GitHub
3 changed files with 29 additions and 13 deletions
+15 -6
View File
@@ -54,7 +54,7 @@ abstract class Position {
Pockets? pockets,
Side? turn,
Castles? castles,
Square? epSquare,
Object? epSquare = _uniqueObjectInstance,
int? halfmoves,
int? fullmoves,
(int, int)? remainingChecks,
@@ -567,10 +567,12 @@ abstract class Position {
}
final capturedPiece = castlingSide == null
? board.pieceAt(to)
: to == epSquare && epCaptureTarget != null
? board.pieceAt(epCaptureTarget)
: null;
? (board.pieceAt(to) ??
(to == epSquare && epCaptureTarget != null
? board.pieceAt(epCaptureTarget)
: null))
: null;
final isCapture = capturedPiece != null;
if (capturedPiece != null && capturedPiece.role == Role.rook) {
@@ -596,6 +598,7 @@ abstract class Position {
turn: turn.opposite,
board: board.setPieceAt(to, Piece(color: turn, role: role)),
pockets: pockets?.decrement(turn, role),
epSquare: null,
);
}
}
@@ -1323,9 +1326,15 @@ abstract class Atomic extends Position {
/// board.
@override
Position playUnchecked(Move move) {
if (move is! NormalMove) {
return copyWith();
}
final castlingSide = _getCastlingSide(move);
final capturedPiece = castlingSide == null ? board.pieceAt(move.to) : null;
final isCapture = capturedPiece != null || move.to == epSquare;
final isEnPassant =
move.to == epSquare && board.pieceAt(move.from)?.role == Role.pawn;
final isCapture = capturedPiece != null || isEnPassant;
final newPos = super.playUnchecked(move);
if (isCapture) {
+6 -7
View File
@@ -99,10 +99,10 @@ void main() async {
}
}
});
/*
group('Atomic', () {
final tests =
Parser().parse(File('test/resources/atomic.perft').readAsStringSync());
final tests = Parser()
.parse(io.File('test/resources/atomic.perft').readAsStringSync());
for (final perftTest in tests) {
final position = Atomic.fromSetup(Setup.parseFen(perftTest.fen));
for (final testCase in perftTest.cases
@@ -115,11 +115,10 @@ void main() async {
}
}
});
*/
/*
group('Crazyhouse', () {
final tests = Parser()
.parse(File('test/resources/crazyhouse.perft').readAsStringSync());
.parse(io.File('test/resources/crazyhouse.perft').readAsStringSync());
for (final perftTest in tests) {
final position = Crazyhouse.fromSetup(Setup.parseFen(perftTest.fen));
for (final testCase in perftTest.cases
@@ -132,7 +131,7 @@ void main() async {
}
}
});
*/
group('Horde', () {
final tests = Parser()
.parse(io.File('test/resources/horde.perft').readAsStringSync());
+8
View File
@@ -914,6 +914,14 @@ void main() {
}
});
test('en passant capture', () {
final pos = Crazyhouse.fromSetup(Setup.parseFen(
'r1bqkbnr/ppppp1pp/2n5/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3'))
.play(const NormalMove(from: Square.e5, to: Square.f6));
expect(
pos.pockets, equals(Pockets.empty.increment(Side.white, Role.pawn)));
});
test('parse san', () {
Position position = Crazyhouse.initial;
final moves = [