Almost added TitanChess + EvolutionChess
[vchess.git] / client / src / variants / Colorbound.js
1 import { ChessRules, Move, PiPo } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { randInt } from "@/utils/alea";
4
5 export class ColorboundRules extends ChessRules {
6
7 static get PawnSpecs() {
8 return Object.assign(
9 {},
10 ChessRules.PawnSpecs,
11 {
12 promotions:
13 ChessRules.PawnSpecs.promotions.concat(
14 [V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN])
15 }
16 );
17 }
18
19 getPpath(b) {
20 if ([V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN].includes(b[1]))
21 return "Colorbound/" + b;
22 return b;
23 }
24
25 static GenRandInitFen(randomness) {
26 if (randomness == 0)
27 return "dhaskahd/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 ahah -";
28
29 // Mapping white --> black (at least at start):
30 const piecesMap = {
31 'r': 'd',
32 'n': 'h',
33 'b': 'a',
34 'q': 's',
35 'k': 'k'
36 };
37
38 let pieces = { w: new Array(8), b: new Array(8) };
39 let flags = "";
40 // Shuffle pieces on first (and last rank if randomness == 2)
41 for (let c of ["w", "b"]) {
42 if (c == 'b' && randomness == 1) {
43 pieces['b'] = pieces['w'].map(p => piecesMap[p]);
44 flags += flags;
45 break;
46 }
47
48 // TODO: same code as in base_rules. Should extract and factorize?
49
50 let positions = ArrayFun.range(8);
51
52 let randIndex = 2 * randInt(4);
53 const bishop1Pos = positions[randIndex];
54 let randIndex_tmp = 2 * randInt(4) + 1;
55 const bishop2Pos = positions[randIndex_tmp];
56 positions.splice(Math.max(randIndex, randIndex_tmp), 1);
57 positions.splice(Math.min(randIndex, randIndex_tmp), 1);
58
59 randIndex = randInt(6);
60 const knight1Pos = positions[randIndex];
61 positions.splice(randIndex, 1);
62 randIndex = randInt(5);
63 const knight2Pos = positions[randIndex];
64 positions.splice(randIndex, 1);
65
66 randIndex = randInt(4);
67 const queenPos = positions[randIndex];
68 positions.splice(randIndex, 1);
69
70 const rook1Pos = positions[0];
71 const kingPos = positions[1];
72 const rook2Pos = positions[2];
73
74 pieces[c][rook1Pos] = "r";
75 pieces[c][knight1Pos] = "n";
76 pieces[c][bishop1Pos] = "b";
77 pieces[c][queenPos] = "q";
78 pieces[c][kingPos] = "k";
79 pieces[c][bishop2Pos] = "b";
80 pieces[c][knight2Pos] = "n";
81 pieces[c][rook2Pos] = "r";
82 if (c == 'b') pieces[c] = pieces[c].map(p => piecesMap[p]);
83 flags += V.CoordToColumn(rook1Pos) + V.CoordToColumn(rook2Pos);
84 }
85 // Add turn + flags + enpassant
86 return (
87 pieces["b"].join("") +
88 "/pppppppp/8/8/8/8/PPPPPPPP/" +
89 pieces["w"].join("").toUpperCase() +
90 " w 0 " + flags + " -"
91 );
92 }
93
94 static get C_ROOK() {
95 return 'd';
96 }
97 static get C_KNIGHT() {
98 return 'h';
99 }
100 static get C_BISHOP() {
101 return 'a';
102 }
103 static get C_QUEEN() {
104 return 's';
105 }
106
107 static get PIECES() {
108 return (
109 ChessRules.PIECES.concat([V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN])
110 );
111 }
112
113 getPotentialMovesFrom([x, y]) {
114 switch (this.getPiece(x, y)) {
115 case V.C_ROOK:
116 return this.getPotentialC_rookMoves([x, y]);
117 case V.C_KNIGHT:
118 return this.getPotentialC_knightMoves([x, y]);
119 case V.C_BISHOP:
120 return this.getPotentialC_bishopMoves([x, y]);
121 case V.C_QUEEN:
122 return this.getPotentialC_queenMoves([x, y]);
123 default:
124 return super.getPotentialMovesFrom([x, y]);
125 }
126 return [];
127 }
128
129 static get steps() {
130 return Object.assign(
131 {},
132 ChessRules.steps,
133 {
134 // Dabbabah
135 'd': [
136 [-2, 0],
137 [0, -2],
138 [2, 0],
139 [0, 2]
140 ],
141 // Alfil
142 'a': [
143 [2, 2],
144 [2, -2],
145 [-2, 2],
146 [-2, -2]
147 ],
148 // Ferz
149 'f': [
150 [1, 1],
151 [1, -1],
152 [-1, 1],
153 [-1, -1]
154 ]
155 }
156 );
157 }
158
159 getPotentialC_rookMoves(sq) {
160 return (
161 this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
162 this.getSlideNJumpMoves(sq, V.steps['d'], "oneStep"))
163 );
164 }
165
166 getPotentialC_knightMoves(sq) {
167 return (
168 this.getSlideNJumpMoves(sq, V.steps['a'], "oneStep").concat(
169 this.getSlideNJumpMoves(sq, V.steps[V.ROOK], "oneStep"))
170 );
171 }
172
173 getPotentialC_bishopMoves(sq) {
174 return (
175 this.getSlideNJumpMoves(sq, V.steps['d'], "oneStep").concat(
176 this.getSlideNJumpMoves(sq, V.steps['a'], "oneStep")).concat(
177 this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep"))
178 );
179 }
180
181 getPotentialC_queenMoves(sq) {
182 return (
183 this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
184 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"))
185 );
186 }
187
188 getCastleMoves([x, y]) {
189 const color = this.getColor(x, y);
190 const finalSquares = [
191 // Black castle long in an unusual way:
192 (color == 'w' ? [2, 3] : [1, 2]),
193 [V.size.y - 2, V.size.y - 3]
194 ];
195 return super.getCastleMoves([x, y], finalSquares);
196 }
197
198 isAttacked(sq, color) {
199 return (
200 super.isAttacked(sq, color) ||
201 this.isAttackedByC_rook(sq, color) ||
202 this.isAttackedByC_knight(sq, color) ||
203 this.isAttackedByC_bishop(sq, color) ||
204 this.isAttackedByC_queen(sq, color)
205 );
206 }
207
208 isAttackedByC_rook(sq, color) {
209 return (
210 this.isAttackedBySlideNJump(sq, color, V.C_ROOK, V.steps[V.BISHOP]) ||
211 this.isAttackedBySlideNJump(
212 sq, color, V.C_ROOK, V.steps['d'], "oneStep")
213 );
214 }
215
216 isAttackedByC_knight(sq, color) {
217 return (
218 this.isAttackedBySlideNJump(
219 sq, color, V.C_KNIGHT, V.steps[V.ROOK], "oneStep") ||
220 this.isAttackedBySlideNJump(
221 sq, color, V.C_KNIGHT, V.steps['a'], "oneStep")
222 );
223 }
224
225 isAttackedByC_bishop(sq, color) {
226 return (
227 this.isAttackedBySlideNJump(
228 sq, color, V.C_BISHOP, V.steps['d'], "oneStep") ||
229 this.isAttackedBySlideNJump(
230 sq, color, V.C_BISHOP, V.steps['a'], "oneStep") ||
231 this.isAttackedBySlideNJump(
232 sq, color, V.C_BISHOP, V.steps['f'], "oneStep")
233 );
234 }
235
236 isAttackedByC_queen(sq, color) {
237 return (
238 this.isAttackedBySlideNJump(sq, color, V.C_QUEEN, V.steps[V.BISHOP]) ||
239 this.isAttackedBySlideNJump(
240 sq, color, V.C_QUEEN, V.steps[V.KNIGHT], "oneStep")
241 );
242 }
243
244 static get VALUES() {
245 return Object.assign(
246 {},
247 ChessRules.VALUES,
248 {
249 d: 4,
250 h: 3,
251 a: 5,
252 s: 6
253 }
254 );
255 }
256
257 static get SEARCH_DEPTH() {
258 return 2;
259 }
260
261 };