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