@connectorvol/chessops 0.15.1
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/LICENSE.txt +674 -0
- package/README.md +61 -0
- package/dist/cjs/attacks.js +152 -0
- package/dist/cjs/attacks.js.map +1 -0
- package/dist/cjs/board.js +143 -0
- package/dist/cjs/board.js.map +1 -0
- package/dist/cjs/chess.js +638 -0
- package/dist/cjs/chess.js.map +1 -0
- package/dist/cjs/compat.js +89 -0
- package/dist/cjs/compat.js.map +1 -0
- package/dist/cjs/debug.js +103 -0
- package/dist/cjs/debug.js.map +1 -0
- package/dist/cjs/fen.js +325 -0
- package/dist/cjs/fen.js.map +1 -0
- package/dist/cjs/index.js +94 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/pgn.js +796 -0
- package/dist/cjs/pgn.js.map +1 -0
- package/dist/cjs/san.js +174 -0
- package/dist/cjs/san.js.map +1 -0
- package/dist/cjs/setup.js +167 -0
- package/dist/cjs/setup.js.map +1 -0
- package/dist/cjs/squareSet.js +206 -0
- package/dist/cjs/squareSet.js.map +1 -0
- package/dist/cjs/transform.js +57 -0
- package/dist/cjs/transform.js.map +1 -0
- package/dist/cjs/types.js +24 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/util.js +104 -0
- package/dist/cjs/util.js.map +1 -0
- package/dist/cjs/variant.js +833 -0
- package/dist/cjs/variant.js.map +1 -0
- package/dist/esm/attacks.js +140 -0
- package/dist/esm/attacks.js.map +1 -0
- package/dist/esm/board.js +138 -0
- package/dist/esm/board.js.map +1 -0
- package/dist/esm/chess.js +624 -0
- package/dist/esm/chess.js.map +1 -0
- package/dist/esm/compat.js +81 -0
- package/dist/esm/compat.js.map +1 -0
- package/dist/esm/debug.js +94 -0
- package/dist/esm/debug.js.map +1 -0
- package/dist/esm/fen.js +308 -0
- package/dist/esm/fen.js.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/pgn.js +769 -0
- package/dist/esm/pgn.js.map +1 -0
- package/dist/esm/san.js +167 -0
- package/dist/esm/san.js.map +1 -0
- package/dist/esm/setup.js +157 -0
- package/dist/esm/setup.js.map +1 -0
- package/dist/esm/squareSet.js +202 -0
- package/dist/esm/squareSet.js.map +1 -0
- package/dist/esm/transform.js +48 -0
- package/dist/esm/transform.js.map +1 -0
- package/dist/esm/types.js +19 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/util.js +87 -0
- package/dist/esm/util.js.map +1 -0
- package/dist/esm/variant.js +812 -0
- package/dist/esm/variant.js.map +1 -0
- package/dist/types/attacks.d.ts +58 -0
- package/dist/types/board.d.ts +62 -0
- package/dist/types/chess.d.ts +82 -0
- package/dist/types/compat.d.ts +26 -0
- package/dist/types/debug.d.ts +10 -0
- package/dist/types/fen.d.ts +40 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/pgn.d.ts +203 -0
- package/dist/types/san.d.ts +6 -0
- package/dist/types/setup.d.ts +65 -0
- package/dist/types/squareSet.d.ts +50 -0
- package/dist/types/transform.d.ts +9 -0
- package/dist/types/types.d.ts +58 -0
- package/dist/types/util.d.ts +21 -0
- package/dist/types/variant.d.ts +92 -0
- package/package.json +86 -0
- package/src/attacks.ts +160 -0
- package/src/board.ts +168 -0
- package/src/chess.ts +687 -0
- package/src/compat.ts +120 -0
- package/src/debug.ts +100 -0
- package/src/fen.ts +328 -0
- package/src/index.ts +85 -0
- package/src/pgn.ts +876 -0
- package/src/san.ts +190 -0
- package/src/setup.ts +203 -0
- package/src/squareSet.ts +243 -0
- package/src/transform.ts +49 -0
- package/src/types.ts +93 -0
- package/src/util.ts +116 -0
- package/src/variant.ts +939 -0
|
@@ -0,0 +1,833 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isStandardMaterial = exports.setupPosition = exports.defaultPosition = exports.Horde = exports.RacingKings = exports.ThreeCheck = exports.KingOfTheHill = exports.Antichess = exports.Atomic = exports.Crazyhouse = exports.PositionError = exports.Position = exports.normalizeMove = exports.isImpossibleCheck = exports.IllegalSetup = exports.equalsIgnoreMoves = exports.Chess = exports.castlingSide = exports.Castles = void 0;
|
|
4
|
+
const result_1 = require("@badrap/result");
|
|
5
|
+
const attacks_js_1 = require("./attacks.js");
|
|
6
|
+
const board_js_1 = require("./board.js");
|
|
7
|
+
const chess_js_1 = require("./chess.js");
|
|
8
|
+
Object.defineProperty(exports, "Castles", { enumerable: true, get: function () { return chess_js_1.Castles; } });
|
|
9
|
+
Object.defineProperty(exports, "castlingSide", { enumerable: true, get: function () { return chess_js_1.castlingSide; } });
|
|
10
|
+
Object.defineProperty(exports, "Chess", { enumerable: true, get: function () { return chess_js_1.Chess; } });
|
|
11
|
+
Object.defineProperty(exports, "equalsIgnoreMoves", { enumerable: true, get: function () { return chess_js_1.equalsIgnoreMoves; } });
|
|
12
|
+
Object.defineProperty(exports, "IllegalSetup", { enumerable: true, get: function () { return chess_js_1.IllegalSetup; } });
|
|
13
|
+
Object.defineProperty(exports, "isImpossibleCheck", { enumerable: true, get: function () { return chess_js_1.isImpossibleCheck; } });
|
|
14
|
+
Object.defineProperty(exports, "normalizeMove", { enumerable: true, get: function () { return chess_js_1.normalizeMove; } });
|
|
15
|
+
Object.defineProperty(exports, "Position", { enumerable: true, get: function () { return chess_js_1.Position; } });
|
|
16
|
+
Object.defineProperty(exports, "PositionError", { enumerable: true, get: function () { return chess_js_1.PositionError; } });
|
|
17
|
+
const setup_js_1 = require("./setup.js");
|
|
18
|
+
const squareSet_js_1 = require("./squareSet.js");
|
|
19
|
+
const types_js_1 = require("./types.js");
|
|
20
|
+
const util_js_1 = require("./util.js");
|
|
21
|
+
class Crazyhouse extends chess_js_1.Position {
|
|
22
|
+
constructor() {
|
|
23
|
+
super("crazyhouse");
|
|
24
|
+
}
|
|
25
|
+
reset() {
|
|
26
|
+
super.reset();
|
|
27
|
+
this.pockets = setup_js_1.Material.empty();
|
|
28
|
+
}
|
|
29
|
+
setupUnchecked(setup) {
|
|
30
|
+
super.setupUnchecked(setup);
|
|
31
|
+
this.board.promoted = setup.board.promoted
|
|
32
|
+
.intersect(setup.board.occupied)
|
|
33
|
+
.diff(setup.board.king)
|
|
34
|
+
.diff(setup.board.pawn);
|
|
35
|
+
this.pockets = setup.pockets ? setup.pockets.clone() : setup_js_1.Material.empty();
|
|
36
|
+
}
|
|
37
|
+
static default() {
|
|
38
|
+
const pos = new this();
|
|
39
|
+
pos.reset();
|
|
40
|
+
return pos;
|
|
41
|
+
}
|
|
42
|
+
static fromSetup(setup) {
|
|
43
|
+
const pos = new this();
|
|
44
|
+
pos.setupUnchecked(setup);
|
|
45
|
+
return pos.validate().map((_) => pos);
|
|
46
|
+
}
|
|
47
|
+
clone() {
|
|
48
|
+
return super.clone();
|
|
49
|
+
}
|
|
50
|
+
validate() {
|
|
51
|
+
return super.validate().chain((_) => {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
if ((_a = this.pockets) === null || _a === void 0 ? void 0 : _a.count("king")) {
|
|
54
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Kings));
|
|
55
|
+
}
|
|
56
|
+
if ((((_b = this.pockets) === null || _b === void 0 ? void 0 : _b.size()) || 0) + this.board.occupied.size() > 64) {
|
|
57
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Variant));
|
|
58
|
+
}
|
|
59
|
+
return result_1.Result.ok(undefined);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
hasInsufficientMaterial(color) {
|
|
63
|
+
// No material can leave the game, but we can easily check this for
|
|
64
|
+
// custom positions.
|
|
65
|
+
if (!this.pockets)
|
|
66
|
+
return super.hasInsufficientMaterial(color);
|
|
67
|
+
return (this.board.occupied.size() + this.pockets.size() <= 3 &&
|
|
68
|
+
this.board.pawn.isEmpty() &&
|
|
69
|
+
this.board.promoted.isEmpty() &&
|
|
70
|
+
this.board.rooksAndQueens().isEmpty() &&
|
|
71
|
+
this.pockets.count("pawn") <= 0 &&
|
|
72
|
+
this.pockets.count("rook") <= 0 &&
|
|
73
|
+
this.pockets.count("queen") <= 0);
|
|
74
|
+
}
|
|
75
|
+
dropDests(ctx) {
|
|
76
|
+
var _a, _b;
|
|
77
|
+
const mask = this.board.occupied
|
|
78
|
+
.complement()
|
|
79
|
+
.intersect(((_a = this.pockets) === null || _a === void 0 ? void 0 : _a[this.turn].hasNonPawns())
|
|
80
|
+
? squareSet_js_1.SquareSet.full()
|
|
81
|
+
: ((_b = this.pockets) === null || _b === void 0 ? void 0 : _b[this.turn].hasPawns())
|
|
82
|
+
? squareSet_js_1.SquareSet.backranks().complement()
|
|
83
|
+
: squareSet_js_1.SquareSet.empty());
|
|
84
|
+
ctx = ctx || this.ctx();
|
|
85
|
+
if ((0, util_js_1.defined)(ctx.king) && ctx.checkers.nonEmpty()) {
|
|
86
|
+
const checker = ctx.checkers.singleSquare();
|
|
87
|
+
if (!(0, util_js_1.defined)(checker))
|
|
88
|
+
return squareSet_js_1.SquareSet.empty();
|
|
89
|
+
return mask.intersect((0, attacks_js_1.between)(checker, ctx.king));
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
return mask;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.Crazyhouse = Crazyhouse;
|
|
96
|
+
class Atomic extends chess_js_1.Position {
|
|
97
|
+
constructor() {
|
|
98
|
+
super("atomic");
|
|
99
|
+
}
|
|
100
|
+
static default() {
|
|
101
|
+
const pos = new this();
|
|
102
|
+
pos.reset();
|
|
103
|
+
return pos;
|
|
104
|
+
}
|
|
105
|
+
static fromSetup(setup) {
|
|
106
|
+
const pos = new this();
|
|
107
|
+
pos.setupUnchecked(setup);
|
|
108
|
+
return pos.validate().map((_) => pos);
|
|
109
|
+
}
|
|
110
|
+
clone() {
|
|
111
|
+
return super.clone();
|
|
112
|
+
}
|
|
113
|
+
validate() {
|
|
114
|
+
// Like chess, but allow our king to be missing.
|
|
115
|
+
if (this.board.occupied.isEmpty())
|
|
116
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Empty));
|
|
117
|
+
if (this.board.king.size() > 2)
|
|
118
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Kings));
|
|
119
|
+
const otherKing = this.board.kingOf((0, util_js_1.opposite)(this.turn));
|
|
120
|
+
if (!(0, util_js_1.defined)(otherKing))
|
|
121
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Kings));
|
|
122
|
+
if (this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) {
|
|
123
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.OppositeCheck));
|
|
124
|
+
}
|
|
125
|
+
if (squareSet_js_1.SquareSet.backranks().intersects(this.board.pawn)) {
|
|
126
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.PawnsOnBackrank));
|
|
127
|
+
}
|
|
128
|
+
return result_1.Result.ok(undefined);
|
|
129
|
+
}
|
|
130
|
+
kingAttackers(square, attacker, occupied) {
|
|
131
|
+
const attackerKings = this.board.pieces(attacker, "king");
|
|
132
|
+
if (attackerKings.isEmpty() || (0, attacks_js_1.kingAttacks)(square).intersects(attackerKings)) {
|
|
133
|
+
return squareSet_js_1.SquareSet.empty();
|
|
134
|
+
}
|
|
135
|
+
return super.kingAttackers(square, attacker, occupied);
|
|
136
|
+
}
|
|
137
|
+
playCaptureAt(square, captured) {
|
|
138
|
+
super.playCaptureAt(square, captured);
|
|
139
|
+
this.board.take(square);
|
|
140
|
+
for (const explode of (0, attacks_js_1.kingAttacks)(square)
|
|
141
|
+
.intersect(this.board.occupied)
|
|
142
|
+
.diff(this.board.pawn)) {
|
|
143
|
+
const piece = this.board.take(explode);
|
|
144
|
+
if ((piece === null || piece === void 0 ? void 0 : piece.role) === "rook")
|
|
145
|
+
this.castles.discardRook(explode);
|
|
146
|
+
if ((piece === null || piece === void 0 ? void 0 : piece.role) === "king")
|
|
147
|
+
this.castles.discardColor(piece.color);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
hasInsufficientMaterial(color) {
|
|
151
|
+
// Remaining material does not matter if the enemy king is already
|
|
152
|
+
// exploded.
|
|
153
|
+
if (this.board.pieces((0, util_js_1.opposite)(color), "king").isEmpty())
|
|
154
|
+
return false;
|
|
155
|
+
// Bare king cannot mate.
|
|
156
|
+
if (this.board[color].diff(this.board.king).isEmpty())
|
|
157
|
+
return true;
|
|
158
|
+
// As long as the enemy king is not alone, there is always a chance their
|
|
159
|
+
// own pieces explode next to it.
|
|
160
|
+
if (this.board[(0, util_js_1.opposite)(color)].diff(this.board.king).nonEmpty()) {
|
|
161
|
+
// Unless there are only bishops that cannot explode each other.
|
|
162
|
+
if (this.board.occupied.equals(this.board.bishop.union(this.board.king))) {
|
|
163
|
+
if (!this.board.bishop.intersect(this.board.white).intersects(squareSet_js_1.SquareSet.darkSquares())) {
|
|
164
|
+
return !this.board.bishop
|
|
165
|
+
.intersect(this.board.black)
|
|
166
|
+
.intersects(squareSet_js_1.SquareSet.lightSquares());
|
|
167
|
+
}
|
|
168
|
+
if (!this.board.bishop.intersect(this.board.white).intersects(squareSet_js_1.SquareSet.lightSquares())) {
|
|
169
|
+
return !this.board.bishop.intersect(this.board.black).intersects(squareSet_js_1.SquareSet.darkSquares());
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
// Queen or pawn (future queen) can give mate against bare king.
|
|
175
|
+
if (this.board.queen.nonEmpty() || this.board.pawn.nonEmpty())
|
|
176
|
+
return false;
|
|
177
|
+
// Single knight, bishop or rook cannot mate against bare king.
|
|
178
|
+
if (this.board.knight.union(this.board.bishop).union(this.board.rook).size() === 1)
|
|
179
|
+
return true;
|
|
180
|
+
// If only knights, more than two are required to mate bare king.
|
|
181
|
+
if (this.board.occupied.equals(this.board.knight.union(this.board.king))) {
|
|
182
|
+
return this.board.knight.size() <= 2;
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
dests(square, ctx) {
|
|
187
|
+
ctx = ctx || this.ctx();
|
|
188
|
+
let dests = squareSet_js_1.SquareSet.empty();
|
|
189
|
+
for (const to of (0, chess_js_1.pseudoDests)(this, square, ctx)) {
|
|
190
|
+
const after = this.clone();
|
|
191
|
+
after.play({ from: square, to });
|
|
192
|
+
const ourKing = after.board.kingOf(this.turn);
|
|
193
|
+
if ((0, util_js_1.defined)(ourKing) &&
|
|
194
|
+
(!(0, util_js_1.defined)(after.board.kingOf(after.turn)) ||
|
|
195
|
+
after.kingAttackers(ourKing, after.turn, after.board.occupied).isEmpty())) {
|
|
196
|
+
dests = dests.with(to);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return dests;
|
|
200
|
+
}
|
|
201
|
+
isVariantEnd() {
|
|
202
|
+
return !!this.variantOutcome();
|
|
203
|
+
}
|
|
204
|
+
variantOutcome(_ctx) {
|
|
205
|
+
for (const color of types_js_1.COLORS) {
|
|
206
|
+
if (this.board.pieces(color, "king").isEmpty())
|
|
207
|
+
return { winner: (0, util_js_1.opposite)(color) };
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.Atomic = Atomic;
|
|
213
|
+
class Antichess extends chess_js_1.Position {
|
|
214
|
+
constructor() {
|
|
215
|
+
super("antichess");
|
|
216
|
+
}
|
|
217
|
+
reset() {
|
|
218
|
+
super.reset();
|
|
219
|
+
this.castles = chess_js_1.Castles.empty();
|
|
220
|
+
}
|
|
221
|
+
setupUnchecked(setup) {
|
|
222
|
+
super.setupUnchecked(setup);
|
|
223
|
+
this.castles = chess_js_1.Castles.empty();
|
|
224
|
+
}
|
|
225
|
+
static default() {
|
|
226
|
+
const pos = new this();
|
|
227
|
+
pos.reset();
|
|
228
|
+
return pos;
|
|
229
|
+
}
|
|
230
|
+
static fromSetup(setup) {
|
|
231
|
+
const pos = new this();
|
|
232
|
+
pos.setupUnchecked(setup);
|
|
233
|
+
return pos.validate().map((_) => pos);
|
|
234
|
+
}
|
|
235
|
+
clone() {
|
|
236
|
+
return super.clone();
|
|
237
|
+
}
|
|
238
|
+
validate() {
|
|
239
|
+
if (this.board.occupied.isEmpty())
|
|
240
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Empty));
|
|
241
|
+
if (squareSet_js_1.SquareSet.backranks().intersects(this.board.pawn)) {
|
|
242
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.PawnsOnBackrank));
|
|
243
|
+
}
|
|
244
|
+
return result_1.Result.ok(undefined);
|
|
245
|
+
}
|
|
246
|
+
kingAttackers(_square, _attacker, _occupied) {
|
|
247
|
+
return squareSet_js_1.SquareSet.empty();
|
|
248
|
+
}
|
|
249
|
+
ctx() {
|
|
250
|
+
const ctx = super.ctx();
|
|
251
|
+
if ((0, util_js_1.defined)(this.epSquare) &&
|
|
252
|
+
(0, attacks_js_1.pawnAttacks)((0, util_js_1.opposite)(this.turn), this.epSquare).intersects(this.board.pieces(this.turn, "pawn"))) {
|
|
253
|
+
ctx.mustCapture = true;
|
|
254
|
+
return ctx;
|
|
255
|
+
}
|
|
256
|
+
const enemy = this.board[(0, util_js_1.opposite)(this.turn)];
|
|
257
|
+
for (const from of this.board[this.turn]) {
|
|
258
|
+
if ((0, chess_js_1.pseudoDests)(this, from, ctx).intersects(enemy)) {
|
|
259
|
+
ctx.mustCapture = true;
|
|
260
|
+
return ctx;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return ctx;
|
|
264
|
+
}
|
|
265
|
+
dests(square, ctx) {
|
|
266
|
+
ctx = ctx || this.ctx();
|
|
267
|
+
const dests = (0, chess_js_1.pseudoDests)(this, square, ctx);
|
|
268
|
+
const enemy = this.board[(0, util_js_1.opposite)(this.turn)];
|
|
269
|
+
return dests.intersect(ctx.mustCapture
|
|
270
|
+
? (0, util_js_1.defined)(this.epSquare) && this.board.getRole(square) === "pawn"
|
|
271
|
+
? enemy.with(this.epSquare)
|
|
272
|
+
: enemy
|
|
273
|
+
: squareSet_js_1.SquareSet.full());
|
|
274
|
+
}
|
|
275
|
+
hasInsufficientMaterial(color) {
|
|
276
|
+
if (this.board[color].isEmpty())
|
|
277
|
+
return false;
|
|
278
|
+
if (this.board[(0, util_js_1.opposite)(color)].isEmpty())
|
|
279
|
+
return true;
|
|
280
|
+
if (this.board.occupied.equals(this.board.bishop)) {
|
|
281
|
+
const weSomeOnLight = this.board[color].intersects(squareSet_js_1.SquareSet.lightSquares());
|
|
282
|
+
const weSomeOnDark = this.board[color].intersects(squareSet_js_1.SquareSet.darkSquares());
|
|
283
|
+
const theyAllOnDark = this.board[(0, util_js_1.opposite)(color)].isDisjoint(squareSet_js_1.SquareSet.lightSquares());
|
|
284
|
+
const theyAllOnLight = this.board[(0, util_js_1.opposite)(color)].isDisjoint(squareSet_js_1.SquareSet.darkSquares());
|
|
285
|
+
return (weSomeOnLight && theyAllOnDark) || (weSomeOnDark && theyAllOnLight);
|
|
286
|
+
}
|
|
287
|
+
if (this.board.occupied.equals(this.board.knight) && this.board.occupied.size() === 2) {
|
|
288
|
+
return ((this.board.white.intersects(squareSet_js_1.SquareSet.lightSquares()) !==
|
|
289
|
+
this.board.black.intersects(squareSet_js_1.SquareSet.darkSquares())) !==
|
|
290
|
+
(this.turn === color));
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
isVariantEnd() {
|
|
295
|
+
return this.board[this.turn].isEmpty();
|
|
296
|
+
}
|
|
297
|
+
variantOutcome(ctx) {
|
|
298
|
+
ctx = ctx || this.ctx();
|
|
299
|
+
if (ctx.variantEnd || this.isStalemate(ctx)) {
|
|
300
|
+
return { winner: this.turn };
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
exports.Antichess = Antichess;
|
|
306
|
+
class KingOfTheHill extends chess_js_1.Position {
|
|
307
|
+
constructor() {
|
|
308
|
+
super("kingofthehill");
|
|
309
|
+
}
|
|
310
|
+
static default() {
|
|
311
|
+
const pos = new this();
|
|
312
|
+
pos.reset();
|
|
313
|
+
return pos;
|
|
314
|
+
}
|
|
315
|
+
static fromSetup(setup) {
|
|
316
|
+
const pos = new this();
|
|
317
|
+
pos.setupUnchecked(setup);
|
|
318
|
+
return pos.validate().map((_) => pos);
|
|
319
|
+
}
|
|
320
|
+
clone() {
|
|
321
|
+
return super.clone();
|
|
322
|
+
}
|
|
323
|
+
hasInsufficientMaterial(_color) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
isVariantEnd() {
|
|
327
|
+
return this.board.king.intersects(squareSet_js_1.SquareSet.center());
|
|
328
|
+
}
|
|
329
|
+
variantOutcome(_ctx) {
|
|
330
|
+
for (const color of types_js_1.COLORS) {
|
|
331
|
+
if (this.board.pieces(color, "king").intersects(squareSet_js_1.SquareSet.center()))
|
|
332
|
+
return { winner: color };
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
exports.KingOfTheHill = KingOfTheHill;
|
|
338
|
+
class ThreeCheck extends chess_js_1.Position {
|
|
339
|
+
constructor() {
|
|
340
|
+
super("3check");
|
|
341
|
+
}
|
|
342
|
+
reset() {
|
|
343
|
+
super.reset();
|
|
344
|
+
this.remainingChecks = setup_js_1.RemainingChecks.default();
|
|
345
|
+
}
|
|
346
|
+
setupUnchecked(setup) {
|
|
347
|
+
var _a;
|
|
348
|
+
super.setupUnchecked(setup);
|
|
349
|
+
this.remainingChecks = ((_a = setup.remainingChecks) === null || _a === void 0 ? void 0 : _a.clone()) || setup_js_1.RemainingChecks.default();
|
|
350
|
+
}
|
|
351
|
+
static default() {
|
|
352
|
+
const pos = new this();
|
|
353
|
+
pos.reset();
|
|
354
|
+
return pos;
|
|
355
|
+
}
|
|
356
|
+
static fromSetup(setup) {
|
|
357
|
+
const pos = new this();
|
|
358
|
+
pos.setupUnchecked(setup);
|
|
359
|
+
return pos.validate().map((_) => pos);
|
|
360
|
+
}
|
|
361
|
+
clone() {
|
|
362
|
+
return super.clone();
|
|
363
|
+
}
|
|
364
|
+
hasInsufficientMaterial(color) {
|
|
365
|
+
return this.board.pieces(color, "king").equals(this.board[color]);
|
|
366
|
+
}
|
|
367
|
+
isVariantEnd() {
|
|
368
|
+
return (!!this.remainingChecks && (this.remainingChecks.white <= 0 || this.remainingChecks.black <= 0));
|
|
369
|
+
}
|
|
370
|
+
variantOutcome(_ctx) {
|
|
371
|
+
if (this.remainingChecks) {
|
|
372
|
+
for (const color of types_js_1.COLORS) {
|
|
373
|
+
if (this.remainingChecks[color] <= 0)
|
|
374
|
+
return { winner: color };
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
exports.ThreeCheck = ThreeCheck;
|
|
381
|
+
const racingKingsBoard = () => {
|
|
382
|
+
const board = board_js_1.Board.empty();
|
|
383
|
+
board.occupied = new squareSet_js_1.SquareSet(0xffff, 0);
|
|
384
|
+
board.promoted = squareSet_js_1.SquareSet.empty();
|
|
385
|
+
board.white = new squareSet_js_1.SquareSet(0xf0f0, 0);
|
|
386
|
+
board.black = new squareSet_js_1.SquareSet(0x0f0f, 0);
|
|
387
|
+
board.pawn = squareSet_js_1.SquareSet.empty();
|
|
388
|
+
board.knight = new squareSet_js_1.SquareSet(0x1818, 0);
|
|
389
|
+
board.bishop = new squareSet_js_1.SquareSet(0x2424, 0);
|
|
390
|
+
board.rook = new squareSet_js_1.SquareSet(0x4242, 0);
|
|
391
|
+
board.queen = new squareSet_js_1.SquareSet(0x0081, 0);
|
|
392
|
+
board.king = new squareSet_js_1.SquareSet(0x8100, 0);
|
|
393
|
+
return board;
|
|
394
|
+
};
|
|
395
|
+
class RacingKings extends chess_js_1.Position {
|
|
396
|
+
constructor() {
|
|
397
|
+
super("racingkings");
|
|
398
|
+
}
|
|
399
|
+
reset() {
|
|
400
|
+
this.board = racingKingsBoard();
|
|
401
|
+
this.pockets = undefined;
|
|
402
|
+
this.turn = "white";
|
|
403
|
+
this.castles = chess_js_1.Castles.empty();
|
|
404
|
+
this.epSquare = undefined;
|
|
405
|
+
this.remainingChecks = undefined;
|
|
406
|
+
this.halfmoves = 0;
|
|
407
|
+
this.fullmoves = 1;
|
|
408
|
+
}
|
|
409
|
+
setupUnchecked(setup) {
|
|
410
|
+
super.setupUnchecked(setup);
|
|
411
|
+
this.castles = chess_js_1.Castles.empty();
|
|
412
|
+
}
|
|
413
|
+
static default() {
|
|
414
|
+
const pos = new this();
|
|
415
|
+
pos.reset();
|
|
416
|
+
return pos;
|
|
417
|
+
}
|
|
418
|
+
static fromSetup(setup) {
|
|
419
|
+
const pos = new this();
|
|
420
|
+
pos.setupUnchecked(setup);
|
|
421
|
+
return pos.validate().map((_) => pos);
|
|
422
|
+
}
|
|
423
|
+
clone() {
|
|
424
|
+
return super.clone();
|
|
425
|
+
}
|
|
426
|
+
validate() {
|
|
427
|
+
if (this.isCheck() || this.board.pawn.nonEmpty())
|
|
428
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Variant));
|
|
429
|
+
return super.validate();
|
|
430
|
+
}
|
|
431
|
+
dests(square, ctx) {
|
|
432
|
+
ctx = ctx || this.ctx();
|
|
433
|
+
// Kings cannot give check.
|
|
434
|
+
if (square === ctx.king)
|
|
435
|
+
return super.dests(square, ctx);
|
|
436
|
+
// Do not allow giving check.
|
|
437
|
+
let dests = squareSet_js_1.SquareSet.empty();
|
|
438
|
+
for (const to of super.dests(square, ctx)) {
|
|
439
|
+
// Valid, because there are no promotions (or even pawns).
|
|
440
|
+
const move = { from: square, to };
|
|
441
|
+
const after = this.clone();
|
|
442
|
+
after.play(move);
|
|
443
|
+
if (!after.isCheck())
|
|
444
|
+
dests = dests.with(to);
|
|
445
|
+
}
|
|
446
|
+
return dests;
|
|
447
|
+
}
|
|
448
|
+
hasInsufficientMaterial(_color) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
isVariantEnd() {
|
|
452
|
+
const goal = squareSet_js_1.SquareSet.fromRank(7);
|
|
453
|
+
const inGoal = this.board.king.intersect(goal);
|
|
454
|
+
if (inGoal.isEmpty())
|
|
455
|
+
return false;
|
|
456
|
+
if (this.turn === "white" || inGoal.intersects(this.board.black))
|
|
457
|
+
return true;
|
|
458
|
+
// White has reached the backrank. Check if black can catch up.
|
|
459
|
+
const blackKing = this.board.kingOf("black");
|
|
460
|
+
if ((0, util_js_1.defined)(blackKing)) {
|
|
461
|
+
const occ = this.board.occupied.without(blackKing);
|
|
462
|
+
for (const target of (0, attacks_js_1.kingAttacks)(blackKing).intersect(goal).diff(this.board.black)) {
|
|
463
|
+
if (this.kingAttackers(target, "white", occ).isEmpty())
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
variantOutcome(ctx) {
|
|
470
|
+
if (ctx ? !ctx.variantEnd : !this.isVariantEnd())
|
|
471
|
+
return;
|
|
472
|
+
const goal = squareSet_js_1.SquareSet.fromRank(7);
|
|
473
|
+
const blackInGoal = this.board.pieces("black", "king").intersects(goal);
|
|
474
|
+
const whiteInGoal = this.board.pieces("white", "king").intersects(goal);
|
|
475
|
+
if (blackInGoal && !whiteInGoal)
|
|
476
|
+
return { winner: "black" };
|
|
477
|
+
if (whiteInGoal && !blackInGoal)
|
|
478
|
+
return { winner: "white" };
|
|
479
|
+
return { winner: undefined };
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
exports.RacingKings = RacingKings;
|
|
483
|
+
const hordeBoard = () => {
|
|
484
|
+
const board = board_js_1.Board.empty();
|
|
485
|
+
board.occupied = new squareSet_js_1.SquareSet(4294967295, 4294901862);
|
|
486
|
+
board.promoted = squareSet_js_1.SquareSet.empty();
|
|
487
|
+
board.white = new squareSet_js_1.SquareSet(4294967295, 102);
|
|
488
|
+
board.black = new squareSet_js_1.SquareSet(0, 4294901760);
|
|
489
|
+
board.pawn = new squareSet_js_1.SquareSet(4294967295, 16711782);
|
|
490
|
+
board.knight = new squareSet_js_1.SquareSet(0, 1107296256);
|
|
491
|
+
board.bishop = new squareSet_js_1.SquareSet(0, 603979776);
|
|
492
|
+
board.rook = new squareSet_js_1.SquareSet(0, 2164260864);
|
|
493
|
+
board.queen = new squareSet_js_1.SquareSet(0, 134217728);
|
|
494
|
+
board.king = new squareSet_js_1.SquareSet(0, 268435456);
|
|
495
|
+
return board;
|
|
496
|
+
};
|
|
497
|
+
class Horde extends chess_js_1.Position {
|
|
498
|
+
constructor() {
|
|
499
|
+
super("horde");
|
|
500
|
+
}
|
|
501
|
+
reset() {
|
|
502
|
+
this.board = hordeBoard();
|
|
503
|
+
this.pockets = undefined;
|
|
504
|
+
this.turn = "white";
|
|
505
|
+
this.castles = chess_js_1.Castles.default();
|
|
506
|
+
this.castles.discardColor("white");
|
|
507
|
+
this.epSquare = undefined;
|
|
508
|
+
this.remainingChecks = undefined;
|
|
509
|
+
this.halfmoves = 0;
|
|
510
|
+
this.fullmoves = 1;
|
|
511
|
+
}
|
|
512
|
+
static default() {
|
|
513
|
+
const pos = new this();
|
|
514
|
+
pos.reset();
|
|
515
|
+
return pos;
|
|
516
|
+
}
|
|
517
|
+
static fromSetup(setup) {
|
|
518
|
+
const pos = new this();
|
|
519
|
+
pos.setupUnchecked(setup);
|
|
520
|
+
return pos.validate().map((_) => pos);
|
|
521
|
+
}
|
|
522
|
+
clone() {
|
|
523
|
+
return super.clone();
|
|
524
|
+
}
|
|
525
|
+
validate() {
|
|
526
|
+
if (this.board.occupied.isEmpty())
|
|
527
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Empty));
|
|
528
|
+
if (this.board.king.size() !== 1)
|
|
529
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.Kings));
|
|
530
|
+
const otherKing = this.board.kingOf((0, util_js_1.opposite)(this.turn));
|
|
531
|
+
if ((0, util_js_1.defined)(otherKing) &&
|
|
532
|
+
this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) {
|
|
533
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.OppositeCheck));
|
|
534
|
+
}
|
|
535
|
+
for (const color of types_js_1.COLORS) {
|
|
536
|
+
const backranks = this.board.pieces(color, "king").isEmpty()
|
|
537
|
+
? squareSet_js_1.SquareSet.backrank((0, util_js_1.opposite)(color))
|
|
538
|
+
: squareSet_js_1.SquareSet.backranks();
|
|
539
|
+
if (this.board.pieces(color, "pawn").intersects(backranks)) {
|
|
540
|
+
return result_1.Result.err(new chess_js_1.PositionError(chess_js_1.IllegalSetup.PawnsOnBackrank));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return result_1.Result.ok(undefined);
|
|
544
|
+
}
|
|
545
|
+
hasInsufficientMaterial(color) {
|
|
546
|
+
// The side with the king can always win by capturing the horde.
|
|
547
|
+
if (this.board.pieces(color, "king").nonEmpty())
|
|
548
|
+
return false;
|
|
549
|
+
const oppositeSquareColor = (squareColor) => squareColor === "light" ? "dark" : "light";
|
|
550
|
+
const coloredSquares = (squareColor) => squareColor === "light" ? squareSet_js_1.SquareSet.lightSquares() : squareSet_js_1.SquareSet.darkSquares();
|
|
551
|
+
const hasBishopPair = (side) => {
|
|
552
|
+
const bishops = this.board.pieces(side, "bishop");
|
|
553
|
+
return (bishops.intersects(squareSet_js_1.SquareSet.darkSquares()) && bishops.intersects(squareSet_js_1.SquareSet.lightSquares()));
|
|
554
|
+
};
|
|
555
|
+
// By this point: color is the horde.
|
|
556
|
+
// Based on
|
|
557
|
+
// https://github.com/stevepapazis/horde-insufficient-material-tests.
|
|
558
|
+
const horde = setup_js_1.MaterialSide.fromBoard(this.board, color);
|
|
559
|
+
const hordeBishops = (squareColor) => coloredSquares(squareColor).intersect(this.board.pieces(color, "bishop")).size();
|
|
560
|
+
const hordeBishopColor = hordeBishops("light") >= 1 ? "light" : "dark";
|
|
561
|
+
const hordeNum = horde.pawn +
|
|
562
|
+
horde.knight +
|
|
563
|
+
horde.rook +
|
|
564
|
+
horde.queen +
|
|
565
|
+
Math.min(hordeBishops("dark"), 2) +
|
|
566
|
+
Math.min(hordeBishops("light"), 2);
|
|
567
|
+
const pieces = setup_js_1.MaterialSide.fromBoard(this.board, (0, util_js_1.opposite)(color));
|
|
568
|
+
const piecesBishops = (squareColor) => coloredSquares(squareColor)
|
|
569
|
+
.intersect(this.board.pieces((0, util_js_1.opposite)(color), "bishop"))
|
|
570
|
+
.size();
|
|
571
|
+
const piecesNum = pieces.size();
|
|
572
|
+
const piecesOfRoleNot = (piece) => piecesNum - piece;
|
|
573
|
+
if (hordeNum === 0)
|
|
574
|
+
return true;
|
|
575
|
+
if (hordeNum >= 4) {
|
|
576
|
+
// Four or more pieces can always deliver mate.
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
if ((horde.pawn >= 1 || horde.queen >= 1) && hordeNum >= 2) {
|
|
580
|
+
// Pawns/queens are never insufficient material when paired with any other
|
|
581
|
+
// piece (a pawn promotes to a queen and delivers mate).
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
if (horde.rook >= 1 && hordeNum >= 2) {
|
|
585
|
+
// A rook is insufficient material only when it is paired with a bishop
|
|
586
|
+
// against a lone king. The horde can mate in any other case.
|
|
587
|
+
// A rook on A1 and a bishop on C3 mate a king on B1 when there is a
|
|
588
|
+
// friendly pawn/opposite-color-bishop/rook/queen on C2.
|
|
589
|
+
// A rook on B8 and a bishop C3 mate a king on A1 when there is a friendly
|
|
590
|
+
// knight on A2.
|
|
591
|
+
if (!(hordeNum === 2 &&
|
|
592
|
+
horde.rook === 1 &&
|
|
593
|
+
horde.bishop === 1 &&
|
|
594
|
+
piecesOfRoleNot(piecesBishops(hordeBishopColor)) === 1)) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (hordeNum === 1) {
|
|
599
|
+
if (piecesNum === 1) {
|
|
600
|
+
// A lone piece cannot mate a lone king.
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
else if (horde.queen === 1) {
|
|
604
|
+
// The horde has a lone queen.
|
|
605
|
+
// A lone queen mates a king on A1 bounded by:
|
|
606
|
+
// -- a pawn/rook on A2
|
|
607
|
+
// -- two same color bishops on A2, B1
|
|
608
|
+
// We ignore every other mating case, since it can be reduced to
|
|
609
|
+
// the two previous cases (e.g. a black pawn on A2 and a black
|
|
610
|
+
// bishop on B1).
|
|
611
|
+
return !(pieces.pawn >= 1 ||
|
|
612
|
+
pieces.rook >= 1 ||
|
|
613
|
+
piecesBishops("light") >= 2 ||
|
|
614
|
+
piecesBishops("dark") >= 2);
|
|
615
|
+
}
|
|
616
|
+
else if (horde.pawn === 1) {
|
|
617
|
+
// Promote the pawn to a queen or a knight and check whether white
|
|
618
|
+
// can mate.
|
|
619
|
+
const pawnSquare = this.board.pieces(color, "pawn").last();
|
|
620
|
+
const promoteToQueen = this.clone();
|
|
621
|
+
promoteToQueen.board.set(pawnSquare, { color, role: "queen" });
|
|
622
|
+
const promoteToKnight = this.clone();
|
|
623
|
+
promoteToKnight.board.set(pawnSquare, { color, role: "knight" });
|
|
624
|
+
return (promoteToQueen.hasInsufficientMaterial(color) &&
|
|
625
|
+
promoteToKnight.hasInsufficientMaterial(color));
|
|
626
|
+
}
|
|
627
|
+
else if (horde.rook === 1) {
|
|
628
|
+
// A lone rook mates a king on A8 bounded by a pawn/rook on A7 and a
|
|
629
|
+
// pawn/knight on B7. We ignore every other case, since it can be
|
|
630
|
+
// reduced to the two previous cases.
|
|
631
|
+
// (e.g. three pawns on A7, B7, C7)
|
|
632
|
+
return !(pieces.pawn >= 2 ||
|
|
633
|
+
(pieces.rook >= 1 && pieces.pawn >= 1) ||
|
|
634
|
+
(pieces.rook >= 1 && pieces.knight >= 1) ||
|
|
635
|
+
(pieces.pawn >= 1 && pieces.knight >= 1));
|
|
636
|
+
}
|
|
637
|
+
else if (horde.bishop === 1) {
|
|
638
|
+
// The horde has a lone bishop.
|
|
639
|
+
return !(
|
|
640
|
+
// The king can be mated on A1 if there is a pawn/opposite-color-bishop
|
|
641
|
+
// on A2 and an opposite-color-bishop on B1.
|
|
642
|
+
// If black has two or more pawns, white gets the benefit of the doubt;
|
|
643
|
+
// there is an outside chance that white promotes its pawns to
|
|
644
|
+
// opposite-color-bishops and selfmates theirself.
|
|
645
|
+
// Every other case that the king is mated by the bishop requires that
|
|
646
|
+
// black has two pawns or two opposite-color-bishop or a pawn and an
|
|
647
|
+
// opposite-color-bishop.
|
|
648
|
+
// For example a king on A3 can be mated if there is
|
|
649
|
+
// a pawn/opposite-color-bishop on A4, a pawn/opposite-color-bishop on
|
|
650
|
+
// B3, a pawn/bishop/rook/queen on A2 and any other piece on B2.
|
|
651
|
+
(piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 2 ||
|
|
652
|
+
(piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 1 && pieces.pawn >= 1) ||
|
|
653
|
+
pieces.pawn >= 2));
|
|
654
|
+
}
|
|
655
|
+
else if (horde.knight === 1) {
|
|
656
|
+
// The horde has a lone knight.
|
|
657
|
+
return !(
|
|
658
|
+
// The king on A1 can be smother mated by a knight on C2 if there is
|
|
659
|
+
// a pawn/knight/bishop on B2, a knight/rook on B1 and any other piece
|
|
660
|
+
// on A2.
|
|
661
|
+
// Moreover, when black has four or more pieces and two of them are
|
|
662
|
+
// pawns, black can promote their pawns and selfmate theirself.
|
|
663
|
+
(piecesNum >= 4 &&
|
|
664
|
+
(pieces.knight >= 2 ||
|
|
665
|
+
pieces.pawn >= 2 ||
|
|
666
|
+
(pieces.rook >= 1 && pieces.knight >= 1) ||
|
|
667
|
+
(pieces.rook >= 1 && pieces.bishop >= 1) ||
|
|
668
|
+
(pieces.knight >= 1 && pieces.bishop >= 1) ||
|
|
669
|
+
(pieces.rook >= 1 && pieces.pawn >= 1) ||
|
|
670
|
+
(pieces.knight >= 1 && pieces.pawn >= 1) ||
|
|
671
|
+
(pieces.bishop >= 1 && pieces.pawn >= 1) ||
|
|
672
|
+
(hasBishopPair((0, util_js_1.opposite)(color)) && pieces.pawn >= 1)) &&
|
|
673
|
+
(piecesBishops("dark") < 2 || piecesOfRoleNot(piecesBishops("dark")) >= 3) &&
|
|
674
|
+
(piecesBishops("light") < 2 || piecesOfRoleNot(piecesBishops("light")) >= 3)));
|
|
675
|
+
}
|
|
676
|
+
// By this point, we only need to deal with white's minor pieces.
|
|
677
|
+
}
|
|
678
|
+
else if (hordeNum === 2) {
|
|
679
|
+
if (piecesNum === 1) {
|
|
680
|
+
// Two minor pieces cannot mate a lone king.
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
else if (horde.knight === 2) {
|
|
684
|
+
// A king on A1 is mated by two knights, if it is obstructed by a
|
|
685
|
+
// pawn/bishop/knight on B2. On the other hand, if black only has
|
|
686
|
+
// major pieces it is a draw.
|
|
687
|
+
return pieces.pawn + pieces.bishop + pieces.knight < 1;
|
|
688
|
+
}
|
|
689
|
+
else if (hasBishopPair(color)) {
|
|
690
|
+
return !(
|
|
691
|
+
// A king on A1 obstructed by a pawn/bishop on A2 is mated
|
|
692
|
+
// by the bishop pair.
|
|
693
|
+
(pieces.pawn >= 1 ||
|
|
694
|
+
pieces.bishop >= 1 ||
|
|
695
|
+
// A pawn/bishop/knight on B4, a pawn/bishop/rook/queen on
|
|
696
|
+
// A4 and the king on A3 enable Boden's mate by the bishop
|
|
697
|
+
// pair. In every other case white cannot win.
|
|
698
|
+
(pieces.knight >= 1 && pieces.rook + pieces.queen >= 1)));
|
|
699
|
+
}
|
|
700
|
+
else if (horde.bishop >= 1 && horde.knight >= 1) {
|
|
701
|
+
// The horde has a bishop and a knight.
|
|
702
|
+
return !(
|
|
703
|
+
// A king on A1 obstructed by a pawn/opposite-color-bishop on
|
|
704
|
+
// A2 is mated by a knight on D2 and a bishop on C3.
|
|
705
|
+
(pieces.pawn >= 1 ||
|
|
706
|
+
piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 1 ||
|
|
707
|
+
// A king on A1 bounded by two friendly pieces on A2 and B1 is
|
|
708
|
+
// mated when the knight moves from D4 to C2 so that both the
|
|
709
|
+
// knight and the bishop deliver check.
|
|
710
|
+
piecesOfRoleNot(piecesBishops(hordeBishopColor)) >= 3));
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
// The horde has two or more bishops on the same color.
|
|
714
|
+
// White can only win if black has enough material to obstruct
|
|
715
|
+
// the squares of the opposite color around the king.
|
|
716
|
+
return !(
|
|
717
|
+
// A king on A1 obstructed by a pawn/opposite-bishop/knight
|
|
718
|
+
// on A2 and a opposite-bishop/knight on B1 is mated by two
|
|
719
|
+
// bishops on B2 and C3. This position is theoretically
|
|
720
|
+
// achievable even when black has two pawns or when they
|
|
721
|
+
// have a pawn and an opposite color bishop.
|
|
722
|
+
((pieces.pawn >= 1 && piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 1) ||
|
|
723
|
+
(pieces.pawn >= 1 && pieces.knight >= 1) ||
|
|
724
|
+
(piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 1 && pieces.knight >= 1) ||
|
|
725
|
+
piecesBishops(oppositeSquareColor(hordeBishopColor)) >= 2 ||
|
|
726
|
+
pieces.knight >= 2 ||
|
|
727
|
+
pieces.pawn >= 2)
|
|
728
|
+
// In every other case, white can only draw.
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
else if (hordeNum === 3) {
|
|
733
|
+
// A king in the corner is mated by two knights and a bishop or three
|
|
734
|
+
// knights or the bishop pair and a knight/bishop.
|
|
735
|
+
if ((horde.knight === 2 && horde.bishop === 1) ||
|
|
736
|
+
horde.knight === 3 ||
|
|
737
|
+
hasBishopPair(color)) {
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
// White has two same color bishops and a knight.
|
|
742
|
+
// A king on A1 is mated by a bishop on B2, a bishop on C1 and a
|
|
743
|
+
// knight on C3, as long as there is another black piece to waste
|
|
744
|
+
// a tempo.
|
|
745
|
+
return piecesNum === 1;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
750
|
+
isVariantEnd() {
|
|
751
|
+
return this.board.white.isEmpty() || this.board.black.isEmpty();
|
|
752
|
+
}
|
|
753
|
+
variantOutcome(_ctx) {
|
|
754
|
+
if (this.board.white.isEmpty())
|
|
755
|
+
return { winner: "black" };
|
|
756
|
+
if (this.board.black.isEmpty())
|
|
757
|
+
return { winner: "white" };
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
exports.Horde = Horde;
|
|
762
|
+
const defaultPosition = (rules) => {
|
|
763
|
+
switch (rules) {
|
|
764
|
+
case "chess":
|
|
765
|
+
return chess_js_1.Chess.default();
|
|
766
|
+
case "antichess":
|
|
767
|
+
return Antichess.default();
|
|
768
|
+
case "atomic":
|
|
769
|
+
return Atomic.default();
|
|
770
|
+
case "horde":
|
|
771
|
+
return Horde.default();
|
|
772
|
+
case "racingkings":
|
|
773
|
+
return RacingKings.default();
|
|
774
|
+
case "kingofthehill":
|
|
775
|
+
return KingOfTheHill.default();
|
|
776
|
+
case "3check":
|
|
777
|
+
return ThreeCheck.default();
|
|
778
|
+
case "crazyhouse":
|
|
779
|
+
return Crazyhouse.default();
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
exports.defaultPosition = defaultPosition;
|
|
783
|
+
const setupPosition = (rules, setup) => {
|
|
784
|
+
switch (rules) {
|
|
785
|
+
case "chess":
|
|
786
|
+
return chess_js_1.Chess.fromSetup(setup);
|
|
787
|
+
case "antichess":
|
|
788
|
+
return Antichess.fromSetup(setup);
|
|
789
|
+
case "atomic":
|
|
790
|
+
return Atomic.fromSetup(setup);
|
|
791
|
+
case "horde":
|
|
792
|
+
return Horde.fromSetup(setup);
|
|
793
|
+
case "racingkings":
|
|
794
|
+
return RacingKings.fromSetup(setup);
|
|
795
|
+
case "kingofthehill":
|
|
796
|
+
return KingOfTheHill.fromSetup(setup);
|
|
797
|
+
case "3check":
|
|
798
|
+
return ThreeCheck.fromSetup(setup);
|
|
799
|
+
case "crazyhouse":
|
|
800
|
+
return Crazyhouse.fromSetup(setup);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
exports.setupPosition = setupPosition;
|
|
804
|
+
const isStandardMaterial = (pos) => {
|
|
805
|
+
var _a, _b, _c, _d, _e;
|
|
806
|
+
switch (pos.rules) {
|
|
807
|
+
case "chess":
|
|
808
|
+
case "antichess":
|
|
809
|
+
case "atomic":
|
|
810
|
+
case "kingofthehill":
|
|
811
|
+
case "3check":
|
|
812
|
+
return types_js_1.COLORS.every((color) => (0, chess_js_1.isStandardMaterialSide)(pos.board, color));
|
|
813
|
+
case "crazyhouse": {
|
|
814
|
+
const promoted = pos.board.promoted;
|
|
815
|
+
return (promoted.size() + pos.board.pawn.size() + (((_a = pos.pockets) === null || _a === void 0 ? void 0 : _a.count("pawn")) || 0) <= 16 &&
|
|
816
|
+
pos.board.knight.diff(promoted).size() + (((_b = pos.pockets) === null || _b === void 0 ? void 0 : _b.count("knight")) || 0) <= 4 &&
|
|
817
|
+
pos.board.bishop.diff(promoted).size() + (((_c = pos.pockets) === null || _c === void 0 ? void 0 : _c.count("bishop")) || 0) <= 4 &&
|
|
818
|
+
pos.board.rook.diff(promoted).size() + (((_d = pos.pockets) === null || _d === void 0 ? void 0 : _d.count("rook")) || 0) <= 4 &&
|
|
819
|
+
pos.board.queen.diff(promoted).size() + (((_e = pos.pockets) === null || _e === void 0 ? void 0 : _e.count("queen")) || 0) <= 2);
|
|
820
|
+
}
|
|
821
|
+
case "horde":
|
|
822
|
+
return types_js_1.COLORS.every((color) => pos.board.pieces(color, "king").nonEmpty()
|
|
823
|
+
? (0, chess_js_1.isStandardMaterialSide)(pos.board, color)
|
|
824
|
+
: pos.board[color].size() <= 36);
|
|
825
|
+
case "racingkings":
|
|
826
|
+
return types_js_1.COLORS.every((color) => pos.board.pieces(color, "knight").size() <= 2 &&
|
|
827
|
+
pos.board.pieces(color, "bishop").size() <= 2 &&
|
|
828
|
+
pos.board.pieces(color, "rook").size() <= 2 &&
|
|
829
|
+
pos.board.pieces(color, "queen").size() <= 1);
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
exports.isStandardMaterial = isStandardMaterial;
|
|
833
|
+
//# sourceMappingURL=variant.js.map
|