1 import { ChessRules
} from "@/base_rules";
3 export class CwdaRules
extends ChessRules
{
7 select: ChessRules
.Options
.select
.concat([
13 { label: "Colorbound Clobberers", value: 'C' },
14 { label: "Nutty Knights", value: 'N' },
15 { label: "Remarkable Rookies", value: 'R' },
16 { label: "Fide", value: 'F' }
24 { label: "Colorbound Clobberers", value: 'C' },
25 { label: "Nutty Knights", value: 'N' },
26 { label: "Remarkable Rookies", value: 'R' },
27 { label: "Fide", value: 'F' }
34 static AbbreviateOptions(opts
) {
35 return opts
["army1"] + opts
["army2"];
38 static IsValidOptions(opts
) {
39 // Both armies filled, avoid Fide vs Fide
41 opts
.army1
&& opts
.army2
&&
42 (opts
.army1
!= 'F' || opts
.army2
!= 'F')
47 return (ChessRules
.PIECES
.includes(b
[1]) ? "" : "Cwda/") + b
;
50 static get PiecesMap() {
52 // Colorbound Clobberers
79 static GenRandInitFen(options
) {
80 const baseFen
= ChessRules
.GenRandInitFen(options
.randomness
);
81 let blackLine
= baseFen
.substr(0, 8);
82 if (options
.army2
!= 'F') {
83 blackLine
= blackLine
.split('')
84 .map(p
=> V
.PiecesMap
[options
.army2
][p
]).join('');
86 let whiteLine
= baseFen
.substr(35, 8);
87 if (options
.army1
!= 'F') {
88 whiteLine
= whiteLine
.split('')
89 .map(p
=> V
.PiecesMap
[options
.army1
][p
.toLowerCase()])
90 .join('').toUpperCase();
93 blackLine
+ baseFen
.substring(8, 35) + whiteLine
+
94 baseFen
.substr(43) + " " + options
.army1
+ options
.army2
98 setOtherVariables(fen
) {
99 super.setOtherVariables(fen
);
100 const armies
= V
.ParseFen(fen
).armies
;
101 this.army1
= armies
.charAt(0);
102 this.army2
= armies
.charAt(1);
105 static ParseFen(fen
) {
106 return Object
.assign(
107 { armies: fen
.split(" ")[5] },
108 ChessRules
.ParseFen(fen
)
112 static IsGoodFen(fen
) {
113 if (!ChessRules
.IsGoodFen(fen
)) return false;
114 const armies
= V
.ParseFen(fen
).armies
;
115 if (!armies
|| !armies
.match(/^[CNRF]{2,2}$/)) return false;
120 return super.getFen() + " " + this.army1
+ this.army2
;
123 static get C_ROOK() {
126 static get C_KNIGHT() {
129 static get C_BISHOP() {
132 static get C_QUEEN() {
135 static get N_ROOK() {
138 static get N_KNIGHT() {
141 static get N_BISHOP() {
144 static get N_QUEEN() {
147 static get R_ROOK() {
150 static get R_KNIGHT() {
153 static get R_BISHOP() {
156 static get R_QUEEN() {
160 static get PIECES() {
161 return ChessRules
.PIECES
.concat(
162 [V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
]).concat(
163 [V
.N_ROOK
, V
.N_KNIGHT
, V
.N_BISHOP
, V
.N_QUEEN
]).concat(
164 [V
.R_ROOK
, V
.R_KNIGHT
, V
.R_BISHOP
, V
.R_QUEEN
]);
167 getPotentialMovesFrom(sq
) {
168 switch (this.getPiece(sq
[0], sq
[1])) {
169 case V
.C_ROOK: return this.getPotentialC_rookMoves(sq
);
170 case V
.C_KNIGHT: return this.getPotentialC_knightMoves(sq
);
171 case V
.C_BISHOP: return this.getPotentialC_bishopMoves(sq
);
172 case V
.C_QUEEN: return this.getPotentialC_queenMoves(sq
);
173 case V
.N_ROOK: return this.getPotentialN_rookMoves(sq
);
174 case V
.N_KNIGHT: return this.getPotentialN_knightMoves(sq
);
175 case V
.N_BISHOP: return this.getPotentialN_bishopMoves(sq
);
176 case V
.N_QUEEN: return this.getPotentialN_queenMoves(sq
);
177 case V
.R_ROOK: return this.getPotentialR_rookMoves(sq
);
178 case V
.R_KNIGHT: return this.getPotentialR_knightMoves(sq
);
179 case V
.R_BISHOP: return this.getPotentialR_bishopMoves(sq
);
180 case V
.R_QUEEN: return this.getPotentialR_queenMoves(sq
);
182 // Can promote in anything from the two current armies
184 for (let army
of ["army1", "army2"]) {
185 if (army
== "army2" && this.army2
== this.army1
) break;
186 switch (this[army
]) {
188 Array
.prototype.push
.apply(promotions
,
189 [V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
]);
193 Array
.prototype.push
.apply(promotions
,
194 [V
.N_ROOK
, V
.N_KNIGHT
, V
.N_BISHOP
, V
.N_QUEEN
]);
198 Array
.prototype.push
.apply(promotions
,
199 [V
.R_ROOK
, V
.R_KNIGHT
, V
.R_BISHOP
, V
.R_QUEEN
]);
203 Array
.prototype.push
.apply(promotions
,
204 [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]);
209 return super.getPotentialPawnMoves(sq
, promotions
);
211 default: return super.getPotentialMovesFrom(sq
);
217 return Object
.assign(
266 getPotentialC_rookMoves(sq
) {
268 this.getSlideNJumpMoves(sq
, V
.steps
.b
).concat(
269 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1))
273 getPotentialC_knightMoves(sq
) {
275 this.getSlideNJumpMoves(sq
, V
.steps
.a
, 1).concat(
276 this.getSlideNJumpMoves(sq
, V
.steps
.r
, 1))
280 getPotentialC_bishopMoves(sq
) {
282 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
283 this.getSlideNJumpMoves(sq
, V
.steps
.a
, 1)).concat(
284 this.getSlideNJumpMoves(sq
, V
.steps
.b
, 1))
288 getPotentialC_queenMoves(sq
) {
290 this.getSlideNJumpMoves(sq
, V
.steps
.b
).concat(
291 this.getSlideNJumpMoves(sq
, V
.steps
.n
, 1))
295 getPotentialN_rookMoves(sq
) {
297 const rookSteps
= [ [0, -1], [0, 1], [c
== 'w' ? -1 : 1, 0] ];
298 const backward
= (c
== 'w' ? 1 : -1);
299 const kingSteps
= [ [backward
, -1], [backward
, 0], [backward
, 1] ];
301 this.getSlideNJumpMoves(sq
, rookSteps
).concat(
302 this.getSlideNJumpMoves(sq
, kingSteps
, 1))
306 getPotentialN_knightMoves(sq
) {
308 this.getSlideNJumpMoves(sq
, V
.steps
.$n
, 1).concat(
309 this.getSlideNJumpMoves(sq
, V
.steps
.f
, 1))
313 getPotentialN_bishopMoves(sq
) {
314 const backward
= (this.turn
== 'w' ? 1 : -1);
316 [0, -1], [0, 1], [backward
, -1], [backward
, 0], [backward
, 1]
318 const forward
= -backward
;
319 const knightSteps
= [
320 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
323 this.getSlideNJumpMoves(sq
, knightSteps
, 1).concat(
324 this.getSlideNJumpMoves(sq
, kingSteps
, 1))
328 getPotentialN_queenMoves(sq
) {
329 const backward
= (this.turn
== 'w' ? 1 : -1);
330 const forward
= -backward
;
332 [forward
, -1], [forward
, 1],
333 [backward
, -1], [backward
, 0], [backward
, 1]
335 const knightSteps
= [
336 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
338 const rookSteps
= [ [0, -1], [0, 1], [forward
, 0] ];
340 this.getSlideNJumpMoves(sq
, rookSteps
).concat(
341 this.getSlideNJumpMoves(sq
, kingSteps
, 1)).concat(
342 this.getSlideNJumpMoves(sq
, knightSteps
, 1))
346 getPotentialR_rookMoves(sq
) {
347 return this.getSlideNJumpMoves(sq
, V
.steps
.r
, 4);
350 getPotentialR_knightMoves(sq
) {
352 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
353 this.getSlideNJumpMoves(sq
, V
.steps
.w
, 1))
357 getPotentialR_bishopMoves(sq
) {
359 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
360 this.getSlideNJumpMoves(sq
, V
.steps
.f
, 1)).concat(
361 this.getSlideNJumpMoves(sq
, V
.steps
.$3, 1))
365 getPotentialR_queenMoves(sq
) {
367 this.getSlideNJumpMoves(sq
, V
.steps
.r
).concat(
368 this.getSlideNJumpMoves(sq
, V
.steps
.n
, 1))
372 getCastleMoves([x
, y
]) {
373 const color
= this.getColor(x
, y
);
374 let finalSquares
= [ [2, 3], [V
.size
.y
- 2, V
.size
.y
- 3] ];
376 (color
== 'w' && this.army1
== 'C') ||
377 (color
== 'b' && this.army2
== 'C')
379 // Colorbound castle long in an unusual way:
380 finalSquares
[0] = [1, 2];
382 return super.getCastleMoves([x
, y
], finalSquares
);
385 isAttacked(sq
, color
) {
386 if (super.isAttackedByPawn(sq
, color
) || super.isAttackedByKing(sq
, color
))
388 for (let army
of ['C', 'N', 'R', 'F']) {
390 [this.army1
, this.army2
].includes(army
) &&
392 this["isAttackedBy" + army
+ "_rook"](sq
, color
) ||
393 this["isAttackedBy" + army
+ "_knight"](sq
, color
) ||
394 this["isAttackedBy" + army
+ "_bishop"](sq
, color
) ||
395 this["isAttackedBy" + army
+ "_queen"](sq
, color
)
404 isAttackedByC_rook(sq
, color
) {
406 this.isAttackedBySlideNJump(sq
, color
, V
.C_ROOK
, V
.steps
.b
) ||
407 this.isAttackedBySlideNJump(sq
, color
, V
.C_ROOK
, V
.steps
.d
, 1)
411 isAttackedByC_knight(sq
, color
) {
413 this.isAttackedBySlideNJump(sq
, color
, V
.C_KNIGHT
, V
.steps
.r
, 1) ||
414 this.isAttackedBySlideNJump(sq
, color
, V
.C_KNIGHT
, V
.steps
.a
, 1)
418 isAttackedByC_bishop(sq
, color
) {
420 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.d
, 1) ||
421 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.a
, 1) ||
422 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.f
, 1)
426 isAttackedByC_queen(sq
, color
) {
428 this.isAttackedBySlideNJump(sq
, color
, V
.C_QUEEN
, V
.steps
.b
) ||
429 this.isAttackedBySlideNJump(sq
, color
, V
.C_QUEEN
, V
.steps
.n
, 1)
433 isAttackedByN_rook(sq
, color
) {
434 const rookSteps
= [ [0, -1], [0, 1], [color
== 'w' ? 1 : -1, 0] ];
435 const backward
= (color
== 'w' ? -1 : 1);
436 const kingSteps
= [ [backward
, -1], [backward
, 0], [backward
, 1] ];
438 this.isAttackedBySlideNJump(sq
, color
, V
.N_ROOK
, rookSteps
) ||
439 this.isAttackedBySlideNJump(sq
, color
, V
.N_ROOK
, kingSteps
, 1)
443 isAttackedByN_knight(sq
, color
) {
445 this.isAttackedBySlideNJump(sq
, color
, V
.N_KNIGHT
, V
.steps
.$n
, 1) ||
446 this.isAttackedBySlideNJump(sq
, color
, V
.N_KNIGHT
, V
.steps
.f
, 1)
450 isAttackedByN_bishop(sq
, color
) {
451 const backward
= (color
== 'w' ? -1 : 1);
453 [0, -1], [0, 1], [backward
, -1], [backward
, 0], [backward
, 1]
455 const forward
= -backward
;
456 const knightSteps
= [
457 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
460 this.isAttackedBySlideNJump(sq
, color
, V
.N_BISHOP
, knightSteps
, 1) ||
461 this.isAttackedBySlideNJump(sq
, color
, V
.N_BISHOP
, kingSteps
, 1)
465 isAttackedByN_queen(sq
, color
) {
466 const backward
= (color
== 'w' ? -1 : 1);
467 const forward
= -backward
;
469 [forward
, -1], [forward
, 1],
470 [backward
, -1], [backward
, 0], [backward
, 1]
472 const knightSteps
= [
473 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
475 const rookSteps
= [ [0, -1], [0, 1], [forward
, 0] ];
477 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, knightSteps
, 1) ||
478 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, kingSteps
, 1) ||
479 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, rookSteps
)
483 isAttackedByR_rook(sq
, color
) {
484 return this.isAttackedBySlideNJump(sq
, color
, V
.R_ROOK
, V
.steps
.r
, 4);
487 isAttackedByR_knight(sq
, color
) {
489 this.isAttackedBySlideNJump(sq
, color
, V
.R_KNIGHT
, V
.steps
.d
, 1) ||
490 this.isAttackedBySlideNJump(sq
, color
, V
.R_KNIGHT
, V
.steps
.w
, 1)
494 isAttackedByR_bishop(sq
, color
) {
496 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.d
, 1) ||
497 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.f
, 1) ||
498 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.$3, 1)
502 isAttackedByR_queen(sq
, color
) {
504 this.isAttackedBySlideNJump(sq
, color
, V
.R_QUEEN
, V
.steps
.r
) ||
505 this.isAttackedBySlideNJump(sq
, color
, V
.R_QUEEN
, V
.steps
.n
, 1)
509 // [HACK] So that the function above works also on Fide army:
510 isAttackedByF_rook(sq
, color
) {
511 return super.isAttackedByRook(sq
, color
);
513 isAttackedByF_knight(sq
, color
) {
514 return super.isAttackedByKnight(sq
, color
);
516 isAttackedByF_bishop(sq
, color
) {
517 return super.isAttackedByBishop(sq
, color
);
519 isAttackedByF_queen(sq
, color
) {
520 return super.isAttackedByQueen(sq
, color
);
523 static get VALUES() {
524 return Object
.assign(
543 static get SEARCH_DEPTH() {