Some simplifactions, a few fixes, update TODO
[vchess.git] / client / src / variants / Twokings.js
1 import { ChessRules } from "@/base_rules";
2 import { CoregalRules } from "@/variants/Coregal";
3
4 export class TwokingsRules extends CoregalRules {
5
6 static get PawnSpecs() {
7 return Object.assign(
8 {},
9 ChessRules.PawnSpecs,
10 { promotions: ChessRules.PawnSpecs.promotions.concat([V.KING]) }
11 );
12 }
13
14 static IsGoodPosition(position) {
15 if (position.length == 0) return false;
16 const rows = position.split("/");
17 if (rows.length != V.size.x) return false;
18 let kings = { 'K': 0, 'k': 0 };
19 for (let row of rows) {
20 let sumElts = 0;
21 for (let i = 0; i < row.length; i++) {
22 if (['K','k'].includes(row[i])) kings[row[i]]++;
23 if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
24 else {
25 const num = parseInt(row[i], 10);
26 if (isNaN(num)) return false;
27 sumElts += num;
28 }
29 }
30 if (sumElts != V.size.y) return false;
31 }
32 // Two kings (at least) per side should be present:
33 if (Object.values(kings).some(v => v < 2)) return false;
34 return true;
35 }
36
37 // Not scanning king positions. In this variant, scan the board everytime.
38 scanKings() {}
39
40 getCheckSquares() {
41 const color = this.turn;
42 let squares = [];
43 const oppCol = V.GetOppCol(color);
44 for (let i=0; i<V.size.x; i++) {
45 for (let j=0; j<V.size.y; j++) {
46 if (
47 this.getColor(i, j) == color &&
48 this.getPiece(i, j) == V.KING &&
49 this.isAttacked([i, j], oppCol)
50 ) {
51 squares.push([i, j]);
52 }
53 }
54 }
55 return squares;
56 }
57
58 static GenRandInitFen(randomness) {
59 if (randomness == 0)
60 return "rnqkkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNQKKBNR w 0 adehadeh -";
61
62 const replaceBishop = (fen, first, ch1, ch2) => {
63 // Remove and re-add final part:
64 const suffix = fen.substr(-15);
65 fen = fen.slice(0, -15);
66 if (first) fen = fen.replace(ch1, ch2);
67 else {
68 fen =
69 fen.split("").reverse().join("")
70 .replace(ch1, ch2)
71 .split("").reverse().join("")
72 }
73 return fen + suffix;
74 };
75
76 const sameIndexReplace = (fen) => {
77 const first = (Math.random() < 0.5);
78 return replaceBishop(
79 replaceBishop(fen, first, 'B', 'Q'),
80 first,
81 'b',
82 'q'
83 );
84 };
85
86 const fen =
87 CoregalRules.GenRandInitFen(randomness)
88 .replace("q", "k").replace("Q", "K");
89 // Now replace a bishop by the queen,
90 // so that bishops are of different colors:
91 if (randomness == 1) return sameIndexReplace(fen);
92 const wOdd = fen.indexOf('B') % 2;
93 const bOdd = fen.indexOf('b') % 2;
94 // Since there are 7 slashes, different oddities means symmetric
95 if (wOdd != bOdd) return sameIndexReplace(fen);
96 const wFirst = (Math.random() < 0.5);
97 return replaceBishop(
98 replaceBishop(fen, wFirst, 'B', 'Q'),
99 !wFirst,
100 'b',
101 'q'
102 );
103 }
104
105 getPotentialQueenMoves(sq) {
106 return this.getSlideNJumpMoves(sq,
107 V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
108 }
109
110 underCheck(color) {
111 const oppCol = V.GetOppCol(color);
112 for (let i=0; i<V.size.x; i++) {
113 for (let j=0; j<V.size.y; j++) {
114 if (
115 this.getColor(i, j) == color &&
116 this.getPiece(i, j) == V.KING &&
117 this.isAttacked([i, j], oppCol)
118 ) {
119 return true;
120 }
121 }
122 }
123 return false;
124 }
125
126 postPlay(move) {
127 const piece = move.vanish[0].p;
128 super.updateCastleFlags(move, piece, "twoKings");
129 }
130
131 postUndo() {}
132
133 };