mirror of
https://github.com/lichess-org/dartchess.git
synced 2026-05-26 13:51:01 +00:00
Improve Position types
This commit is contained in:
@@ -16,7 +16,7 @@ void main() {
|
||||
benchmark('parse san moves', () {
|
||||
const moves =
|
||||
'e4 Nc6 Bc4 e6 a3 g6 Nf3 Bg7 c3 Nge7 d3 O-O Be3 Na5 Ba2 b6 Qd2 Bb7 Bh6 d5 e5 d4 Bxg7 Kxg7 Qf4 Bxf3 Qxf3 dxc3 Nxc3 Nac6 Qf6+ Kg8 Rd1 Nd4 O-O c5 Ne4 Nef5 Rd2 Qxf6 Nxf6+ Kg7 Re1 h5 h3 Rad8 b4 Nh4 Re3 Nhf5 Re1 a5 bxc5 bxc5 Bc4 Ra8 Rb1 Nh4 Rdb2 Nc6 Rb7 Nxe5 Bxe6 Kxf6 Bd5 Nf5 R7b6+ Kg7 Bxa8 Rxa8 R6b3 Nd4 Rb7 Nxd3 Rd1 Ne2+ Kh2 Ndf4 Rdd7 Rf8 Ra7 c4 Rxa5 c3 Rc5 Ne6 Rc4 Ra8 a4 Rb8 a5 Rb2 a6 c2';
|
||||
Position pos = Chess.initial;
|
||||
Chess pos = Chess.initial;
|
||||
for (final san in moves.split(' ')) {
|
||||
pos = pos.play(pos.parseSan(san)!);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ void main() {
|
||||
benchmark('parse san moves, play unchecked', () {
|
||||
const moves =
|
||||
'e4 Nc6 Bc4 e6 a3 g6 Nf3 Bg7 c3 Nge7 d3 O-O Be3 Na5 Ba2 b6 Qd2 Bb7 Bh6 d5 e5 d4 Bxg7 Kxg7 Qf4 Bxf3 Qxf3 dxc3 Nxc3 Nac6 Qf6+ Kg8 Rd1 Nd4 O-O c5 Ne4 Nef5 Rd2 Qxf6 Nxf6+ Kg7 Re1 h5 h3 Rad8 b4 Nh4 Re3 Nhf5 Re1 a5 bxc5 bxc5 Bc4 Ra8 Rb1 Nh4 Rdb2 Nc6 Rb7 Nxe5 Bxe6 Kxf6 Bd5 Nf5 R7b6+ Kg7 Bxa8 Rxa8 R6b3 Nd4 Rb7 Nxd3 Rd1 Ne2+ Kh2 Ndf4 Rdd7 Rf8 Ra7 c4 Rxa5 c3 Rc5 Ne6 Rc4 Ra8 a4 Rb8 a5 Rb2 a6 c2';
|
||||
Position pos = Chess.initial;
|
||||
Chess pos = Chess.initial;
|
||||
for (final san in moves.split(' ')) {
|
||||
pos = pos.playUnchecked(pos.parseSan(san)!);
|
||||
}
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ final _promotionRoles = [Role.queen, Role.rook, Role.knight, Role.bishop];
|
||||
///
|
||||
/// Computing perft numbers is useful for comparing, testing and debugging move
|
||||
/// generation correctness and performance.
|
||||
int perft(Position pos, int depth, {bool shouldLog = false}) {
|
||||
int perft<T extends Position<T>>(T pos, int depth, {bool shouldLog = false}) {
|
||||
if (depth < 1) return 1;
|
||||
|
||||
final promotionRoles =
|
||||
|
||||
+3
-3
@@ -144,17 +144,17 @@ class PgnGame<T extends PgnNodeData> {
|
||||
/// Headers can include an optional 'Variant' and 'Fen' key.
|
||||
///
|
||||
/// Throws a [PositionSetupException] if it does not meet basic validity requirements.
|
||||
static Position startingPosition(PgnHeaders headers,
|
||||
static T startingPosition<T extends Position<T>>(PgnHeaders headers,
|
||||
{bool? ignoreImpossibleCheck}) {
|
||||
final rule = Rule.fromPgn(headers['Variant']);
|
||||
if (rule == null) throw PositionSetupException.variant;
|
||||
if (!headers.containsKey('FEN')) {
|
||||
return Position.initialPosition(rule);
|
||||
return Position.initialPosition(rule) as T;
|
||||
}
|
||||
final fen = headers['FEN']!;
|
||||
try {
|
||||
return Position.setupPosition(rule, Setup.parseFen(fen),
|
||||
ignoreImpossibleCheck: ignoreImpossibleCheck);
|
||||
ignoreImpossibleCheck: ignoreImpossibleCheck) as T;
|
||||
} catch (err) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
+7
-14
@@ -49,7 +49,7 @@ abstract class Position<T extends Position<T>> {
|
||||
Rule get rule;
|
||||
|
||||
/// Creates a copy of this position with some fields changed.
|
||||
Position<T> copyWith({
|
||||
T copyWith({
|
||||
Board? board,
|
||||
Pockets? pockets,
|
||||
Side? turn,
|
||||
@@ -509,7 +509,7 @@ abstract class Position<T extends Position<T>> {
|
||||
/// Plays a move and returns the updated [Position].
|
||||
///
|
||||
/// Throws a [PlayException] if the move is not legal.
|
||||
Position<T> play(Move move) {
|
||||
T play(Move move) {
|
||||
if (isLegal(move)) {
|
||||
return playUnchecked(move);
|
||||
} else {
|
||||
@@ -518,7 +518,7 @@ abstract class Position<T extends Position<T>> {
|
||||
}
|
||||
|
||||
/// Plays a move without checking if the move is legal and returns the updated [Position].
|
||||
Position<T> playUnchecked(Move move) {
|
||||
T playUnchecked(Move move) {
|
||||
switch (move) {
|
||||
case NormalMove(from: final from, to: final to, promotion: final prom):
|
||||
final piece = board.pieceAt(from);
|
||||
@@ -600,7 +600,7 @@ abstract class Position<T extends Position<T>> {
|
||||
}
|
||||
|
||||
/// Returns the SAN of this [Move] and the updated [Position], without checking if the move is legal.
|
||||
(Position<T>, String) makeSanUnchecked(Move move) {
|
||||
(T, String) makeSanUnchecked(Move move) {
|
||||
final san = _makeSanWithoutSuffix(move);
|
||||
final newPos = playUnchecked(move);
|
||||
final suffixed = newPos.outcome?.winner != null
|
||||
@@ -614,7 +614,7 @@ abstract class Position<T extends Position<T>> {
|
||||
/// Returns the SAN of this [Move] and the updated [Position].
|
||||
///
|
||||
/// Throws a [PlayException] if the move is not legal.
|
||||
(Position<T>, String) makeSan(Move move) {
|
||||
(T, String) makeSan(Move move) {
|
||||
if (isLegal(move)) {
|
||||
return makeSanUnchecked(move);
|
||||
} else {
|
||||
@@ -1336,7 +1336,7 @@ abstract class Atomic extends Position<Atomic> {
|
||||
final castlingSide = _getCastlingSide(move);
|
||||
final capturedPiece = castlingSide == null ? board.pieceAt(move.to) : null;
|
||||
final isCapture = capturedPiece != null || move.to == epSquare;
|
||||
final newPos = super.playUnchecked(move) as Atomic;
|
||||
final newPos = super.playUnchecked(move);
|
||||
|
||||
if (isCapture) {
|
||||
Castles newCastles = newPos.castles;
|
||||
@@ -1753,7 +1753,7 @@ abstract class ThreeCheck extends Position<ThreeCheck> {
|
||||
|
||||
@override
|
||||
ThreeCheck playUnchecked(Move move) {
|
||||
final newPos = super.playUnchecked(move) as ThreeCheck;
|
||||
final newPos = super.playUnchecked(move);
|
||||
if (newPos.isCheck) {
|
||||
final (whiteChecks, blackChecks) = remainingChecks;
|
||||
return newPos.copyWith(
|
||||
@@ -1897,10 +1897,6 @@ abstract class RacingKings extends Position<RacingKings> {
|
||||
@override
|
||||
bool hasInsufficientMaterial(Side side) => false;
|
||||
|
||||
@override
|
||||
RacingKings playUnchecked(Move move) =>
|
||||
super.playUnchecked(move) as RacingKings;
|
||||
|
||||
@override
|
||||
RacingKings copyWith({
|
||||
Board? board,
|
||||
@@ -2233,9 +2229,6 @@ abstract class Horde extends Position<Horde> {
|
||||
@override
|
||||
bool get isVariantEnd => board.white.isEmpty;
|
||||
|
||||
@override
|
||||
Horde playUnchecked(Move move) => super.playUnchecked(move) as Horde;
|
||||
|
||||
@override
|
||||
Horde copyWith({
|
||||
Board? board,
|
||||
|
||||
+2
-2
@@ -227,8 +227,8 @@ void main() {
|
||||
test('transform pgn', () {
|
||||
final game = PgnGame.parsePgn('1. a4 ( 1. b4 b5 -- ) 1... a5');
|
||||
final PgnNode<PgnNodeWithFen> res =
|
||||
game.moves.transform<PgnNodeWithFen, Position>(
|
||||
PgnGame.startingPosition(game.headers),
|
||||
game.moves.transform<PgnNodeWithFen, Chess>(
|
||||
PgnGame.startingPosition<Chess>(game.headers),
|
||||
(pos, data, _) {
|
||||
final move = pos.parseSan(data.san);
|
||||
if (move != null) {
|
||||
|
||||
@@ -104,7 +104,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('parse pawn capture', () {
|
||||
Position pos = Chess.initial;
|
||||
Chess pos = Chess.initial;
|
||||
const line = ['e4', 'd5', 'c4', 'Nf6', 'exd5'];
|
||||
for (final san in line) {
|
||||
pos = pos.play(pos.parseSan(san)!);
|
||||
@@ -124,7 +124,7 @@ void main() {
|
||||
|
||||
test('parse fools mate', () {
|
||||
const moves = ['e4', 'e5', 'Qh5', 'Nf6', 'Bc4', 'Nc6', 'Qxf7#'];
|
||||
Position position = Chess.initial;
|
||||
Chess position = Chess.initial;
|
||||
for (final move in moves) {
|
||||
position = position.play(position.parseSan(move)!);
|
||||
}
|
||||
@@ -807,7 +807,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('parse san', () {
|
||||
Position position = Antichess.initial;
|
||||
Antichess position = Antichess.initial;
|
||||
final moves = [
|
||||
'g3',
|
||||
'Nh6',
|
||||
@@ -892,7 +892,7 @@ void main() {
|
||||
'Bxh1',
|
||||
'bxa8=K'
|
||||
];
|
||||
Position position = Antichess.initial;
|
||||
Antichess position = Antichess.initial;
|
||||
for (final move in moves) {
|
||||
position = position.play(position.parseSan(move)!);
|
||||
}
|
||||
@@ -915,7 +915,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('parse san', () {
|
||||
Position position = Crazyhouse.initial;
|
||||
Crazyhouse position = Crazyhouse.initial;
|
||||
final moves = [
|
||||
'd4',
|
||||
'd5',
|
||||
@@ -976,7 +976,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('castle checkmates', () {
|
||||
Position position = Crazyhouse.initial;
|
||||
Crazyhouse position = Crazyhouse.initial;
|
||||
final moves = [
|
||||
'd4',
|
||||
'f5',
|
||||
|
||||
Reference in New Issue
Block a user