Fix complete rules of Cwda
[xogo.git] / variants / Cwda / class.js
1 import ChessRules from "/base_rules.js";
2 import {FenUtil} from "/utils/setupPieces.js"
3
4 export default class CwdaRules extends ChessRules {
5
6 static get Options() {
7 return {
8 select: ChessRules.Options.select.concat([
9 {
10 label: "Army 1",
11 variable: "army1",
12 defaut: 'C',
13 options: [
14 { label: "Colorbound Clobberers", value: 'C' },
15 { label: "Nutty Knights", value: 'N' },
16 { label: "Remarkable Rookies", value: 'R' },
17 { label: "Fide", value: 'F' }
18 ]
19 },
20 {
21 label: "Army 2",
22 variable: "army2",
23 defaut: 'C',
24 options: [
25 { label: "Colorbound Clobberers", value: 'C' },
26 { label: "Nutty Knights", value: 'N' },
27 { label: "Remarkable Rookies", value: 'R' },
28 { label: "Fide", value: 'F' }
29 ]
30 }
31 ]),
32 input: ChessRules.Options.input,
33 styles: ChessRules.Options.styles
34 };
35 }
36
37 static get PiecesMap() {
38 return {
39 // Colorbound Clobberers
40 'C': {
41 'r': 'd',
42 'n': 'w',
43 'b': 'f',
44 'q': 'c',
45 'k': 'm',
46 'p': 'z'
47 },
48 // Nutty Knights
49 'N': {
50 'r': 'g',
51 'n': 'i',
52 'b': 't',
53 'q': 'l',
54 'k': 'e',
55 'p': 'v'
56 },
57 // Remarkable Rookies
58 'R': {
59 'r': 's',
60 'n': 'y',
61 'b': 'h',
62 'q': 'o',
63 'k': 'a',
64 'p': 'u'
65 }
66 };
67 }
68
69 genRandInitBaseFen() {
70 let s = FenUtil.setupPieces(
71 ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
72 {
73 randomness: this.options["randomness"],
74 between: [{p1: 'k', p2: 'r'}],
75 diffCol: ['b'],
76 flags: ['r']
77 }
78 );
79 let pawnLines = {
80 w: Array(8).fill('p'),
81 b: Array(8).fill('p')
82 };
83 for (const c of ['w', 'b']) {
84 const army = "army" + (c == 'w' ? "1" : "2");
85 if (this.options[army] != 'F') {
86 for (let obj of [s, pawnLines])
87 obj[c] = obj[c].map(p => V.PiecesMap[this.options[army]][p]);
88 }
89 }
90 return {
91 fen: s.b.join("") + "/" +
92 pawnLines['b'].join("") +
93 "/8/8/8/8/" +
94 pawnLines['w'].join("").toUpperCase() +
95 "/" + s.w.join("").toUpperCase(),
96 o: {flags: s.flags}
97 };
98 }
99
100 getPartFen(o) {
101 return Object.assign(
102 { "armies": this.options["army1"] + this.options["army2"] },
103 super.getPartFen(o)
104 );
105 }
106
107 setOtherVariables(fenParsed) {
108 super.setOtherVariables(fenParsed);
109 this.options["army1"] = fenParsed.armies.charAt(0);
110 this.options["army2"] = fenParsed.armies.charAt(1);
111 }
112
113 isKing(x, y, p) {
114 if (!p)
115 p = this.getPiece(x, y);
116 return (super.isKing(x, y, p) || ['a', 'e', 'm'].includes(p));
117 }
118
119 // Helper to describe pieces movements
120 static get steps() {
121 return {
122 // Dabbabah
123 'd': [
124 [-2, 0],
125 [0, -2],
126 [2, 0],
127 [0, 2]
128 ],
129 // Alfil
130 'a': [
131 [2, 2],
132 [2, -2],
133 [-2, 2],
134 [-2, -2]
135 ],
136 // Ferz
137 'f': [
138 [1, 1],
139 [1, -1],
140 [-1, 1],
141 [-1, -1]
142 ],
143 // Wazir
144 'w': [
145 [-1, 0],
146 [0, -1],
147 [1, 0],
148 [0, 1]
149 ],
150 // Threeleaper
151 '$3': [
152 [-3, 0],
153 [0, -3],
154 [3, 0],
155 [0, 3]
156 ],
157 // Narrow knight
158 '$n': [
159 [-2, -1],
160 [-2, 1],
161 [2, -1],
162 [2, 1]
163 ]
164 };
165 }
166
167 pieces(color, x, y) {
168 const res = super.pieces(color, x, y);
169 const backward = (color == 'w' ? 1 : -1);
170 const forward = -backward;
171 return Object.assign(
172 {
173 'd': {
174 "class": "c_rook",
175 both: [
176 {steps: res['b'].both[0].steps},
177 {steps: V.steps.d, range: 1}
178 ]
179 },
180 'w': {
181 "class": "c_knight",
182 both: [
183 {steps: V.steps.a, range: 1},
184 {steps: res['r'].both[0].steps, range: 1}
185 ]
186 },
187 'f': {
188 "class": "c_bishop",
189 both: [
190 {steps: V.steps.d, range: 1},
191 {steps: V.steps.a, range: 1},
192 {steps: res['b'].both[0].steps, range: 1}
193 ]
194 },
195 'c': {
196 "class": "c_queen",
197 both: [
198 {steps: res['b'].both[0].steps},
199 {steps: res['n'].both[0].steps, range: 1}
200 ]
201 },
202 'm': { "class": "c_king", moveas: 'k' },
203 'z': { "class": "c_pawn", moveas: 'p' },
204 'g': {
205 "class": "n_rook",
206 both: [
207 {steps: [[0, -1], [0, 1], [color == 'w' ? -1 : 1, 0]]},
208 {steps: [[backward, -1], [backward, 0], [backward, 1]], range: 1}
209 ]
210 },
211 'i': {
212 "class": "n_knight",
213 both: [
214 {steps: V.steps.$n, range: 1},
215 {steps: V.steps.f, range: 1}
216 ]
217 },
218 't': {
219 "class": "n_bishop",
220 both: [
221 {
222 steps: [[0, -1], [0, 1], [backward, -1],
223 [backward, 0], [backward, 1]],
224 range: 1
225 },
226 {
227 steps: [[2*forward, -1], [2*forward, 1],
228 [forward, -2], [forward, 2]],
229 range: 1
230 }
231 ]
232 },
233 'l': {
234 "class": "n_queen",
235 both: [
236 {steps: [[0, -1], [0, 1], [forward, 0]]},
237 {steps: [[forward, -1], [forward, 1],
238 [backward, -1], [backward, 0], [backward, 1]], range: 1},
239 {steps: [[2*forward, -1], [2*forward, 1],
240 [forward, -2], [forward, 2]], range: 1}
241 ]
242 },
243 'e': { "class": "n_king", moveas: 'k' },
244 'v': { "class": "n_pawn", moveas: 'p' },
245 's': {
246 "class": "r_rook",
247 both: [{steps: res['r'].both[0].steps, range: 4}]
248 },
249 'y': {
250 "class": "r_knight",
251 both: [
252 {steps: V.steps.d, range: 1},
253 {steps: V.steps.w, range: 1}
254 ]
255 },
256 'h': {
257 "class": "r_bishop",
258 both: [
259 {steps: V.steps.d, range: 1},
260 {steps: V.steps.f, range: 1},
261 {steps: V.steps.$3, range: 1}
262 ]
263 },
264 'o': {
265 "class": "r_queen",
266 both: [
267 {steps: res['r'].both[0].steps},
268 {steps: res['n'].both[0].steps, range: 1}
269 ]
270 },
271 'a': { "class": "r_king", moveas: 'k' },
272 'u': { "class": "r_pawn", moveas: 'p' }
273 },
274 res
275 );
276 }
277
278 get pawnPromotions() {
279 // Can promote in anything from the two current armies
280 let promotions = [];
281 for (let army of ["army1", "army2"]) {
282 if (army == "army2" && this.options["army2"] == this.options["army1"])
283 break;
284 switch (this.options[army]) {
285 case 'C':
286 Array.prototype.push.apply(promotions, ['d', 'w', 'f', 'c']);
287 break;
288 case 'N':
289 Array.prototype.push.apply(promotions, ['g', 'i', 't', 'l']);
290 break;
291 case 'R':
292 Array.prototype.push.apply(promotions, ['s', 'y', 'h', 'o']);
293 break;
294 case 'F':
295 Array.prototype.push.apply(promotions, ['r', 'n', 'b', 'q']);
296 break;
297 }
298 }
299 return promotions;
300 }
301
302 getCastleMoves([x, y]) {
303 const color = this.getColor(x, y);
304 let finalSquares = [ [2, 3], [this.size.y - 2, this.size.y - 3] ];
305 if (
306 (color == 'w' && this.options["army1"] == 'C') ||
307 (color == 'b' && this.options["army2"] == 'C')
308 ) {
309 // Colorbound castle long in an unusual way:
310 finalSquares[0] = [1, 2];
311 }
312 return super.getCastleMoves([x, y], finalSquares);
313 }
314
315 };