@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.
Files changed (93) hide show
  1. package/dist/{esm/attacks.js → attacks.js} +2 -3
  2. package/dist/{esm/board.js → board.js} +25 -9
  3. package/dist/{esm/chess.js → chess.js} +24 -18
  4. package/dist/{esm/compat.js → compat.js} +1 -2
  5. package/dist/{esm/debug.js → debug.js} +0 -1
  6. package/dist/{esm/fen.js → fen.js} +1 -2
  7. package/dist/{types/index.d.ts → index.d.ts} +6 -3
  8. package/dist/{esm/index.js → index.js} +1 -2
  9. package/dist/{esm/pgn.js → pgn.js} +54 -34
  10. package/dist/pgnOps.svelte.d.ts +31 -0
  11. package/dist/pgnOps.svelte.js +122 -0
  12. package/dist/{esm/san.js → san.js} +2 -5
  13. package/dist/{esm/setup.js → setup.js} +29 -26
  14. package/dist/{esm/squareSet.js → squareSet.js} +17 -16
  15. package/dist/{esm/transform.js → transform.js} +10 -14
  16. package/dist/{esm/types.js → types.js} +0 -1
  17. package/dist/{esm/util.js → util.js} +0 -1
  18. package/dist/{types/variant.d.ts → variant.d.ts} +2 -1
  19. package/dist/{esm/variant.js → variant.js} +21 -26
  20. package/package.json +31 -59
  21. package/dist/cjs/attacks.js +0 -152
  22. package/dist/cjs/attacks.js.map +0 -1
  23. package/dist/cjs/board.js +0 -143
  24. package/dist/cjs/board.js.map +0 -1
  25. package/dist/cjs/chess.js +0 -638
  26. package/dist/cjs/chess.js.map +0 -1
  27. package/dist/cjs/compat.js +0 -89
  28. package/dist/cjs/compat.js.map +0 -1
  29. package/dist/cjs/debug.js +0 -103
  30. package/dist/cjs/debug.js.map +0 -1
  31. package/dist/cjs/fen.js +0 -325
  32. package/dist/cjs/fen.js.map +0 -1
  33. package/dist/cjs/index.js +0 -94
  34. package/dist/cjs/index.js.map +0 -1
  35. package/dist/cjs/pgn.js +0 -796
  36. package/dist/cjs/pgn.js.map +0 -1
  37. package/dist/cjs/san.js +0 -174
  38. package/dist/cjs/san.js.map +0 -1
  39. package/dist/cjs/setup.js +0 -167
  40. package/dist/cjs/setup.js.map +0 -1
  41. package/dist/cjs/squareSet.js +0 -206
  42. package/dist/cjs/squareSet.js.map +0 -1
  43. package/dist/cjs/transform.js +0 -57
  44. package/dist/cjs/transform.js.map +0 -1
  45. package/dist/cjs/types.js +0 -24
  46. package/dist/cjs/types.js.map +0 -1
  47. package/dist/cjs/util.js +0 -104
  48. package/dist/cjs/util.js.map +0 -1
  49. package/dist/cjs/variant.js +0 -833
  50. package/dist/cjs/variant.js.map +0 -1
  51. package/dist/esm/attacks.js.map +0 -1
  52. package/dist/esm/board.js.map +0 -1
  53. package/dist/esm/chess.js.map +0 -1
  54. package/dist/esm/compat.js.map +0 -1
  55. package/dist/esm/debug.js.map +0 -1
  56. package/dist/esm/fen.js.map +0 -1
  57. package/dist/esm/index.js.map +0 -1
  58. package/dist/esm/pgn.js.map +0 -1
  59. package/dist/esm/san.js.map +0 -1
  60. package/dist/esm/setup.js.map +0 -1
  61. package/dist/esm/squareSet.js.map +0 -1
  62. package/dist/esm/transform.js.map +0 -1
  63. package/dist/esm/types.js.map +0 -1
  64. package/dist/esm/util.js.map +0 -1
  65. package/dist/esm/variant.js.map +0 -1
  66. package/src/attacks.ts +0 -160
  67. package/src/board.ts +0 -168
  68. package/src/chess.ts +0 -687
  69. package/src/compat.ts +0 -120
  70. package/src/debug.ts +0 -100
  71. package/src/fen.ts +0 -328
  72. package/src/index.ts +0 -85
  73. package/src/pgn.ts +0 -876
  74. package/src/san.ts +0 -190
  75. package/src/setup.ts +0 -203
  76. package/src/squareSet.ts +0 -243
  77. package/src/transform.ts +0 -49
  78. package/src/types.ts +0 -93
  79. package/src/util.ts +0 -116
  80. package/src/variant.ts +0 -939
  81. /package/dist/{types/attacks.d.ts → attacks.d.ts} +0 -0
  82. /package/dist/{types/board.d.ts → board.d.ts} +0 -0
  83. /package/dist/{types/chess.d.ts → chess.d.ts} +0 -0
  84. /package/dist/{types/compat.d.ts → compat.d.ts} +0 -0
  85. /package/dist/{types/debug.d.ts → debug.d.ts} +0 -0
  86. /package/dist/{types/fen.d.ts → fen.d.ts} +0 -0
  87. /package/dist/{types/pgn.d.ts → pgn.d.ts} +0 -0
  88. /package/dist/{types/san.d.ts → san.d.ts} +0 -0
  89. /package/dist/{types/setup.d.ts → setup.d.ts} +0 -0
  90. /package/dist/{types/squareSet.d.ts → squareSet.d.ts} +0 -0
  91. /package/dist/{types/transform.d.ts → transform.d.ts} +0 -0
  92. /package/dist/{types/types.d.ts → types.d.ts} +0 -0
  93. /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]));