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
82 static GenRandInitFen(options
) {
83 const baseFen
= ChessRules
.GenRandInitFen(options
.randomness
);
84 let blackLine
= baseFen
.substr(0, 8), blackPawns
= "pppppppp";
85 if (options
.army2
!= 'F') {
86 blackLine
= blackLine
.split('')
87 .map(p
=> V
.PiecesMap
[options
.army2
][p
]).join('');
88 blackPawns
= V
.PiecesMap
[options
.army2
]['p'].repeat(8);
90 let whiteLine
= baseFen
.substr(35, 8), whitePawns
= "PPPPPPPP";
91 if (options
.army1
!= 'F') {
92 whiteLine
= whiteLine
.split('')
93 .map(p
=> V
.PiecesMap
[options
.army1
][p
.toLowerCase()])
94 .join('').toUpperCase();
95 whitePawns
= V
.PiecesMap
[options
.army1
]['p'].toUpperCase().repeat(8);
98 blackLine
+ "/" + blackPawns
+
99 baseFen
.substring(17, 26) +
100 whitePawns
+ "/" + whiteLine
+
101 baseFen
.substr(43) + " " + options
.army1
+ options
.army2
105 setOtherVariables(fen
) {
106 super.setOtherVariables(fen
);
107 const armies
= V
.ParseFen(fen
).armies
;
108 this.army1
= armies
.charAt(0);
109 this.army2
= armies
.charAt(1);
112 static ParseFen(fen
) {
113 return Object
.assign(
114 { armies: fen
.split(" ")[5] },
115 ChessRules
.ParseFen(fen
)
119 static IsGoodFen(fen
) {
120 if (!ChessRules
.IsGoodFen(fen
)) return false;
121 const armies
= V
.ParseFen(fen
).armies
;
122 return (!!armies
&& armies
.match(/^[CNRF]{2,2}$/));
126 return super.getFen() + " " + this.army1
+ this.army2
;
129 static get C_ROOK() {
132 static get C_KNIGHT() {
135 static get C_BISHOP() {
138 static get C_QUEEN() {
141 static get N_ROOK() {
144 static get N_KNIGHT() {
147 static get N_BISHOP() {
150 static get N_QUEEN() {
153 static get N_KING() {
156 static get N_PAWN() {
159 static get R_ROOK() {
162 static get R_KNIGHT() {
165 static get R_BISHOP() {
168 static get R_QUEEN() {
171 static get R_KING() {
174 static get R_PAWN() {
179 const p
= this.board
[x
][y
][1];
180 if (['u', 'v'].includes(p
)) return 'p';
181 if (['a', 'e'].includes(p
)) return 'k';
185 static get PIECES() {
186 return ChessRules
.PIECES
.concat(
188 V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
,
189 V
.N_ROOK
, V
.N_KNIGHT
, V
.N_BISHOP
, V
.N_QUEEN
, V
.N_KING
, V
.N_PAWN
,
190 V
.R_ROOK
, V
.R_KNIGHT
, V
.R_BISHOP
, V
.R_QUEEN
, V
.R_KING
, V
.R_PAWN
195 getPotentialMovesFrom(sq
) {
196 switch (this.getPiece(sq
[0], sq
[1])) {
197 case V
.C_ROOK: return this.getPotentialC_rookMoves(sq
);
198 case V
.C_KNIGHT: return this.getPotentialC_knightMoves(sq
);
199 case V
.C_BISHOP: return this.getPotentialC_bishopMoves(sq
);
200 case V
.C_QUEEN: return this.getPotentialC_queenMoves(sq
);
201 case V
.N_ROOK: return this.getPotentialN_rookMoves(sq
);
202 case V
.N_KNIGHT: return this.getPotentialN_knightMoves(sq
);
203 case V
.N_BISHOP: return this.getPotentialN_bishopMoves(sq
);
204 case V
.N_QUEEN: return this.getPotentialN_queenMoves(sq
);
205 case V
.R_ROOK: return this.getPotentialR_rookMoves(sq
);
206 case V
.R_KNIGHT: return this.getPotentialR_knightMoves(sq
);
207 case V
.R_BISHOP: return this.getPotentialR_bishopMoves(sq
);
208 case V
.R_QUEEN: return this.getPotentialR_queenMoves(sq
);
210 // Can promote in anything from the two current armies
212 for (let army
of ["army1", "army2"]) {
213 if (army
== "army2" && this.army2
== this.army1
) break;
214 switch (this[army
]) {
216 Array
.prototype.push
.apply(promotions
,
217 [V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
]);
221 Array
.prototype.push
.apply(promotions
,
222 [V
.N_ROOK
, V
.N_KNIGHT
, V
.N_BISHOP
, V
.N_QUEEN
]);
226 Array
.prototype.push
.apply(promotions
,
227 [V
.R_ROOK
, V
.R_KNIGHT
, V
.R_BISHOP
, V
.R_QUEEN
]);
231 Array
.prototype.push
.apply(promotions
,
232 [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]);
237 return super.getPotentialPawnMoves(sq
, promotions
);
239 default: return super.getPotentialMovesFrom(sq
);
245 return Object
.assign(
294 getPotentialC_rookMoves(sq
) {
296 this.getSlideNJumpMoves(sq
, V
.steps
.b
).concat(
297 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1))
301 getPotentialC_knightMoves(sq
) {
303 this.getSlideNJumpMoves(sq
, V
.steps
.a
, 1).concat(
304 this.getSlideNJumpMoves(sq
, V
.steps
.r
, 1))
308 getPotentialC_bishopMoves(sq
) {
310 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
311 this.getSlideNJumpMoves(sq
, V
.steps
.a
, 1)).concat(
312 this.getSlideNJumpMoves(sq
, V
.steps
.b
, 1))
316 getPotentialC_queenMoves(sq
) {
318 this.getSlideNJumpMoves(sq
, V
.steps
.b
).concat(
319 this.getSlideNJumpMoves(sq
, V
.steps
.n
, 1))
323 getPotentialN_rookMoves(sq
) {
325 const rookSteps
= [ [0, -1], [0, 1], [c
== 'w' ? -1 : 1, 0] ];
326 const backward
= (c
== 'w' ? 1 : -1);
327 const kingSteps
= [ [backward
, -1], [backward
, 0], [backward
, 1] ];
329 this.getSlideNJumpMoves(sq
, rookSteps
).concat(
330 this.getSlideNJumpMoves(sq
, kingSteps
, 1))
334 getPotentialN_knightMoves(sq
) {
336 this.getSlideNJumpMoves(sq
, V
.steps
.$n
, 1).concat(
337 this.getSlideNJumpMoves(sq
, V
.steps
.f
, 1))
341 getPotentialN_bishopMoves(sq
) {
342 const backward
= (this.turn
== 'w' ? 1 : -1);
344 [0, -1], [0, 1], [backward
, -1], [backward
, 0], [backward
, 1]
346 const forward
= -backward
;
347 const knightSteps
= [
348 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
351 this.getSlideNJumpMoves(sq
, knightSteps
, 1).concat(
352 this.getSlideNJumpMoves(sq
, kingSteps
, 1))
356 getPotentialN_queenMoves(sq
) {
357 const backward
= (this.turn
== 'w' ? 1 : -1);
358 const forward
= -backward
;
360 [forward
, -1], [forward
, 1],
361 [backward
, -1], [backward
, 0], [backward
, 1]
363 const knightSteps
= [
364 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
366 const rookSteps
= [ [0, -1], [0, 1], [forward
, 0] ];
368 this.getSlideNJumpMoves(sq
, rookSteps
).concat(
369 this.getSlideNJumpMoves(sq
, kingSteps
, 1)).concat(
370 this.getSlideNJumpMoves(sq
, knightSteps
, 1))
374 getPotentialR_rookMoves(sq
) {
375 return this.getSlideNJumpMoves(sq
, V
.steps
.r
, 4);
378 getPotentialR_knightMoves(sq
) {
380 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
381 this.getSlideNJumpMoves(sq
, V
.steps
.w
, 1))
385 getPotentialR_bishopMoves(sq
) {
387 this.getSlideNJumpMoves(sq
, V
.steps
.d
, 1).concat(
388 this.getSlideNJumpMoves(sq
, V
.steps
.f
, 1)).concat(
389 this.getSlideNJumpMoves(sq
, V
.steps
.$3, 1))
393 getPotentialR_queenMoves(sq
) {
395 this.getSlideNJumpMoves(sq
, V
.steps
.r
).concat(
396 this.getSlideNJumpMoves(sq
, V
.steps
.n
, 1))
400 getCastleMoves([x
, y
]) {
401 const color
= this.getColor(x
, y
);
402 let finalSquares
= [ [2, 3], [V
.size
.y
- 2, V
.size
.y
- 3] ];
404 (color
== 'w' && this.army1
== 'C') ||
405 (color
== 'b' && this.army2
== 'C')
407 // Colorbound castle long in an unusual way:
408 finalSquares
[0] = [1, 2];
410 return super.getCastleMoves([x
, y
], finalSquares
);
413 isAttacked(sq
, color
) {
414 if (super.isAttackedByPawn(sq
, color
) || super.isAttackedByKing(sq
, color
))
416 for (let army
of ['C', 'N', 'R', 'F']) {
418 [this.army1
, this.army2
].includes(army
) &&
420 this["isAttackedBy" + army
+ "_rook"](sq
, color
) ||
421 this["isAttackedBy" + army
+ "_knight"](sq
, color
) ||
422 this["isAttackedBy" + army
+ "_bishop"](sq
, color
) ||
423 this["isAttackedBy" + army
+ "_queen"](sq
, color
)
432 isAttackedByC_rook(sq
, color
) {
434 this.isAttackedBySlideNJump(sq
, color
, V
.C_ROOK
, V
.steps
.b
) ||
435 this.isAttackedBySlideNJump(sq
, color
, V
.C_ROOK
, V
.steps
.d
, 1)
439 isAttackedByC_knight(sq
, color
) {
441 this.isAttackedBySlideNJump(sq
, color
, V
.C_KNIGHT
, V
.steps
.r
, 1) ||
442 this.isAttackedBySlideNJump(sq
, color
, V
.C_KNIGHT
, V
.steps
.a
, 1)
446 isAttackedByC_bishop(sq
, color
) {
448 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.d
, 1) ||
449 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.a
, 1) ||
450 this.isAttackedBySlideNJump(sq
, color
, V
.C_BISHOP
, V
.steps
.f
, 1)
454 isAttackedByC_queen(sq
, color
) {
456 this.isAttackedBySlideNJump(sq
, color
, V
.C_QUEEN
, V
.steps
.b
) ||
457 this.isAttackedBySlideNJump(sq
, color
, V
.C_QUEEN
, V
.steps
.n
, 1)
461 isAttackedByN_rook(sq
, color
) {
462 const rookSteps
= [ [0, -1], [0, 1], [color
== 'w' ? 1 : -1, 0] ];
463 const backward
= (color
== 'w' ? -1 : 1);
464 const kingSteps
= [ [backward
, -1], [backward
, 0], [backward
, 1] ];
466 this.isAttackedBySlideNJump(sq
, color
, V
.N_ROOK
, rookSteps
) ||
467 this.isAttackedBySlideNJump(sq
, color
, V
.N_ROOK
, kingSteps
, 1)
471 isAttackedByN_knight(sq
, color
) {
473 this.isAttackedBySlideNJump(sq
, color
, V
.N_KNIGHT
, V
.steps
.$n
, 1) ||
474 this.isAttackedBySlideNJump(sq
, color
, V
.N_KNIGHT
, V
.steps
.f
, 1)
478 isAttackedByN_bishop(sq
, color
) {
479 const backward
= (color
== 'w' ? -1 : 1);
481 [0, -1], [0, 1], [backward
, -1], [backward
, 0], [backward
, 1]
483 const forward
= -backward
;
484 const knightSteps
= [
485 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
488 this.isAttackedBySlideNJump(sq
, color
, V
.N_BISHOP
, knightSteps
, 1) ||
489 this.isAttackedBySlideNJump(sq
, color
, V
.N_BISHOP
, kingSteps
, 1)
493 isAttackedByN_queen(sq
, color
) {
494 const backward
= (color
== 'w' ? -1 : 1);
495 const forward
= -backward
;
497 [forward
, -1], [forward
, 1],
498 [backward
, -1], [backward
, 0], [backward
, 1]
500 const knightSteps
= [
501 [2*forward
, -1], [2*forward
, 1], [forward
, -2], [forward
, 2]
503 const rookSteps
= [ [0, -1], [0, 1], [forward
, 0] ];
505 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, knightSteps
, 1) ||
506 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, kingSteps
, 1) ||
507 this.isAttackedBySlideNJump(sq
, color
, V
.N_QUEEN
, rookSteps
)
511 isAttackedByR_rook(sq
, color
) {
512 return this.isAttackedBySlideNJump(sq
, color
, V
.R_ROOK
, V
.steps
.r
, 4);
515 isAttackedByR_knight(sq
, color
) {
517 this.isAttackedBySlideNJump(sq
, color
, V
.R_KNIGHT
, V
.steps
.d
, 1) ||
518 this.isAttackedBySlideNJump(sq
, color
, V
.R_KNIGHT
, V
.steps
.w
, 1)
522 isAttackedByR_bishop(sq
, color
) {
524 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.d
, 1) ||
525 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.f
, 1) ||
526 this.isAttackedBySlideNJump(sq
, color
, V
.R_BISHOP
, V
.steps
.$3, 1)
530 isAttackedByR_queen(sq
, color
) {
532 this.isAttackedBySlideNJump(sq
, color
, V
.R_QUEEN
, V
.steps
.r
) ||
533 this.isAttackedBySlideNJump(sq
, color
, V
.R_QUEEN
, V
.steps
.n
, 1)
537 // [HACK] So that the function above works also on Fide army:
538 isAttackedByF_rook(sq
, color
) {
539 return super.isAttackedByRook(sq
, color
);
541 isAttackedByF_knight(sq
, color
) {
542 return super.isAttackedByKnight(sq
, color
);
544 isAttackedByF_bishop(sq
, color
) {
545 return super.isAttackedByBishop(sq
, color
);
547 isAttackedByF_queen(sq
, color
) {
548 return super.isAttackedByQueen(sq
, color
);
551 static get VALUES() {
552 return Object
.assign(
571 static get SEARCH_DEPTH() {