@connectorvol/chessops 0.16.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{esm/attacks.js → attacks.js} +2 -3
- package/dist/{esm/board.js → board.js} +25 -9
- package/dist/{esm/chess.js → chess.js} +24 -18
- package/dist/{esm/compat.js → compat.js} +1 -2
- package/dist/{esm/debug.js → debug.js} +0 -1
- package/dist/{esm/fen.js → fen.js} +1 -2
- package/dist/{types/index.d.ts → index.d.ts} +6 -3
- package/dist/{esm/index.js → index.js} +1 -2
- package/dist/{esm/pgn.js → pgn.js} +54 -34
- package/dist/pgnOps.svelte.d.ts +31 -0
- package/dist/pgnOps.svelte.js +122 -0
- package/dist/{esm/san.js → san.js} +2 -5
- package/dist/{esm/setup.js → setup.js} +29 -26
- package/dist/{esm/squareSet.js → squareSet.js} +17 -16
- package/dist/{esm/transform.js → transform.js} +10 -14
- package/dist/{esm/types.js → types.js} +0 -1
- package/dist/{esm/util.js → util.js} +0 -1
- package/dist/{types/variant.d.ts → variant.d.ts} +2 -1
- package/dist/{esm/variant.js → variant.js} +21 -26
- package/package.json +31 -59
- package/dist/cjs/attacks.js +0 -152
- package/dist/cjs/attacks.js.map +0 -1
- package/dist/cjs/board.js +0 -143
- package/dist/cjs/board.js.map +0 -1
- package/dist/cjs/chess.js +0 -638
- package/dist/cjs/chess.js.map +0 -1
- package/dist/cjs/compat.js +0 -89
- package/dist/cjs/compat.js.map +0 -1
- package/dist/cjs/debug.js +0 -103
- package/dist/cjs/debug.js.map +0 -1
- package/dist/cjs/fen.js +0 -325
- package/dist/cjs/fen.js.map +0 -1
- package/dist/cjs/index.js +0 -94
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/pgn.js +0 -796
- package/dist/cjs/pgn.js.map +0 -1
- package/dist/cjs/san.js +0 -174
- package/dist/cjs/san.js.map +0 -1
- package/dist/cjs/setup.js +0 -167
- package/dist/cjs/setup.js.map +0 -1
- package/dist/cjs/squareSet.js +0 -206
- package/dist/cjs/squareSet.js.map +0 -1
- package/dist/cjs/transform.js +0 -57
- package/dist/cjs/transform.js.map +0 -1
- package/dist/cjs/types.js +0 -24
- package/dist/cjs/types.js.map +0 -1
- package/dist/cjs/util.js +0 -104
- package/dist/cjs/util.js.map +0 -1
- package/dist/cjs/variant.js +0 -833
- package/dist/cjs/variant.js.map +0 -1
- package/dist/esm/attacks.js.map +0 -1
- package/dist/esm/board.js.map +0 -1
- package/dist/esm/chess.js.map +0 -1
- package/dist/esm/compat.js.map +0 -1
- package/dist/esm/debug.js.map +0 -1
- package/dist/esm/fen.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/pgn.js.map +0 -1
- package/dist/esm/san.js.map +0 -1
- package/dist/esm/setup.js.map +0 -1
- package/dist/esm/squareSet.js.map +0 -1
- package/dist/esm/transform.js.map +0 -1
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/util.js.map +0 -1
- package/dist/esm/variant.js.map +0 -1
- package/src/attacks.ts +0 -160
- package/src/board.ts +0 -168
- package/src/chess.ts +0 -687
- package/src/compat.ts +0 -120
- package/src/debug.ts +0 -100
- package/src/fen.ts +0 -328
- package/src/index.ts +0 -85
- package/src/pgn.ts +0 -876
- package/src/san.ts +0 -190
- package/src/setup.ts +0 -203
- package/src/squareSet.ts +0 -243
- package/src/transform.ts +0 -49
- package/src/types.ts +0 -93
- package/src/util.ts +0 -116
- package/src/variant.ts +0 -939
- /package/dist/{types/attacks.d.ts → attacks.d.ts} +0 -0
- /package/dist/{types/board.d.ts → board.d.ts} +0 -0
- /package/dist/{types/chess.d.ts → chess.d.ts} +0 -0
- /package/dist/{types/compat.d.ts → compat.d.ts} +0 -0
- /package/dist/{types/debug.d.ts → debug.d.ts} +0 -0
- /package/dist/{types/fen.d.ts → fen.d.ts} +0 -0
- /package/dist/{types/pgn.d.ts → pgn.d.ts} +0 -0
- /package/dist/{types/san.d.ts → san.d.ts} +0 -0
- /package/dist/{types/setup.d.ts → setup.d.ts} +0 -0
- /package/dist/{types/squareSet.d.ts → squareSet.d.ts} +0 -0
- /package/dist/{types/transform.d.ts → transform.d.ts} +0 -0
- /package/dist/{types/types.d.ts → types.d.ts} +0 -0
- /package/dist/{types/util.d.ts → util.d.ts} +0 -0
package/src/attacks.ts
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compute attacks and rays.
|
|
3
|
-
*
|
|
4
|
-
* These are low-level functions that can be used to implement chess rules.
|
|
5
|
-
*
|
|
6
|
-
* Implementation notes: Sliding attacks are computed using
|
|
7
|
-
* [Hyperbola Quintessence](https://www.chessprogramming.org/Hyperbola_Quintessence).
|
|
8
|
-
* Magic Bitboards would deliver slightly faster lookups, but also require
|
|
9
|
-
* initializing considerably larger attack tables. On the web, initialization
|
|
10
|
-
* time is important, so the chosen method may strike a better balance.
|
|
11
|
-
*
|
|
12
|
-
* @packageDocumentation
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { SquareSet } from "./squareSet.js";
|
|
16
|
-
import { BySquare, Color, Piece, Square } from "./types.js";
|
|
17
|
-
import { squareFile, squareRank } from "./util.js";
|
|
18
|
-
|
|
19
|
-
const computeRange = (square: Square, deltas: number[]): SquareSet => {
|
|
20
|
-
let range = SquareSet.empty();
|
|
21
|
-
for (const delta of deltas) {
|
|
22
|
-
const sq = square + delta;
|
|
23
|
-
if (0 <= sq && sq < 64 && Math.abs(squareFile(square) - squareFile(sq)) <= 2) {
|
|
24
|
-
range = range.with(sq);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return range;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const tabulate = <T>(f: (square: Square) => T): BySquare<T> => {
|
|
31
|
-
const table = [];
|
|
32
|
-
for (let square = 0; square < 64; square++) table[square] = f(square);
|
|
33
|
-
return table;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const KING_ATTACKS = tabulate((sq) => computeRange(sq, [-9, -8, -7, -1, 1, 7, 8, 9]));
|
|
37
|
-
const KNIGHT_ATTACKS = tabulate((sq) => computeRange(sq, [-17, -15, -10, -6, 6, 10, 15, 17]));
|
|
38
|
-
const PAWN_ATTACKS = {
|
|
39
|
-
white: tabulate((sq) => computeRange(sq, [7, 9])),
|
|
40
|
-
black: tabulate((sq) => computeRange(sq, [-7, -9])),
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Gets squares attacked or defended by a king on `square`.
|
|
45
|
-
*/
|
|
46
|
-
export const kingAttacks = (square: Square): SquareSet => KING_ATTACKS[square];
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Gets squares attacked or defended by a knight on `square`.
|
|
50
|
-
*/
|
|
51
|
-
export const knightAttacks = (square: Square): SquareSet => KNIGHT_ATTACKS[square];
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Gets squares attacked or defended by a pawn of the given `color`
|
|
55
|
-
* on `square`.
|
|
56
|
-
*/
|
|
57
|
-
export const pawnAttacks = (color: Color, square: Square): SquareSet => PAWN_ATTACKS[color][square];
|
|
58
|
-
|
|
59
|
-
const FILE_RANGE = tabulate((sq) => SquareSet.fromFile(squareFile(sq)).without(sq));
|
|
60
|
-
const RANK_RANGE = tabulate((sq) => SquareSet.fromRank(squareRank(sq)).without(sq));
|
|
61
|
-
|
|
62
|
-
const DIAG_RANGE = tabulate((sq) => {
|
|
63
|
-
const diag = new SquareSet(0x0804_0201, 0x8040_2010);
|
|
64
|
-
const shift = 8 * (squareRank(sq) - squareFile(sq));
|
|
65
|
-
return (shift >= 0 ? diag.shl64(shift) : diag.shr64(-shift)).without(sq);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const ANTI_DIAG_RANGE = tabulate((sq) => {
|
|
69
|
-
const diag = new SquareSet(0x1020_4080, 0x0102_0408);
|
|
70
|
-
const shift = 8 * (squareRank(sq) + squareFile(sq) - 7);
|
|
71
|
-
return (shift >= 0 ? diag.shl64(shift) : diag.shr64(-shift)).without(sq);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const hyperbola = (bit: SquareSet, range: SquareSet, occupied: SquareSet): SquareSet => {
|
|
75
|
-
let forward = occupied.intersect(range);
|
|
76
|
-
let reverse = forward.bswap64(); // Assumes no more than 1 bit per rank
|
|
77
|
-
forward = forward.minus64(bit);
|
|
78
|
-
reverse = reverse.minus64(bit.bswap64());
|
|
79
|
-
return forward.xor(reverse.bswap64()).intersect(range);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const fileAttacks = (square: Square, occupied: SquareSet): SquareSet =>
|
|
83
|
-
hyperbola(SquareSet.fromSquare(square), FILE_RANGE[square], occupied);
|
|
84
|
-
|
|
85
|
-
const rankAttacks = (square: Square, occupied: SquareSet): SquareSet => {
|
|
86
|
-
const range = RANK_RANGE[square];
|
|
87
|
-
let forward = occupied.intersect(range);
|
|
88
|
-
let reverse = forward.rbit64();
|
|
89
|
-
forward = forward.minus64(SquareSet.fromSquare(square));
|
|
90
|
-
reverse = reverse.minus64(SquareSet.fromSquare(63 - square));
|
|
91
|
-
return forward.xor(reverse.rbit64()).intersect(range);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Gets squares attacked or defended by a bishop on `square`, given `occupied`
|
|
96
|
-
* squares.
|
|
97
|
-
*/
|
|
98
|
-
export const bishopAttacks = (square: Square, occupied: SquareSet): SquareSet => {
|
|
99
|
-
const bit = SquareSet.fromSquare(square);
|
|
100
|
-
return hyperbola(bit, DIAG_RANGE[square], occupied).xor(
|
|
101
|
-
hyperbola(bit, ANTI_DIAG_RANGE[square], occupied),
|
|
102
|
-
);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Gets squares attacked or defended by a rook on `square`, given `occupied`
|
|
107
|
-
* squares.
|
|
108
|
-
*/
|
|
109
|
-
export const rookAttacks = (square: Square, occupied: SquareSet): SquareSet =>
|
|
110
|
-
fileAttacks(square, occupied).xor(rankAttacks(square, occupied));
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Gets squares attacked or defended by a queen on `square`, given `occupied`
|
|
114
|
-
* squares.
|
|
115
|
-
*/
|
|
116
|
-
export const queenAttacks = (square: Square, occupied: SquareSet): SquareSet =>
|
|
117
|
-
bishopAttacks(square, occupied).xor(rookAttacks(square, occupied));
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Gets squares attacked or defended by a `piece` on `square`, given
|
|
121
|
-
* `occupied` squares.
|
|
122
|
-
*/
|
|
123
|
-
export const attacks = (piece: Piece, square: Square, occupied: SquareSet): SquareSet => {
|
|
124
|
-
switch (piece.role) {
|
|
125
|
-
case "pawn":
|
|
126
|
-
return pawnAttacks(piece.color, square);
|
|
127
|
-
case "knight":
|
|
128
|
-
return knightAttacks(square);
|
|
129
|
-
case "bishop":
|
|
130
|
-
return bishopAttacks(square, occupied);
|
|
131
|
-
case "rook":
|
|
132
|
-
return rookAttacks(square, occupied);
|
|
133
|
-
case "queen":
|
|
134
|
-
return queenAttacks(square, occupied);
|
|
135
|
-
case "king":
|
|
136
|
-
return kingAttacks(square);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Gets all squares of the rank, file or diagonal with the two squares
|
|
142
|
-
* `a` and `b`, or an empty set if they are not aligned.
|
|
143
|
-
*/
|
|
144
|
-
export const ray = (a: Square, b: Square): SquareSet => {
|
|
145
|
-
const other = SquareSet.fromSquare(b);
|
|
146
|
-
if (RANK_RANGE[a].intersects(other)) return RANK_RANGE[a].with(a);
|
|
147
|
-
if (ANTI_DIAG_RANGE[a].intersects(other)) return ANTI_DIAG_RANGE[a].with(a);
|
|
148
|
-
if (DIAG_RANGE[a].intersects(other)) return DIAG_RANGE[a].with(a);
|
|
149
|
-
if (FILE_RANGE[a].intersects(other)) return FILE_RANGE[a].with(a);
|
|
150
|
-
return SquareSet.empty();
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Gets all squares between `a` and `b` (bounds not included), or an empty set
|
|
155
|
-
* if they are not on the same rank, file or diagonal.
|
|
156
|
-
*/
|
|
157
|
-
export const between = (a: Square, b: Square): SquareSet =>
|
|
158
|
-
ray(a, b)
|
|
159
|
-
.intersect(SquareSet.full().shl64(a).xor(SquareSet.full().shl64(b)))
|
|
160
|
-
.withoutFirst();
|
package/src/board.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { SquareSet } from "./squareSet.js";
|
|
2
|
-
import { ByColor, ByRole, Color, COLORS, Piece, Role, ROLES, Square } from "./types.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Piece positions on a board.
|
|
6
|
-
*
|
|
7
|
-
* Properties are sets of squares, like `board.occupied` for all occupied
|
|
8
|
-
* squares, `board[color]` for all pieces of that color, and `board[role]`
|
|
9
|
-
* for all pieces of that role. When modifying the properties directly, take
|
|
10
|
-
* care to keep them consistent.
|
|
11
|
-
*/
|
|
12
|
-
export class Board implements Iterable<[Square, Piece]>, ByRole<SquareSet>, ByColor<SquareSet> {
|
|
13
|
-
/**
|
|
14
|
-
* All occupied squares.
|
|
15
|
-
*/
|
|
16
|
-
occupied: SquareSet;
|
|
17
|
-
/**
|
|
18
|
-
* All squares occupied by pieces known to be promoted. This information is
|
|
19
|
-
* relevant in chess variants like Crazyhouse.
|
|
20
|
-
*/
|
|
21
|
-
promoted: SquareSet;
|
|
22
|
-
|
|
23
|
-
white: SquareSet;
|
|
24
|
-
black: SquareSet;
|
|
25
|
-
|
|
26
|
-
pawn: SquareSet;
|
|
27
|
-
knight: SquareSet;
|
|
28
|
-
bishop: SquareSet;
|
|
29
|
-
rook: SquareSet;
|
|
30
|
-
queen: SquareSet;
|
|
31
|
-
king: SquareSet;
|
|
32
|
-
|
|
33
|
-
private constructor() {}
|
|
34
|
-
|
|
35
|
-
static default(): Board {
|
|
36
|
-
const board = new Board();
|
|
37
|
-
board.reset();
|
|
38
|
-
return board;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Resets all pieces to the default starting position for standard chess.
|
|
43
|
-
*/
|
|
44
|
-
reset(): void {
|
|
45
|
-
this.occupied = new SquareSet(0xffff, 0xffff_0000);
|
|
46
|
-
this.promoted = SquareSet.empty();
|
|
47
|
-
this.white = new SquareSet(0xffff, 0);
|
|
48
|
-
this.black = new SquareSet(0, 0xffff_0000);
|
|
49
|
-
this.pawn = new SquareSet(0xff00, 0x00ff_0000);
|
|
50
|
-
this.knight = new SquareSet(0x42, 0x4200_0000);
|
|
51
|
-
this.bishop = new SquareSet(0x24, 0x2400_0000);
|
|
52
|
-
this.rook = new SquareSet(0x81, 0x8100_0000);
|
|
53
|
-
this.queen = new SquareSet(0x8, 0x0800_0000);
|
|
54
|
-
this.king = new SquareSet(0x10, 0x1000_0000);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static empty(): Board {
|
|
58
|
-
const board = new Board();
|
|
59
|
-
board.clear();
|
|
60
|
-
return board;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
clear(): void {
|
|
64
|
-
this.occupied = SquareSet.empty();
|
|
65
|
-
this.promoted = SquareSet.empty();
|
|
66
|
-
for (const color of COLORS) this[color] = SquareSet.empty();
|
|
67
|
-
for (const role of ROLES) this[role] = SquareSet.empty();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
clone(): Board {
|
|
71
|
-
const board = new Board();
|
|
72
|
-
board.occupied = this.occupied;
|
|
73
|
-
board.promoted = this.promoted;
|
|
74
|
-
for (const color of COLORS) board[color] = this[color];
|
|
75
|
-
for (const role of ROLES) board[role] = this[role];
|
|
76
|
-
return board;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
getColor(square: Square): Color | undefined {
|
|
80
|
-
if (this.white.has(square)) return "white";
|
|
81
|
-
if (this.black.has(square)) return "black";
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
getRole(square: Square): Role | undefined {
|
|
86
|
-
for (const role of ROLES) {
|
|
87
|
-
if (this[role].has(square)) return role;
|
|
88
|
-
}
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
get(square: Square): Piece | undefined {
|
|
93
|
-
const color = this.getColor(square);
|
|
94
|
-
if (!color) return;
|
|
95
|
-
const role = this.getRole(square)!;
|
|
96
|
-
const promoted = this.promoted.has(square);
|
|
97
|
-
return { color, role, promoted };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Removes and returns the piece from the given `square`, if any.
|
|
102
|
-
*/
|
|
103
|
-
take(square: Square): Piece | undefined {
|
|
104
|
-
const piece = this.get(square);
|
|
105
|
-
if (piece) {
|
|
106
|
-
this.occupied = this.occupied.without(square);
|
|
107
|
-
this[piece.color] = this[piece.color].without(square);
|
|
108
|
-
this[piece.role] = this[piece.role].without(square);
|
|
109
|
-
if (piece.promoted) this.promoted = this.promoted.without(square);
|
|
110
|
-
}
|
|
111
|
-
return piece;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Put `piece` onto `square`, potentially replacing an existing piece.
|
|
116
|
-
* Returns the existing piece, if any.
|
|
117
|
-
*/
|
|
118
|
-
set(square: Square, piece: Piece): Piece | undefined {
|
|
119
|
-
const old = this.take(square);
|
|
120
|
-
this.occupied = this.occupied.with(square);
|
|
121
|
-
this[piece.color] = this[piece.color].with(square);
|
|
122
|
-
this[piece.role] = this[piece.role].with(square);
|
|
123
|
-
if (piece.promoted) this.promoted = this.promoted.with(square);
|
|
124
|
-
return old;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
has(square: Square): boolean {
|
|
128
|
-
return this.occupied.has(square);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
*[Symbol.iterator](): Iterator<[Square, Piece]> {
|
|
132
|
-
for (const square of this.occupied) {
|
|
133
|
-
yield [square, this.get(square)!];
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
pieces(color: Color, role: Role): SquareSet {
|
|
138
|
-
return this[color].intersect(this[role]);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
rooksAndQueens(): SquareSet {
|
|
142
|
-
return this.rook.union(this.queen);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
bishopsAndQueens(): SquareSet {
|
|
146
|
-
return this.bishop.union(this.queen);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
steppers(): SquareSet {
|
|
150
|
-
return this.knight.union(this.pawn).union(this.king);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
sliders(): SquareSet {
|
|
154
|
-
return this.bishop.union(this.rook).union(this.queen);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Finds the unique king of the given `color`, if any.
|
|
159
|
-
*/
|
|
160
|
-
kingOf(color: Color): Square | undefined {
|
|
161
|
-
return this.pieces(color, "king").singleSquare();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export const boardEquals = (left: Board, right: Board): boolean =>
|
|
166
|
-
left.white.equals(right.white) &&
|
|
167
|
-
left.promoted.equals(right.promoted) &&
|
|
168
|
-
ROLES.every((role) => left[role].equals(right[role]));
|