Fix Align4, fix mushrooms effect for Chakart
[xogo.git] / variants / Chakart / class.js
CommitLineData
bc2bc396
BA
1import ChessRules from "/base_rules.js";
2import GiveawayRules from "/variants/Giveaway/class.js";
8f57fbf2
BA
3import { ArrayFun } from "/utils/array.js";
4import { Random } from "/utils/alea.js";
5import PiPo from "/utils/PiPo.js";
6import Move from "/utils/Move.js";
f382c57b 7
bc2bc396 8export default class ChakartRules extends ChessRules {
f8b43ef7
BA
9
10 static get Options() {
11 return {
12 select: [
13 {
14 label: "Randomness",
15 variable: "randomness",
16 defaut: 2,
17 options: [
37481d1e
BA
18 {label: "Deterministic", value: 0},
19 {label: "Symmetric random", value: 1},
20 {label: "Asymmetric random", value: 2}
f8b43ef7
BA
21 ]
22 }
3b641716
BA
23 ],
24 styles: ["cylinder"]
f8b43ef7
BA
25 };
26 }
27
8f57fbf2
BA
28 get pawnPromotions() {
29 return ['q', 'r', 'n', 'b', 'k'];
f8b43ef7 30 }
8f57fbf2 31
2b9b90da 32 get hasCastle() {
f8b43ef7
BA
33 return false;
34 }
2b9b90da 35 get hasEnpassant() {
f8b43ef7
BA
36 return false;
37 }
24872b22
BA
38 get hasReserve() {
39 return true;
40 }
41 get hasReserveFen() {
42 return false;
43 }
f8b43ef7 44
f8b43ef7
BA
45 static get IMMOBILIZE_CODE() {
46 return {
47 'p': 's',
48 'r': 'u',
49 'n': 'o',
50 'b': 'c',
51 'q': 't',
52 'k': 'l'
53 };
54 }
55
56 static get IMMOBILIZE_DECODE() {
57 return {
58 's': 'p',
59 'u': 'r',
60 'o': 'n',
61 'c': 'b',
62 't': 'q',
63 'l': 'k'
64 };
65 }
66
f8b43ef7
BA
67 // Fictive color 'a', bomb banana mushroom egg
68 static get BOMB() {
69 return 'w'; //"Wario"
70 }
71 static get BANANA() {
72 return 'd'; //"Donkey"
73 }
74 static get EGG() {
75 return 'e';
76 }
77 static get MUSHROOM() {
78 return 'm';
79 }
80
24872b22
BA
81 static get EGG_SURPRISE() {
82 return [
83 "kingboo", "bowser", "daisy", "koopa",
84 "luigi", "waluigi", "toadette", "chomp"];
85 }
86
3b641716
BA
87 canIplay(x, y) {
88 if (
89 this.playerColor != this.turn ||
90 Object.keys(V.IMMOBILIZE_DECODE).includes(this.getPiece(x, y))
91 ) {
92 return false;
93 }
94 return this.egg == "kingboo" || this.getColor(x, y) == this.turn;
95 }
96
24872b22 97 pieces(color, x, y) {
3b641716 98 const specials = {
24872b22 99 'i': {"class": "invisible"}, //queen
cc9fe4f1 100 '?': {"class": "mystery"}, //...initial square
24872b22
BA
101 'e': {"class": "egg"},
102 'm': {"class": "mushroom"},
103 'd': {"class": "banana"},
3b641716
BA
104 'w': {"class": "bomb"},
105 'z': {"class": "remote-capture"}
24872b22 106 };
3b641716
BA
107 const bowsered = {
108 's': {"class": ["immobilized", "pawn"]},
109 'u': {"class": ["immobilized", "rook"]},
110 'o': {"class": ["immobilized", "knight"]},
111 'c': {"class": ["immobilized", "bishop"]},
112 't': {"class": ["immobilized", "queen"]},
113 'l': {"class": ["immobilized", "king"]}
114 };
f5435757
BA
115 return Object.assign(
116 {
117 'y': {
118 // Virtual piece for "king remote shell captures"
119 moves: [],
120 attack: [
121 {
122 steps: [
123 [0, 1], [0, -1], [1, 0], [-1, 0],
124 [1, 1], [1, -1], [-1, 1], [-1, -1]
125 ]
126 }
127 ]
128 }
129 },
130 specials, bowsered, super.pieces(color, x, y));
24872b22
BA
131 }
132
91339921 133 genRandInitFen(seed) {
554e3ad3
BA
134 const options = Object.assign({mode: "suicide"}, this.options);
135 const gr = new GiveawayRules({options: options, genFenOnly: true});
fc12475f
BA
136 const baseFen = gr.genRandInitFen(seed);
137 const fenParts = baseFen.split(" ");
138 let others = JSON.parse(fenParts[3]);
139 delete others["enpassant"];
140 others["flags"] = "1111"; //Peach + Mario flags
141 return fenParts.slice(0, 3).join(" ") + " " + JSON.stringify(others);
91339921
BA
142 }
143
8f57fbf2 144 fen2board(f) {
f8b43ef7
BA
145 return (
146 f.charCodeAt() <= 90
147 ? "w" + f.toLowerCase()
148 : (['w', 'd', 'e', 'm'].includes(f) ? "a" : "b") + f
149 );
150 }
151
f8b43ef7
BA
152 setFlags(fenflags) {
153 // King can send shell? Queen can be invisible?
154 this.powerFlags = {
8f57fbf2
BA
155 w: {k: false, q: false},
156 b: {k: false, q: false}
f8b43ef7 157 };
8f57fbf2 158 for (let c of ['w', 'b']) {
f8b43ef7
BA
159 for (let p of ['k', 'q']) {
160 this.powerFlags[c][p] =
161 fenflags.charAt((c == "w" ? 0 : 2) + (p == 'k' ? 0 : 1)) == "1";
162 }
163 }
164 }
165
166 aggregateFlags() {
167 return this.powerFlags;
168 }
169
170 disaggregateFlags(flags) {
171 this.powerFlags = flags;
172 }
173
91339921
BA
174 getFlagsFen() {
175 return ['w', 'b'].map(c => {
176 return ['k', 'q'].map(p => this.powerFlags[c][p] ? "1" : "0").join("");
177 }).join("");
178 }
179
8f57fbf2 180 setOtherVariables(fenParsed) {
24872b22
BA
181 this.setFlags(fenParsed.flags);
182 this.reserve = {}; //to be filled later
bc2bc396 183 this.egg = null;
24872b22 184 this.moveStack = [];
3b641716
BA
185 // Change seed (after FEN generation!!)
186 // so that further calls differ between players:
554e3ad3 187 Random.setSeed(Math.floor(19840 * Math.random()));
f8b43ef7
BA
188 }
189
c7c2f41c 190 // For Toadette bonus
91339921 191 getDropMovesFrom([c, p]) {
be3cb9d1 192 if (typeof c != "string" || this.reserve[c][p] == 0)
c7c2f41c 193 return [];
f8b43ef7 194 let moves = [];
91339921 195 const start = (c == 'w' && p == 'p' ? 1 : 0);
3b641716 196 const end = (c == 'b' && p == 'p' ? 7 : 8);
f8b43ef7 197 for (let i = start; i < end; i++) {
91339921
BA
198 for (let j = 0; j < this.size.y; j++) {
199 const pieceIJ = this.getPiece(i, j);
3b641716 200 const colIJ = this.getColor(i, j);
cc9fe4f1 201 if (this.board[i][j] == "" || colIJ == 'a' || pieceIJ == 'i') {
91339921
BA
202 let m = new Move({
203 start: {x: c, y: p},
91339921
BA
204 appear: [new PiPo({x: i, y: j, c: c, p: p})],
205 vanish: []
206 });
207 // A drop move may remove a bonus (or hidden queen!)
208 if (this.board[i][j] != "")
3b641716 209 m.vanish.push(new PiPo({x: i, y: j, c: colIJ, p: pieceIJ}));
f8b43ef7
BA
210 moves.push(m);
211 }
212 }
213 }
214 return moves;
215 }
216
bc2bc396 217 getPotentialMovesFrom([x, y]) {
f8b43ef7 218 let moves = [];
3b641716 219 const piece = this.getPiece(x, y);
bc2bc396 220 if (this.egg == "toadette")
24872b22
BA
221 moves = this.getDropMovesFrom([x, y]);
222 else if (this.egg == "kingboo") {
3b641716 223 const color = this.turn;
37481d1e 224 const oppCol = C.GetOppCol(color);
3b641716 225 // Only allow to swap (non-immobilized!) pieces
37481d1e
BA
226 for (let i=0; i<this.size.x; i++) {
227 for (let j=0; j<this.size.y; j++) {
bc2bc396
BA
228 const colIJ = this.getColor(i, j);
229 const pieceIJ = this.getPiece(i, j);
230 if (
231 (i != x || j != y) &&
232 ['w', 'b'].includes(colIJ) &&
3b641716 233 !Object.keys(V.IMMOBILIZE_DECODE).includes(pieceIJ) &&
bc2bc396
BA
234 // Next conditions = no pawn on last rank
235 (
3b641716 236 piece != 'p' ||
bc2bc396
BA
237 (
238 (color != 'w' || i != 0) &&
239 (color != 'b' || i != this.size.x - 1)
240 )
241 )
242 &&
243 (
244 pieceIJ != 'p' ||
245 (
246 (colIJ != 'w' || x != 0) &&
247 (colIJ != 'b' || x != this.size.x - 1)
248 )
249 )
250 ) {
37481d1e 251 let m = this.getBasicMove([x, y], [i, j]);
3b641716
BA
252 m.appear.push(new PiPo({x: x, y: y, p: pieceIJ, c: colIJ}));
253 m.kingboo = true; //avoid some side effects (bananas/bombs)
37481d1e
BA
254 moves.push(m);
255 }
256 }
257 }
be3cb9d1 258 }
24872b22
BA
259 else {
260 // Normal case (including bonus daisy)
24872b22
BA
261 switch (piece) {
262 case 'p':
263 moves = this.getPawnMovesFrom([x, y]); //apply promotions
264 break;
265 case 'q':
266 moves = this.getQueenMovesFrom([x, y]);
267 break;
268 case 'k':
269 moves = this.getKingMovesFrom([x, y]);
270 break;
271 case 'n':
272 moves = this.getKnightMovesFrom([x, y]);
273 break;
274 case 'b':
275 case 'r':
3b641716 276 // Explicitely listing types to avoid moving immobilized piece
f5435757 277 moves = this.getPotentialMovesOf(piece, [x, y]);
24872b22
BA
278 break;
279 }
280 }
24872b22
BA
281 return moves;
282 }
283
3b641716
BA
284 canStepOver(i, j) {
285 return (
286 this.board[i][j] == "" ||
cc9fe4f1
BA
287 ['i', V.EGG, V.MUSHROOM].includes(this.getPiece(i, j))
288 );
b0cf998b
BA
289 }
290
37481d1e 291 getPawnMovesFrom([x, y]) {
f8b43ef7 292 const color = this.turn;
be3cb9d1
BA
293 const oppCol = C.GetOppCol(color);
294 const shiftX = (color == 'w' ? -1 : 1);
295 const firstRank = (color == "w" ? this.size.x - 1 : 0);
f8b43ef7 296 let moves = [];
cc9fe4f1 297 const frontPiece = this.getPiece(x + shiftX, y);
f8b43ef7 298 if (
be3cb9d1 299 this.board[x + shiftX][y] == "" ||
f8b43ef7 300 this.getColor(x + shiftX, y) == 'a' ||
cc9fe4f1 301 frontPiece == 'i'
f8b43ef7 302 ) {
7562d2c2 303 moves.push(this.getBasicMove([x, y], [x + shiftX, y]));
f8b43ef7
BA
304 if (
305 [firstRank, firstRank + shiftX].includes(x) &&
cc9fe4f1 306 ![V.BANANA, V.BOMB].includes(frontPiece) &&
f8b43ef7 307 (
7562d2c2 308 this.board[x + 2 * shiftX][y] == "" ||
f8b43ef7 309 this.getColor(x + 2 * shiftX, y) == 'a' ||
cc9fe4f1 310 this.getPiece(x + 2 * shiftX, y) == 'i'
f8b43ef7
BA
311 )
312 ) {
7562d2c2 313 moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
f8b43ef7
BA
314 }
315 }
316 for (let shiftY of [-1, 1]) {
f5435757 317 const nextY = this.getY(y + shiftY);
f8b43ef7 318 if (
f5435757
BA
319 nextY >= 0 &&
320 nextY < this.size.y &&
321 this.board[x + shiftX][nextY] != "" &&
f8b43ef7 322 // Pawns cannot capture invisible queen this way!
f5435757
BA
323 this.getPiece(x + shiftX, nextY) != 'i' &&
324 ['a', oppCol].includes(this.getColor(x + shiftX, nextY))
f8b43ef7 325 ) {
f5435757 326 moves.push(this.getBasicMove([x, y], [x + shiftX, nextY]));
f8b43ef7
BA
327 }
328 }
f5435757
BA
329 this.pawnPostProcess(moves, color, oppCol);
330 // Add mushroom on before-last square (+ potential segments)
24872b22 331 moves.forEach(m => {
f5435757
BA
332 let [mx, my] = [x, y];
333 if (Math.abs(m.end.x - m.start.x) == 2)
334 mx = (m.start.x + m.end.x) / 2;
335 m.appear.push(new PiPo({x: mx, y: my, c: 'a', p: 'm'}));
336 if (mx != x && this.board[mx][my] != "") {
3b641716 337 m.vanish.push(new PiPo({
f5435757
BA
338 x: mx,
339 y: my,
340 c: this.getColor(mx, my),
341 p: this.getPiece(mx, my)
3b641716 342 }));
24872b22 343 }
f5435757
BA
344 if (Math.abs(m.end.y - m.start.y) > 1) {
345 m.segments = [
346 [[x, y], [x, y]],
347 [[m.end.x, m.end.y], [m.end.x, m.end.y]]
348 ];
349 }
24872b22 350 });
3b641716 351 return moves;
24872b22
BA
352 }
353
354 getKnightMovesFrom([x, y]) {
355 // Add egg on initial square:
356 return this.getPotentialMovesOf('n', [x, y]).map(m => {
357 m.appear.push(new PiPo({p: "e", c: "a", x: x, y: y}));
358 return m;
359 });
360 }
361
37481d1e 362 getQueenMovesFrom(sq) {
24872b22 363 const normalMoves = this.getPotentialMovesOf('q', sq);
f8b43ef7
BA
364 // If flag allows it, add 'invisible movements'
365 let invisibleMoves = [];
7562d2c2 366 if (this.powerFlags[this.turn]['q']) {
f8b43ef7
BA
367 normalMoves.forEach(m => {
368 if (
369 m.appear.length == 1 &&
370 m.vanish.length == 1 &&
371 // Only simple non-capturing moves:
372 m.vanish[0].c != 'a'
373 ) {
374 let im = JSON.parse(JSON.stringify(m));
cc9fe4f1 375 im.appear[0].p = 'i';
24872b22 376 im.noAnimate = true;
f8b43ef7
BA
377 invisibleMoves.push(im);
378 }
379 });
380 }
381 return normalMoves.concat(invisibleMoves);
382 }
383
37481d1e 384 getKingMovesFrom([x, y]) {
24872b22 385 let moves = this.getPotentialMovesOf('k', [x, y]);
f8b43ef7 386 // If flag allows it, add 'remote shell captures'
7562d2c2 387 if (this.powerFlags[this.turn]['k']) {
f5435757
BA
388 let shellCaptures = this.getPotentialMovesOf('y', [x, y]);
389 shellCaptures.forEach(sc => {
390 sc.shell = true; //easier play()
391 sc.choice = 'z'; //to display in showChoices()
392 // Fix move (Rifle style):
393 sc.vanish.shift();
394 sc.appear.shift();
f8b43ef7 395 });
f5435757 396 Array.prototype.push.apply(moves, shellCaptures);
f8b43ef7
BA
397 }
398 return moves;
399 }
400
7562d2c2 401 play(move) {
a2bb7e06
BA
402 const color = this.turn;
403 const oppCol = C.GetOppCol(color);
404 if (
405 move.appear.length > 0 &&
406 move.appear[0].p == 'p' &&
407 (
408 (color == 'w' && move.end.x == 0) ||
409 (color == 'b' && move.end.x == this.size.x - 1)
410 )
411 ) {
412 // "Forgotten" promotion, which occurred after some effect
413 let moves = [move];
414 super.pawnPostProcess(moves, color, oppCol);
415 super.showChoices(moves);
416 return false;
417 }
3b641716
BA
418 if (!move.nextComputed) {
419 // Set potential random effects, so that play() is deterministic
420 // from opponent viewpoint:
421 const endPiece = this.getPiece(move.end.x, move.end.y);
422 switch (endPiece) {
423 case V.EGG:
424 move.egg = Random.sample(V.EGG_SURPRISE);
425 move.next = this.getEggEffect(move);
426 break;
427 case V.MUSHROOM:
428 move.next = this.getMushroomEffect(move);
429 break;
430 case V.BANANA:
431 case V.BOMB:
432 move.next = this.getBombBananaEffect(move, endPiece);
433 break;
434 }
435 if (!move.next && move.appear.length > 0 && !move.kingboo) {
436 const movingPiece = move.appear[0].p;
437 if (['b', 'r'].includes(movingPiece)) {
438 // Drop a banana or bomb:
439 const bs =
440 this.getRandomSquare([move.end.x, move.end.y],
441 movingPiece == 'r'
442 ? [[1, 1], [1, -1], [-1, 1], [-1, -1]]
443 : [[1, 0], [-1, 0], [0, 1], [0, -1]],
444 "freeSquare");
445 if (bs) {
446 move.appear.push(
447 new PiPo({
448 x: bs[0],
449 y: bs[1],
450 c: 'a',
451 p: movingPiece == 'r' ? 'd' : 'w'
452 })
453 );
454 if (this.board[bs[0]][bs[1]] != "") {
455 move.vanish.push(
456 new PiPo({
457 x: bs[0],
458 y: bs[1],
459 c: this.getColor(bs[0], bs[1]),
460 p: this.getPiece(bs[0], bs[1])
461 })
462 );
463 }
464 }
465 }
466 }
467 move.nextComputed = true;
468 }
24872b22 469 this.egg = move.egg;
24872b22
BA
470 if (move.egg == "toadette") {
471 this.reserve = { w: {}, b: {} };
472 // Randomly select a piece in pawnPromotions
3b641716
BA
473 if (!move.toadette)
474 move.toadette = Random.sample(this.pawnPromotions);
475 this.reserve[color][move.toadette] = 1;
24872b22 476 this.re_drawReserve([color]);
f8b43ef7 477 }
24872b22
BA
478 else if (Object.keys(this.reserve).length > 0) {
479 this.reserve = {};
480 this.re_drawReserve([color]);
f8b43ef7 481 }
24872b22
BA
482 if (move.shell)
483 this.powerFlags[color]['k'] = false;
cc9fe4f1 484 else if (move.appear.length > 0 && move.appear[0].p == 'i') {
24872b22 485 this.powerFlags[move.appear[0].c]['q'] = false;
cc9fe4f1
BA
486 if (color == this.playerColor) {
487 move.appear.push(
488 new PiPo({x: move.start.x, y: move.start.y, c: color, p: '?'}));
489 }
3b641716
BA
490 }
491 if (color == this.playerColor) {
492 // Look for an immobilized piece of my color: it can now move
493 for (let i=0; i<8; i++) {
494 for (let j=0; j<8; j++) {
495 if ((i != move.end.x || j != move.end.y) && this.board[i][j] != "") {
496 const piece = this.getPiece(i, j);
497 if (
498 this.getColor(i, j) == color &&
499 Object.keys(V.IMMOBILIZE_DECODE).includes(piece)
500 ) {
501 move.vanish.push(new PiPo({
502 x: i, y: j, c: color, p: piece
503 }));
504 move.appear.push(new PiPo({
505 x: i, y: j, c: color, p: V.IMMOBILIZE_DECODE[piece]
506 }));
507 }
f8b43ef7
BA
508 }
509 }
510 }
3b641716
BA
511 // Also make opponent invisible queen visible again, if any
512 for (let i=0; i<8; i++) {
513 for (let j=0; j<8; j++) {
514 if (
515 this.board[i][j] != "" &&
cc9fe4f1 516 this.getColor(i, j) == oppCol
3b641716 517 ) {
cc9fe4f1
BA
518 const pieceIJ = this.getPiece(i, j);
519 if (pieceIJ == 'i') {
520 move.vanish.push(new PiPo({x: i, y: j, c: oppCol, p: 'i'}));
521 move.appear.push(new PiPo({x: i, y: j, c: oppCol, p: 'q'}));
522 }
523 else if (pieceIJ == '?')
524 move.vanish.push(new PiPo({x: i, y: j, c: oppCol, p: '?'}));
3b641716 525 }
f8b43ef7
BA
526 }
527 }
528 }
24872b22
BA
529 if (!move.next && !["daisy", "toadette", "kingboo"].includes(move.egg)) {
530 this.turn = oppCol;
91339921 531 this.movesCount++;
f8b43ef7 532 }
bc2bc396 533 if (move.egg)
cc9fe4f1 534 this.displayBonus(move);
3b641716 535 this.playOnBoard(move);
24872b22 536 this.nextMove = move.next;
a2bb7e06 537 return true;
bc2bc396
BA
538 }
539
3b641716
BA
540 // Helper to set and apply banana/bomb effect
541 getRandomSquare([x, y], steps, freeSquare) {
542 let validSteps = steps.filter(s => this.onBoard(x + s[0], y + s[1]));
543 if (freeSquare) {
544 // Square to put banana/bomb cannot be occupied by a piece
545 validSteps = validSteps.filter(s => {
546 return ["", 'a'].includes(this.getColor(x + s[0], y + s[1]))
547 });
548 }
549 if (validSteps.length == 0)
550 return null;
551 const step = validSteps[Random.randInt(validSteps.length)];
552 return [x + step[0], y + step[1]];
f8b43ef7
BA
553 }
554
3b641716
BA
555 getEggEffect(move) {
556 const getRandomPiece = (c) => {
557 let bagOfPieces = [];
558 for (let i=0; i<this.size.x; i++) {
559 for (let j=0; j<this.size.y; j++) {
560 if (this.getColor(i, j) == c && this.getPiece(i, j) != 'k')
561 bagOfPieces.push([i, j]);
562 }
563 }
564 if (bagOfPieces.length >= 1)
565 return Random.sample(bagOfPieces);
566 return null;
567 };
568 const color = this.turn;
569 let em = null;
570 switch (move.egg) {
571 case "luigi":
572 case "waluigi":
573 // Change color of friendly or enemy piece, king excepted
574 const oldColor = (move.egg == "waluigi" ? color : C.GetOppCol(color));
575 const newColor = C.GetOppCol(oldColor);
576 const coords = getRandomPiece(oldColor);
577 if (coords) {
578 const piece = this.getPiece(coords[0], coords[1]);
579 em = new Move({
580 appear: [
581 new PiPo({x: coords[0], y: coords[1], c: newColor, p: piece})
582 ],
583 vanish: [
584 new PiPo({x: coords[0], y: coords[1], c: oldColor, p: piece})
585 ]
586 });
587 }
588 break;
589 case "bowser":
590 em = new Move({
591 appear: [
592 new PiPo({
593 x: move.end.x,
594 y: move.end.y,
595 c: color,
596 p: V.IMMOBILIZE_CODE[move.appear[0].p]
597 })
598 ],
599 vanish: [
600 new PiPo({
601 x: move.end.x,
602 y: move.end.y,
603 c: color,
604 p: move.appear[0].p
605 })
606 ]
607 });
608 break;
609 case "koopa":
610 // Reverse move
611 em = new Move({
612 appear: [
613 new PiPo({
614 x: move.start.x, y: move.start.y, c: color, p: move.appear[0].p
615 })
616 ],
617 vanish: [
618 new PiPo({
619 x: move.end.x, y: move.end.y, c: color, p: move.appear[0].p
620 })
621 ]
622 });
623 if (this.board[move.start.x][move.start.y] != "") {
624 // Pawn or knight let something on init square
625 em.vanish.push(new PiPo({
626 x: move.start.x,
627 y: move.start.y,
628 c: 'a',
629 p: this.getPiece(move.start.x, move.start.y)
630 }));
631 }
632 break;
633 case "chomp":
634 // Eat piece
635 em = new Move({
636 appear: [],
637 vanish: [
638 new PiPo({
639 x: move.end.x, y: move.end.y, c: color, p: move.appear[0].p
640 })
641 ],
642 end: {x: move.end.x, y: move.end.y}
643 });
644 break;
645 }
646 if (em && move.egg != "koopa")
647 em.noAnimate = true; //static move
648 return em;
f8b43ef7
BA
649 }
650
24872b22 651 getMushroomEffect(move) {
fc12475f
BA
652 if (
653 typeof move.start.x == "string" || //drop move (toadette)
654 ['b', 'r', 'q'].includes(move.vanish[0].p) //slider
655 ) {
cc9fe4f1 656 return null;
37481d1e 657 }
fc12475f
BA
658 let step = [move.end.x - move.start.x, move.end.y - move.start.y];
659 if (Math.abs(step[0]) == 2 && Math.abs(step[1]) == 0)
660 // Pawn initial 2-squares move: normalize step
661 step[0] /= 2;
24872b22 662 const nextSquare = [move.end.x + step[0], move.end.y + step[1]];
24872b22 663 let nextMove = null;
fc12475f
BA
664 if (
665 this.onBoard(nextSquare[0], nextSquare[1]) &&
666 (
667 this.board[nextSquare[0]][nextSquare[1]] == "" ||
668 this.getColor(nextSquare[0], nextSquare[1]) == 'a'
669 )
670 ) {
bc5d61a7 671 this.playOnBoard(move); //HACK for getBasicMove()
24872b22 672 nextMove = this.getBasicMove([move.end.x, move.end.y], nextSquare);
bc5d61a7 673 this.undoOnBoard(move);
24872b22 674 }
24872b22 675 return nextMove;
37481d1e
BA
676 }
677
3b641716
BA
678 getBombBananaEffect(move, item) {
679 const steps = item == V.BANANA
680 ? [[1, 0], [-1, 0], [0, 1], [0, -1]]
681 : [[1, 1], [1, -1], [-1, 1], [-1, -1]];
682 const nextSquare = this.getRandomSquare([move.end.x, move.end.y], steps);
683 this.playOnBoard(move); //HACK for getBasicMove()
684 const res = this.getBasicMove([move.end.x, move.end.y], nextSquare);
685 this.undoOnBoard(move);
686 return res;
687 }
688
cc9fe4f1
BA
689 displayBonus(move) {
690 let divBonus = document.createElement("div");
691 divBonus.classList.add("bonus-text");
692 divBonus.innerHTML = move.egg;
693 let container = document.getElementById(this.containerId);
694 container.appendChild(divBonus);
695 setTimeout(() => container.removeChild(divBonus), 2000);
3b641716
BA
696 }
697
698 atLeastOneMove() {
699 return true;
700 }
701
702 filterValid(moves) {
703 return moves;
704 }
705
be3cb9d1 706 playPlusVisual(move, r) {
3b641716 707 const nextLines = () => {
a2bb7e06
BA
708 if (!this.play(move))
709 return;
710 this.moveStack.push(move);
3b641716
BA
711 this.playVisual(move, r);
712 if (this.nextMove)
713 this.playPlusVisual(this.nextMove, r);
714 else {
715 this.afterPlay(this.moveStack);
716 this.moveStack = [];
717 }
718 };
a2bb7e06 719 if (this.moveStack.length == 0)
3b641716 720 nextLines();
24872b22 721 else
3b641716 722 this.animate(move, nextLines);
be3cb9d1 723 }
f8b43ef7
BA
724
725};