Skip to content

Commit

Permalink
Merge pull request #41 from lichess-org/square_extension_type
Browse files Browse the repository at this point in the history
Square extension type
  • Loading branch information
veloce authored Aug 1, 2024
2 parents 02d7734 + 2d0be94 commit 8577e98
Show file tree
Hide file tree
Showing 24 changed files with 1,009 additions and 605 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.8.0

### Breaking changes:
- `Square` is now an extension type.
- Introduce `File` and `Rank` types.

## 0.7.1

- Add Piece.kind, Role.letter and Role.uppercaseLetter getters.
Expand Down
10 changes: 3 additions & 7 deletions benchmark/dartchess_benchmark.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:benchmark/benchmark.dart';
import 'package:dartchess/dartchess.dart';
import 'dart:io';
import 'dart:io' as io;

void main() {
benchmark('make fen from initial position', () {
Expand Down Expand Up @@ -37,19 +37,15 @@ void main() {
legalMovesPos.legalMoves.length;
});

benchmark('algebraic legal moves', () {
algebraicLegalMoves(legalMovesPos);
});

benchmark('parsePgn - kasparov-deep-blue', () {
final String data =
File('./data/kasparov-deep-blue-1997.pgn').readAsStringSync();
io.File('./data/kasparov-deep-blue-1997.pgn').readAsStringSync();

PgnGame.parseMultiGamePgn(data);
});

final game = PgnGame.parsePgn(
File('./data/lichess-bullet-game.pgn').readAsStringSync());
io.File('./data/lichess-bullet-game.pgn').readAsStringSync());
benchmark('makePgn', () {
game.makePgn();
});
Expand Down
8 changes: 3 additions & 5 deletions example/dartchess_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ void main() {
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
final pos = Chess.fromSetup(setup);

// Generate legal moves in algebraic notation
final legalMoves = algebraicLegalMoves(pos);
// Generate legal moves
assert(pos.legalMoves.length == 16);

assert(legalMoves['e2']!.length == 2);

const move = NormalMove(from: 12, to: 28);
const move = NormalMove(from: Square.e2, to: Square.e4);

assert(pos.isLegal(move));

Expand Down
20 changes: 7 additions & 13 deletions lib/src/attacks.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import './square_set.dart';
import './utils.dart';
import './models.dart';

/// Gets squares attacked or defended by a king on [Square].
SquareSet kingAttacks(Square square) {
assert(square >= 0 && square < 64);
return _kingAttacks[square];
}

/// Gets squares attacked or defended by a knight on [Square].
SquareSet knightAttacks(Square square) {
assert(square >= 0 && square < 64);
return _knightAttacks[square];
}

/// Gets squares attacked or defended by a pawn of the given [Side] on [Square].
SquareSet pawnAttacks(Side side, Square square) {
assert(square >= 0 && square < 64);
return _pawnAttacks[side]![square];
}

Expand Down Expand Up @@ -89,18 +85,16 @@ SquareSet _computeRange(Square square, List<int> deltas) {
SquareSet range = SquareSet.empty;
for (final delta in deltas) {
final sq = square + delta;
if (0 <= sq &&
sq < 64 &&
(squareFile(square) - squareFile(sq)).abs() <= 2) {
range = range.withSquare(sq);
if (0 <= sq && sq < 64 && (square.file - Square(sq).file).abs() <= 2) {
range = range.withSquare(Square(sq));
}
}
return range;
}

List<T> _tabulate<T>(T Function(Square square) f) {
final List<T> table = [];
for (Square square = 0; square < 64; square++) {
for (final square in Square.values) {
table.insert(square, f(square));
}
return table;
Expand All @@ -116,18 +110,18 @@ final _pawnAttacks = {
};

final _fileRange =
_tabulate((sq) => SquareSet.fromFile(squareFile(sq)).withoutSquare(sq));
_tabulate((sq) => SquareSet.fromFile(sq.file).withoutSquare(sq));
final _rankRange =
_tabulate((sq) => SquareSet.fromRank(squareRank(sq)).withoutSquare(sq));
_tabulate((sq) => SquareSet.fromRank(sq.rank).withoutSquare(sq));
final _diagRange = _tabulate((sq) {
final shift = 8 * (squareRank(sq) - squareFile(sq));
final shift = 8 * (sq.rank - sq.file);
return (shift >= 0
? SquareSet.diagonal.shl(shift)
: SquareSet.diagonal.shr(-shift))
.withoutSquare(sq);
});
final _antiDiagRange = _tabulate((sq) {
final shift = 8 * (squareRank(sq) + squareFile(sq) - 7);
final shift = 8 * (sq.rank + sq.file - 7);
return (shift >= 0
? SquareSet.antidiagonal.shl(shift)
: SquareSet.antidiagonal.shr(-shift))
Expand Down
4 changes: 2 additions & 2 deletions lib/src/board.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class Board {
file += code - 48;
} else {
if (file >= 8 || rank < 0) throw const FenError('ERR_BOARD');
final square = file + rank * 8;
final square = Square(file + rank * 8);
final promoted = i + 1 < boardFen.length && boardFen[i + 1] == '~';
final piece = _charToPiece(c, promoted);
if (piece == null) throw const FenError('ERR_BOARD');
Expand All @@ -147,7 +147,7 @@ class Board {
int empty = 0;
for (int rank = 7; rank >= 0; rank--) {
for (int file = 0; file < 8; file++) {
final square = file + rank * 8;
final square = Square(file + rank * 8);
final piece = pieceAt(square);
if (piece == null) {
empty++;
Expand Down
3 changes: 0 additions & 3 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
const kFileNames = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const kRankNames = ['1', '2', '3', '4', '5', '6', '7', '8'];

/// The board part of the initial position in the FEN format.
const kInitialBoardFEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';

Expand Down
9 changes: 4 additions & 5 deletions lib/src/debug.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import './board.dart';
import './models.dart';
import './position.dart';
import './square_set.dart';
import './utils.dart';

/// Takes a string and returns a SquareSet. Useful for debugging/testing purposes.
///
Expand Down Expand Up @@ -34,7 +33,7 @@ SquareSet makeSquareSet(String rep) {
for (int x = 0; x < 8; x++) {
final repSq = table[y][x];
if (repSq == '1') {
ret = ret.withSquare(x + y * 8);
ret = ret.withSquare(Square(x + y * 8));
}
}
}
Expand All @@ -46,7 +45,7 @@ String humanReadableSquareSet(SquareSet sq) {
final buffer = StringBuffer();
for (int y = 7; y >= 0; y--) {
for (int x = 0; x < 8; x++) {
final square = x + y * 8;
final square = Square(x + y * 8);
buffer.write(sq.has(square) ? '1' : '.');
buffer.write(x < 7 ? ' ' : '\n');
}
Expand All @@ -59,7 +58,7 @@ String humanReadableBoard(Board board) {
final buffer = StringBuffer();
for (int y = 7; y >= 0; y--) {
for (int x = 0; x < 8; x++) {
final square = x + y * 8;
final square = Square(x + y * 8);
final p = board.pieceAt(square);
final col = p != null ? p.fenChar : '.';
buffer.write(col);
Expand Down Expand Up @@ -100,7 +99,7 @@ int perft(Position pos, int depth, {bool shouldLog = false}) {
for (final entry in pos.legalMoves.entries) {
final from = entry.key;
final dests = entry.value;
final promotions = squareRank(from) == (pos.turn == Side.white ? 6 : 1) &&
final promotions = from.rank == (pos.turn == Side.white ? 6 : 1) &&
pos.board.pawns.has(from)
? promotionRoles
: [null];
Expand Down
Loading

0 comments on commit 8577e98

Please sign in to comment.