Merge Atomic1 & 2
[vchess.git] / client / src / variants / Cwda.js
CommitLineData
4313762d 1import { ChessRules } from "@/base_rules";
801e2870 2
cee75a57 3export class CwdaRules extends ChessRules {
7e8a7ea1 4
4313762d
BA
5 static get Options() {
6 return {
7 select: ChessRules.Options.select.concat([
8 {
9 label: "Army 1",
10 variable: "army1",
11 defaut: 'C',
12 options: [
13 { label: "Colorbound Clobberers", value: 'C' },
14 { label: "Nutty Knights", value: 'N' },
15 { label: "Remarkable Rookies", value: 'R' },
16 { label: "Fide", value: 'F' }
17 ]
18 },
19 {
20 label: "Army 2",
21 variable: "army2",
22 defaut: 'C',
23 options: [
24 { label: "Colorbound Clobberers", value: 'C' },
25 { label: "Nutty Knights", value: 'N' },
26 { label: "Remarkable Rookies", value: 'R' },
27 { label: "Fide", value: 'F' }
28 ]
29 }
30 ])
31 };
32 }
33
34 static AbbreviateOptions(opts) {
35 return opts["army1"] + opts["army2"];
36 }
37
38 static IsValidOptions(opts) {
39 // Both armies filled, avoid Fide vs Fide
40 return (
41 opts.army1 && opts.army2 &&
42 (opts.army1 != 'F' || opts.army2 != 'F')
801e2870
BA
43 );
44 }
45
46 getPpath(b) {
4313762d
BA
47 return (ChessRules.PIECES.includes(b[1]) ? "" : "Cwda/") + b;
48 }
49
50 static get PiecesMap() {
51 return {
52 // Colorbound Clobberers
53 'C': {
54 'r': 'd',
55 'n': 'w',
56 'b': 'f',
57 'q': 'c',
58 'k': 'k'
59 },
60 // Nutty Knights
61 'N': {
62 'r': 'g',
63 'n': 'i',
64 'b': 't',
65 'q': 'l',
66 'k': 'k'
67 },
68 // Remarkable Rookies
69 'R': {
70 'r': 's',
71 'n': 'y',
72 'b': 'h',
73 'q': 'o',
74 'k': 'k'
75 }
801e2870 76 };
4313762d 77 }
801e2870 78
4313762d
BA
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('');
85 }
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();
91 }
801e2870 92 return (
4313762d
BA
93 blackLine + baseFen.substring(8, 35) + whiteLine +
94 baseFen.substr(43) + " " + options.army1 + options.army2
801e2870
BA
95 );
96 }
97
4313762d
BA
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);
103 }
104
105 static ParseFen(fen) {
106 return Object.assign(
107 { armies: fen.split(" ")[5] },
108 ChessRules.ParseFen(fen)
109 );
110 }
111
112 static IsGoodFen(fen) {
113 if (!ChessRules.IsGoodFen(fen)) return false;
114 const armies = V.ParseFen(fen).armies;
10cceb25 115 return (!!armies && armies.match(/^[CNRF]{2,2}$/));
4313762d
BA
116 }
117
118 getFen() {
119 return super.getFen() + " " + this.army1 + this.army2;
120 }
121
801e2870
BA
122 static get C_ROOK() {
123 return 'd';
124 }
125 static get C_KNIGHT() {
4313762d 126 return 'w';
801e2870
BA
127 }
128 static get C_BISHOP() {
4313762d 129 return 'f';
801e2870
BA
130 }
131 static get C_QUEEN() {
4313762d
BA
132 return 'c';
133 }
134 static get N_ROOK() {
135 return 'g';
136 }
137 static get N_KNIGHT() {
138 return 'i';
139 }
140 static get N_BISHOP() {
141 return 't';
142 }
143 static get N_QUEEN() {
144 return 'l';
145 }
146 static get R_ROOK() {
801e2870
BA
147 return 's';
148 }
4313762d
BA
149 static get R_KNIGHT() {
150 return 'y';
151 }
152 static get R_BISHOP() {
153 return 'h';
154 }
155 static get R_QUEEN() {
156 return 'o';
157 }
801e2870
BA
158
159 static get PIECES() {
4313762d
BA
160 return ChessRules.PIECES.concat(
161 [V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN]).concat(
162 [V.N_ROOK, V.N_KNIGHT, V.N_BISHOP, V.N_QUEEN]).concat(
163 [V.R_ROOK, V.R_KNIGHT, V.R_BISHOP, V.R_QUEEN]);
801e2870
BA
164 }
165
4313762d
BA
166 getPotentialMovesFrom(sq) {
167 switch (this.getPiece(sq[0], sq[1])) {
168 case V.C_ROOK: return this.getPotentialC_rookMoves(sq);
169 case V.C_KNIGHT: return this.getPotentialC_knightMoves(sq);
170 case V.C_BISHOP: return this.getPotentialC_bishopMoves(sq);
171 case V.C_QUEEN: return this.getPotentialC_queenMoves(sq);
172 case V.N_ROOK: return this.getPotentialN_rookMoves(sq);
173 case V.N_KNIGHT: return this.getPotentialN_knightMoves(sq);
174 case V.N_BISHOP: return this.getPotentialN_bishopMoves(sq);
175 case V.N_QUEEN: return this.getPotentialN_queenMoves(sq);
176 case V.R_ROOK: return this.getPotentialR_rookMoves(sq);
177 case V.R_KNIGHT: return this.getPotentialR_knightMoves(sq);
178 case V.R_BISHOP: return this.getPotentialR_bishopMoves(sq);
179 case V.R_QUEEN: return this.getPotentialR_queenMoves(sq);
180 case V.PAWN: {
181 // Can promote in anything from the two current armies
182 let promotions = [];
183 for (let army of ["army1", "army2"]) {
184 if (army == "army2" && this.army2 == this.army1) break;
185 switch (this[army]) {
186 case 'C': {
187 Array.prototype.push.apply(promotions,
188 [V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN]);
189 break;
190 }
191 case 'N': {
192 Array.prototype.push.apply(promotions,
193 [V.N_ROOK, V.N_KNIGHT, V.N_BISHOP, V.N_QUEEN]);
194 break;
195 }
196 case 'R': {
197 Array.prototype.push.apply(promotions,
198 [V.R_ROOK, V.R_KNIGHT, V.R_BISHOP, V.R_QUEEN]);
199 break;
200 }
201 case 'F': {
202 Array.prototype.push.apply(promotions,
203 [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]);
204 break;
205 }
206 }
207 }
208 return super.getPotentialPawnMoves(sq, promotions);
209 }
210 default: return super.getPotentialMovesFrom(sq);
801e2870
BA
211 }
212 return [];
213 }
214
215 static get steps() {
216 return Object.assign(
801e2870
BA
217 {
218 // Dabbabah
219 'd': [
220 [-2, 0],
221 [0, -2],
222 [2, 0],
223 [0, 2]
224 ],
225 // Alfil
226 'a': [
227 [2, 2],
228 [2, -2],
229 [-2, 2],
230 [-2, -2]
231 ],
232 // Ferz
233 'f': [
234 [1, 1],
235 [1, -1],
236 [-1, 1],
237 [-1, -1]
4313762d
BA
238 ],
239 // Wazir
240 'w': [
241 [-1, 0],
242 [0, -1],
243 [1, 0],
244 [0, 1]
245 ],
246 // Threeleaper
247 '$3': [
248 [-3, 0],
249 [0, -3],
250 [3, 0],
251 [0, 3]
252 ],
253 // Narrow knight
254 '$n': [
255 [-2, -1],
256 [-2, 1],
257 [2, -1],
258 [2, 1]
801e2870 259 ]
4313762d
BA
260 },
261 ChessRules.steps,
801e2870
BA
262 );
263 }
264
265 getPotentialC_rookMoves(sq) {
266 return (
4313762d
BA
267 this.getSlideNJumpMoves(sq, V.steps.b).concat(
268 this.getSlideNJumpMoves(sq, V.steps.d, 1))
801e2870
BA
269 );
270 }
271
272 getPotentialC_knightMoves(sq) {
273 return (
4313762d
BA
274 this.getSlideNJumpMoves(sq, V.steps.a, 1).concat(
275 this.getSlideNJumpMoves(sq, V.steps.r, 1))
801e2870
BA
276 );
277 }
278
279 getPotentialC_bishopMoves(sq) {
280 return (
4313762d
BA
281 this.getSlideNJumpMoves(sq, V.steps.d, 1).concat(
282 this.getSlideNJumpMoves(sq, V.steps.a, 1)).concat(
283 this.getSlideNJumpMoves(sq, V.steps.b, 1))
801e2870
BA
284 );
285 }
286
287 getPotentialC_queenMoves(sq) {
288 return (
4313762d
BA
289 this.getSlideNJumpMoves(sq, V.steps.b).concat(
290 this.getSlideNJumpMoves(sq, V.steps.n, 1))
291 );
292 }
293
294 getPotentialN_rookMoves(sq) {
295 const c = this.turn;
296 const rookSteps = [ [0, -1], [0, 1], [c == 'w' ? -1 : 1, 0] ];
297 const backward = (c == 'w' ? 1 : -1);
298 const kingSteps = [ [backward, -1], [backward, 0], [backward, 1] ];
299 return (
300 this.getSlideNJumpMoves(sq, rookSteps).concat(
301 this.getSlideNJumpMoves(sq, kingSteps, 1))
302 );
303 }
304
305 getPotentialN_knightMoves(sq) {
4313762d
BA
306 return (
307 this.getSlideNJumpMoves(sq, V.steps.$n, 1).concat(
902378e6 308 this.getSlideNJumpMoves(sq, V.steps.f, 1))
4313762d
BA
309 );
310 }
311
312 getPotentialN_bishopMoves(sq) {
313 const backward = (this.turn == 'w' ? 1 : -1);
314 const kingSteps = [
315 [0, -1], [0, 1], [backward, -1], [backward, 0], [backward, 1]
316 ];
317 const forward = -backward;
318 const knightSteps = [
319 [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2]
320 ];
321 return (
322 this.getSlideNJumpMoves(sq, knightSteps, 1).concat(
323 this.getSlideNJumpMoves(sq, kingSteps, 1))
324 );
325 }
326
327 getPotentialN_queenMoves(sq) {
328 const backward = (this.turn == 'w' ? 1 : -1);
329 const forward = -backward;
330 const kingSteps = [
331 [forward, -1], [forward, 1],
332 [backward, -1], [backward, 0], [backward, 1]
333 ];
334 const knightSteps = [
335 [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2]
336 ];
337 const rookSteps = [ [0, -1], [0, 1], [forward, 0] ];
338 return (
339 this.getSlideNJumpMoves(sq, rookSteps).concat(
340 this.getSlideNJumpMoves(sq, kingSteps, 1)).concat(
341 this.getSlideNJumpMoves(sq, knightSteps, 1))
342 );
343 }
344
345 getPotentialR_rookMoves(sq) {
346 return this.getSlideNJumpMoves(sq, V.steps.r, 4);
347 }
348
349 getPotentialR_knightMoves(sq) {
350 return (
351 this.getSlideNJumpMoves(sq, V.steps.d, 1).concat(
352 this.getSlideNJumpMoves(sq, V.steps.w, 1))
353 );
354 }
355
356 getPotentialR_bishopMoves(sq) {
357 return (
358 this.getSlideNJumpMoves(sq, V.steps.d, 1).concat(
359 this.getSlideNJumpMoves(sq, V.steps.f, 1)).concat(
360 this.getSlideNJumpMoves(sq, V.steps.$3, 1))
361 );
362 }
363
364 getPotentialR_queenMoves(sq) {
365 return (
366 this.getSlideNJumpMoves(sq, V.steps.r).concat(
367 this.getSlideNJumpMoves(sq, V.steps.n, 1))
801e2870
BA
368 );
369 }
370
801e2870 371 getCastleMoves([x, y]) {
7e8a7ea1 372 const color = this.getColor(x, y);
4313762d
BA
373 let finalSquares = [ [2, 3], [V.size.y - 2, V.size.y - 3] ];
374 if (
375 (color == 'w' && this.army1 == 'C') ||
376 (color == 'b' && this.army2 == 'C')
377 ) {
378 // Colorbound castle long in an unusual way:
379 finalSquares[0] = [1, 2];
380 }
7e8a7ea1 381 return super.getCastleMoves([x, y], finalSquares);
801e2870
BA
382 }
383
384 isAttacked(sq, color) {
4313762d
BA
385 if (super.isAttackedByPawn(sq, color) || super.isAttackedByKing(sq, color))
386 return true;
387 for (let army of ['C', 'N', 'R', 'F']) {
388 if (
389 [this.army1, this.army2].includes(army) &&
390 (
391 this["isAttackedBy" + army + "_rook"](sq, color) ||
392 this["isAttackedBy" + army + "_knight"](sq, color) ||
393 this["isAttackedBy" + army + "_bishop"](sq, color) ||
394 this["isAttackedBy" + army + "_queen"](sq, color)
395 )
396 ) {
397 return true;
398 }
399 }
400 return false;
801e2870
BA
401 }
402
403 isAttackedByC_rook(sq, color) {
404 return (
4313762d
BA
405 this.isAttackedBySlideNJump(sq, color, V.C_ROOK, V.steps.b) ||
406 this.isAttackedBySlideNJump(sq, color, V.C_ROOK, V.steps.d, 1)
801e2870
BA
407 );
408 }
409
410 isAttackedByC_knight(sq, color) {
411 return (
4313762d
BA
412 this.isAttackedBySlideNJump(sq, color, V.C_KNIGHT, V.steps.r, 1) ||
413 this.isAttackedBySlideNJump(sq, color, V.C_KNIGHT, V.steps.a, 1)
801e2870
BA
414 );
415 }
416
417 isAttackedByC_bishop(sq, color) {
418 return (
4313762d
BA
419 this.isAttackedBySlideNJump(sq, color, V.C_BISHOP, V.steps.d, 1) ||
420 this.isAttackedBySlideNJump(sq, color, V.C_BISHOP, V.steps.a, 1) ||
421 this.isAttackedBySlideNJump(sq, color, V.C_BISHOP, V.steps.f, 1)
801e2870
BA
422 );
423 }
424
425 isAttackedByC_queen(sq, color) {
426 return (
4313762d
BA
427 this.isAttackedBySlideNJump(sq, color, V.C_QUEEN, V.steps.b) ||
428 this.isAttackedBySlideNJump(sq, color, V.C_QUEEN, V.steps.n, 1)
429 );
430 }
431
432 isAttackedByN_rook(sq, color) {
433 const rookSteps = [ [0, -1], [0, 1], [color == 'w' ? 1 : -1, 0] ];
434 const backward = (color == 'w' ? -1 : 1);
435 const kingSteps = [ [backward, -1], [backward, 0], [backward, 1] ];
436 return (
437 this.isAttackedBySlideNJump(sq, color, V.N_ROOK, rookSteps) ||
438 this.isAttackedBySlideNJump(sq, color, V.N_ROOK, kingSteps, 1)
439 );
440 }
441
442 isAttackedByN_knight(sq, color) {
4313762d 443 return (
902378e6
BA
444 this.isAttackedBySlideNJump(sq, color, V.N_KNIGHT, V.steps.$n, 1) ||
445 this.isAttackedBySlideNJump(sq, color, V.N_KNIGHT, V.steps.f, 1)
4313762d
BA
446 );
447 }
448
449 isAttackedByN_bishop(sq, color) {
450 const backward = (color == 'w' ? -1 : 1);
451 const kingSteps = [
452 [0, -1], [0, 1], [backward, -1], [backward, 0], [backward, 1]
453 ];
454 const forward = -backward;
455 const knightSteps = [
456 [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2]
457 ];
458 return (
459 this.isAttackedBySlideNJump(sq, color, V.N_BISHOP, knightSteps, 1) ||
460 this.isAttackedBySlideNJump(sq, color, V.N_BISHOP, kingSteps, 1)
461 );
462 }
463
464 isAttackedByN_queen(sq, color) {
465 const backward = (color == 'w' ? -1 : 1);
466 const forward = -backward;
467 const kingSteps = [
468 [forward, -1], [forward, 1],
469 [backward, -1], [backward, 0], [backward, 1]
470 ];
471 const knightSteps = [
472 [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2]
473 ];
474 const rookSteps = [ [0, -1], [0, 1], [forward, 0] ];
475 return (
476 this.isAttackedBySlideNJump(sq, color, V.N_QUEEN, knightSteps, 1) ||
477 this.isAttackedBySlideNJump(sq, color, V.N_QUEEN, kingSteps, 1) ||
478 this.isAttackedBySlideNJump(sq, color, V.N_QUEEN, rookSteps)
479 );
480 }
481
482 isAttackedByR_rook(sq, color) {
483 return this.isAttackedBySlideNJump(sq, color, V.R_ROOK, V.steps.r, 4);
484 }
485
486 isAttackedByR_knight(sq, color) {
487 return (
488 this.isAttackedBySlideNJump(sq, color, V.R_KNIGHT, V.steps.d, 1) ||
489 this.isAttackedBySlideNJump(sq, color, V.R_KNIGHT, V.steps.w, 1)
490 );
491 }
492
493 isAttackedByR_bishop(sq, color) {
494 return (
495 this.isAttackedBySlideNJump(sq, color, V.R_BISHOP, V.steps.d, 1) ||
496 this.isAttackedBySlideNJump(sq, color, V.R_BISHOP, V.steps.f, 1) ||
497 this.isAttackedBySlideNJump(sq, color, V.R_BISHOP, V.steps.$3, 1)
498 );
499 }
500
501 isAttackedByR_queen(sq, color) {
502 return (
503 this.isAttackedBySlideNJump(sq, color, V.R_QUEEN, V.steps.r) ||
504 this.isAttackedBySlideNJump(sq, color, V.R_QUEEN, V.steps.n, 1)
801e2870
BA
505 );
506 }
507
b2f43cc3
BA
508 // [HACK] So that the function above works also on Fide army:
509 isAttackedByF_rook(sq, color) {
510 return super.isAttackedByRook(sq, color);
511 }
512 isAttackedByF_knight(sq, color) {
513 return super.isAttackedByKnight(sq, color);
514 }
515 isAttackedByF_bishop(sq, color) {
516 return super.isAttackedByBishop(sq, color);
517 }
518 isAttackedByF_queen(sq, color) {
519 return super.isAttackedByQueen(sq, color);
520 }
521
801e2870
BA
522 static get VALUES() {
523 return Object.assign(
801e2870
BA
524 {
525 d: 4,
4313762d
BA
526 w: 3,
527 f: 5,
528 c: 7,
529 g: 4,
530 i: 3,
531 t: 4,
532 l: 7,
533 s: 4,
534 y: 3,
535 h: 4,
536 o: 8
537 },
538 ChessRules.VALUES
801e2870
BA
539 );
540 }
48252022
BA
541
542 static get SEARCH_DEPTH() {
543 return 2;
544 }
7e8a7ea1 545
801e2870 546};