1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
2 import { SuicideRules
} from "@/variants/Suicide";
3 import { randInt
} from "@/utils/alea";
5 export class ChakartRules
extends ChessRules
{
6 static get PawnSpecs() {
7 return SuicideRules
.PawnSpecs
;
10 static get HasCastle() {
14 static get CorrConfirm() {
15 // Because of bonus effects
19 static get CanAnalyze() {
23 hoverHighlight(x
, y
) {
24 if (this.subTurn
== 1) return false;
25 const L
= this.firstMove
.length
;
26 const fm
= this.firstMove
[L
-1];
27 if (fm
.end
.effect
!= 0) return false;
28 const deltaX
= Math
.abs(fm
.end
.x
- x
);
29 const deltaY
= Math
.abs(fm
.end
.y
- y
);
31 (deltaX
== 0 && deltaY
== 0) ||
33 this.board
[x
][y
] == V
.EMPTY
&&
35 (fm
.vanish
[0].p
== V
.ROOK
&& deltaX
== 1 && deltaY
== 1) ||
36 (fm
.vanish
[0].p
== V
.BISHOP
&& deltaX
+ deltaY
== 1)
42 static get IMMOBILIZE_CODE() {
53 static get IMMOBILIZE_DECODE() {
64 static get INVISIBLE_QUEEN() {
68 // Fictive color 'a', bomb banana mushroom egg
70 // Doesn't collide with bishop because color is 'a'
79 static get MUSHROOM() {
85 ChessRules
.PIECES
.concat(
86 Object
.keys(V
.IMMOBILIZE_DECODE
)).concat(
87 [V
.BANANA
, V
.BOMB
, V
.EGG
, V
.MUSHROOM
, V
.INVISIBLE_QUEEN
])
95 b
[1] == V
.INVISIBLE_QUEEN
||
96 Object
.keys(V
.IMMOBILIZE_DECODE
).includes(b
[1])
103 static ParseFen(fen
) {
104 const fenParts
= fen
.split(" ");
105 return Object
.assign(
106 ChessRules
.ParseFen(fen
),
107 { captured: fenParts
[5] }
111 // King can be l or L (immobilized) --> similar to Alice variant
112 static IsGoodPosition(position
) {
113 if (position
.length
== 0) return false;
114 const rows
= position
.split("/");
115 if (rows
.length
!= V
.size
.x
) return false;
116 let kings
= { "k": 0, "K": 0, 'l': 0, 'L': 0 };
117 for (let row
of rows
) {
119 for (let i
= 0; i
< row
.length
; i
++) {
120 if (['K','k','L','l'].includes(row
[i
])) kings
[row
[i
]]++;
121 if (V
.PIECES
.includes(row
[i
].toLowerCase())) sumElts
++;
123 const num
= parseInt(row
[i
]);
124 if (isNaN(num
)) return false;
128 if (sumElts
!= V
.size
.y
) return false;
130 if (kings
['k'] + kings
['l'] != 1 || kings
['K'] + kings
['L'] != 1)
135 static IsGoodFlags(flags
) {
136 // 4 for Peach + Mario w, b
137 return !!flags
.match(/^[01]{4,4}$/);
141 // King can send shell? Queen can be invisible?
143 w: [{ 'k': false, 'q': false }],
144 b: [{ 'k': false, 'q': false }]
146 for (let c
of ["w", "b"]) {
147 for (let p
of ['k', 'q']) {
148 this.powerFlags
[c
][p
] =
149 fenflags
.charAt((c
== "w" ? 0 : 2) + (p
== 'k' ? 0 : 1)) == "1";
155 return this.powerFlags
;
158 disaggregateFlags(flags
) {
159 this.powerFlags
= flags
;
163 return super.getFen() + " " + this.getCapturedFen();
167 return super.getFenForRepeat() + "_" + this.getCapturedFen();
171 let counts
= [...Array(10).fill(0)];
173 for (let p
of [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
, V
.PAWN
]) {
174 counts
[i
] = this.captured
["w"][p
];
175 counts
[5 + i
] = this.captured
["b"][p
];
178 return counts
.join("");
183 setOtherVariables(fen
) {
184 super.setOtherVariables(fen
);
185 const fenParsed
= V
.ParseFen(fen
);
186 // Initialize captured pieces' counts from FEN
189 [V
.ROOK
]: parseInt(fenParsed
.captured
[0]),
190 [V
.KNIGHT
]: parseInt(fenParsed
.captured
[1]),
191 [V
.BISHOP
]: parseInt(fenParsed
.captured
[2]),
192 [V
.QUEEN
]: parseInt(fenParsed
.captured
[3]),
193 [V
.PAWN
]: parseInt(fenParsed
.captured
[4]),
196 [V
.ROOK
]: parseInt(fenParsed
.captured
[5]),
197 [V
.KNIGHT
]: parseInt(fenParsed
.captured
[6]),
198 [V
.BISHOP
]: parseInt(fenParsed
.captured
[7]),
199 [V
.QUEEN
]: parseInt(fenParsed
.captured
[8]),
200 [V
.PAWN
]: parseInt(fenParsed
.captured
[9]),
210 for (let c
of ["w", "b"])
211 for (let p
of ['k', 'q']) fen
+= (this.powerFlags
[c
][p
] ? "1" : "0");
215 static get RESERVE_PIECES() {
216 return [V
.PAWN
, V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
];
219 getReserveMoves([x
, y
]) {
220 const color
= this.turn
;
221 const p
= V
.RESERVE_PIECES
[y
];
222 if (this.reserve
[color
][p
] == 0) return [];
224 const start
= (color
== 'w' && p
== V
.PAWN
? 1 : 0);
225 const end
= (color
== 'b' && p
== V
.PAWN
? 7 : 8);
226 for (let i
= start
; i
< end
; i
++) {
227 for (let j
= 0; j
< V
.size
.y
; j
++) {
228 if (this.board
[i
][j
] == V
.EMPTY
) {
239 start: { x: x
, y: y
}, //a bit artificial...
249 getPotentialMovesFrom([x
, y
]) {
250 if (this.subTurn
== 1) return super.getPotentialMovesFrom([x
, y
]);
251 if (this.subTurn
== 2) {
253 const L
= this.firstMove
.length
;
254 const fm
= this.firstMove
[L
-1];
255 switch (fm
.end
.effect
) {
256 // case 0: a click is required (banana or bomb)
258 // Exchange position with any piece
259 for (let i
=0; i
<8; i
++) {
260 for (let j
=0; j
<8; j
++) {
261 const colIJ
= this.getColor(i
, j
);
265 this.board
[i
][j
] != V
.EMPTY
&&
268 const movedUnit
= new PiPo({
272 p: this.getPiece(i
, j
)
274 let mMove
= this.getBasicMove([x
, y
], [i
, j
]);
275 mMove
.appear
.push(movedUnit
);
282 // Resurrect a captured piece
283 if (x
>= V
.size
.x
) moves
= this.getReserveMoves([x
, y
]);
286 // Play again with the same piece
287 if (fm
.end
.x
== x
&& fm
.end
.y
== y
)
288 moves
= super.getPotentialMovesFrom([x
, y
]);
295 // Helper for getBasicMove()
296 getRandomSquare([x
, y
], steps
) {
297 const validSteps
= steps
.filter(s
=> {
298 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
301 (this.board
[i
][j
] == V
.EMPTY
|| this.getColor(i
, j
) == 'a')
304 if (validSteps
.length
== 0)
305 // Can happen after mushroom jump
307 const step
= validSteps
[randInt(validSteps
.length
)];
308 return [x
+ step
[0], y
+ step
[1]];
311 getBasicMove([x1
, y1
], [x2
, y2
], tr
) {
312 // Apply mushroom, bomb or banana effect (hidden to the player).
313 // Determine egg effect, too, and apply its first part if possible.
314 let move = super.getBasicMove([x1
, y1
], [x2
, y2
], tr
);
315 const color1
= this.getColor(x1
, y1
);
316 const color2
= this.getColor(x2
, y2
);
317 const piece1
= this.getPiece(x1
, y1
);
318 const piece2
= this.getPiece(x2
, y2
);
319 const oppCol
= V
.GetOppCol(color1
);
321 [V
.PAWN
, V
.KNIGHT
].includes(piece1
) &&
322 (color2
!= 'a' || !([V
.BANANA
, V
.BOMB
].includes(piece2
)))
326 const twoSquaresMove
= (Math
.abs(x2
- x1
) == 2);
327 const mushroomX
= x1
+ (twoSquaresMove
? (x2
- x1
) / 2 : 0);
336 if (this.getColor(mushroomX
, y1
) == 'a') {
342 p: this.getPiece(mushroomX
, y1
)
349 const deltaX
= Math
.abs(x2
- x1
);
350 const deltaY
= Math
.abs(y2
- y1
);
352 x1
+ (deltaX
== 2 ? (x2
- x1
) / 2 : 0),
353 y1
+ (deltaY
== 2 ? (y2
- y1
) / 2 : 0)
356 this.board
[eggSquare
[0]][eggSquare
[1]] == V
.EMPTY
||
357 this.getColor(eggSquare
[0], eggSquare
[1]) == 'a'
367 if (this.getColor(eggSquare
[0], eggSquare
[1]) == 'a') {
373 p: this.getPiece(eggSquare
[0], eggSquare
[1])
382 const applyBeffect
= (steps
) => {
383 const [x
, y
] = [move.appear
[0].x
, move.appear
[0].y
];
384 const moveTo
= this.getRandomSquare([x
, y
], steps
);
385 move.appear
[0].x
= moveTo
[0];
386 move.appear
[0].y
= moveTo
[1];
388 // For (wa)luigi effect:
389 const changePieceColor
= (color
) => {
391 for (let i
=0; i
<8; i
++) {
392 for (let j
=0; j
<8; j
++) {
394 this.board
[i
][j
] != V
.EMPTY
&&
395 this.getColor(i
, j
) == color
397 const piece
= this.getPiece(i
, j
);
399 pieces
.push({ x: i
, y: j
, p: piece
});
403 const cp
= pieces
[randInt(pieces
.length
)];
416 c: V
.GetOppCol(color
),
421 const applyEggEffect
= () => {
422 if (this.subTurn
== 1) {
423 // 1) Determine the effect (some may be impossible)
424 let effects
= ["kingboo", "koopa", "chomp", "bowser"];
425 if (this.captured
[color1
].some(c
=> c
>= 1))
426 effects
.push("toadette");
427 V
.PlayOnBoard(this.board
, move);
428 const canPlayAgain
= this.getPotentialMovesFrom([x2
, y2
]).length
> 0;
429 V
.UndoOnBoard(this.board
, move);
430 if (canPlayAgain
) effects
.push("daisy");
433 b
.some(cell
=> cell
[0] == oppCol
&& cell
[1] != V
.KING
))
435 effects
.push("luigi");
439 b
.some(cell
=> cell
[0] == color1
&& cell
[1] != V
.KING
))
441 effects
.push("waluigi");
443 const effect
= effects
[randInd(effects
.length
)];
444 // 2) Apply it if possible, or set move.end.effect
445 if (["kingboo", "toadette", "daisy"].includes(effect
))
446 move.end
.effect
= effect
;
450 move.appear
[0].x
= x1
;
451 move.appear
[0].y
= y1
;
454 move.appear
.unshift();
457 move.appear
[0].p
= V
.IMMOBILIZE_CODE
[piece1
];
460 changePieceColor(oppCol
);
463 changePieceColor(color1
);
469 const applyMushroomEffect
= () => {
470 if ([V
.PAWN
, V
.KING
, V
.KNIGHT
].includes(piece1
)) {
471 // Just make another similar step, if possible (non-capturing)
473 move.appear
[0].x
+ 2 * (x2
- x1
),
474 move.appear
[0].y
+ 2 * (y2
- y1
)
478 (this.board
[i
][j
] == V
.EMPTY
|| this.getColor(i
, j
) == 'a')
480 move.appear
[0].x
= i
;
481 move.appear
[0].y
= j
;
482 if (this.board
[i
][j
] != V
.EMPTY
) {
483 const object
= this.getPiece(i
, j
);
494 applyBeffect(V
.steps
[V
.ROOK
]);
497 applyBeffect(V
.steps
[V
.BISHOP
]);
503 applyMushroomEffect();
510 // Queen, bishop or rook:
512 (x2
- x1
) / Math
.abs(x2
- x1
) || 0,
513 (y2
- y1
) / Math
.abs(y2
- y1
) || 0
515 const next
= [move.appear
[0].x
+ step
[0], move.appear
[0].y
+ step
[1]];
517 V
.OnBoard(next
[0], next
[1]) &&
518 this.board
[next
[0]][next
[1]] != V
.EMPTY
&&
519 this.getColor(next
[0], next
[1]) != 'a'
521 const afterNext
= [next
[0] + step
[0], next
[1] + step
[1]];
523 V
.OnBoard(afterNext
[0], afterNext
[1]) &&
525 this.board
[afterNext
[0]][afterNext
[1]] == V
.EMPTY
||
526 this.getColor(afterNext
[0], afterNext
[1]) == 'a'
529 move.appear
[0].x
= afterNext
[0];
530 move.appear
[0].y
= afterNext
[1];
531 if (this.board
[afterNext
[0]][afterNext
[1]] != V
.EMPTY
) {
532 const object
= this.getPiece(afterNext
[0], afterNext
[1]);
543 applyBeffect(V
.steps
[V
.ROOK
]);
546 applyBeffect(V
.steps
[V
.BISHOP
]);
552 applyMushroomEffect();
563 applyBeffect(V
.steps
[V
.ROOK
]);
566 applyBeffect(V
.steps
[V
.BISHOP
]);
569 applyMushroomEffect();
572 if (this.subTurn
== 1) {
573 // No egg effect at subTurn 2
574 if ([V
.ROOK
, V
.BISHOP
].includes(piece1
)) {
575 // Drop a bomb or banana at random, because even if bonus is
576 // "play again" nothing can be done after next move.
577 const steps
= V
.steps
[piece1
== V
.ROOK
? V
.BISHOP : V
.ROOK
];
578 const object
= (piece1
== V
.ROOK
? V
.BANANA : V
.BOMB
);
579 const dropOn
= this.getRandomSquare([x
, y
], steps
);
596 [V
.ROOK
, V
.BISHOP
].includes(piece1
)
603 getEnpassantCaptures([x
, y
], shiftX
) {
604 const Lep
= this.epSquares
.length
;
605 const epSquare
= this.epSquares
[Lep
- 1]; //always at least one element
606 let enpassantMove
= null;
609 epSquare
.x
== x
+ shiftX
&&
610 Math
.abs(epSquare
.y
- y
) == 1
612 // Not using this.getBasicMove() because the mushroom has no effect
613 enpassantMove
= super.getBasicMove([x
, y
], [epSquare
.x
, epSquare
.y
]);
614 enpassantMove
.vanish
.push({
618 c: this.getColor(x
, epSquare
.y
)
621 return !!enpassantMove
? [enpassantMove
] : [];
624 getPotentialPawnMoves([x
, y
]) {
625 const color
= this.turn
;
626 const oppCol
= V
.GetOppCol(color
);
627 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
628 const shiftX
= V
.PawnSpecs
.directions
[color
];
629 const firstRank
= (color
== "w" ? sizeX
- 1 : 0);
632 this.board
[x
+ shiftX
][y
] == V
.EMPTY
||
633 this.getColor(x
+ shiftX
, y
) == 'a'
635 this.addPawnMoves([x
, y
], [x
+ shiftX
, y
], moves
);
637 [firstRank
, firstRank
+ shiftX
].includes(x
) &&
638 this.board
[x
+ 2 * shiftX
][y
] == V
.EMPTY
640 moves
.push(this.getBasicMove([x
, y
], [x
+ 2 * shiftX
, y
]));
643 for (let shiftY
of [-1, 1]) {
646 y
+ shiftY
< sizeY
&&
647 this.board
[x
+ shiftX
][y
+ shiftY
] != V
.EMPTY
&&
648 this.getColor(x
+ shiftX
, y
+ shiftY
) == oppCol
650 this.addPawnMoves([x
, y
], [x
+ shiftX
, y
+ shiftY
], moves
);
653 Array
.prototype.push
.apply(
655 this.getEnpassantCaptures([x
, y
], shiftX
)
660 getPotentialQueenMoves(sq
) {
661 const normalMoves
= super.getPotentialQueenMoves(sq
);
662 // If flag allows it, add 'invisible movements'
663 let invisibleMoves
= [];
664 if (this.powerFlags
[this.turn
][V
.QUEEN
]) {
665 normalMoves
.forEach(m
=> {
666 if (m
.vanish
.length
== 1) {
667 let im
= JSON
.parse(JSON
.stringify(m
));
668 m
.appear
[0].p
= V
.INVISIBLE_QUEEN
;
669 invisibleMoves
.push(im
);
673 return normalMoves
.concat(invisibleMoves
);
676 getPotentialKingMoves([x
, y
]) {
677 let moves
= super.getPotentialKingMoves([x
, y
]);
678 const color
= this.turn
;
679 // If flag allows it, add 'remote shell captures'
680 if (this.powerFlags
[this.turn
][V
.KING
]) {
681 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]).forEach(step
=> {
682 let [i
, j
] = [x
+ 2 * step
[0], y
+ 2 * step
[1]];
686 this.board
[i
][j
] == V
.EMPTY
||
688 this.getColor(i
, j
) == 'a' &&
689 [V
.EGG
, V
.MUSHROOM
].includes(this.getPiece(i
, j
))
696 if (V
.OnBoard(i
, j
) && this.getColor(i
, j
) != color
)
697 // May just destroy a bomb or banana:
698 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
704 getSlideNJumpMoves([x
, y
], steps
, oneStep
) {
706 outerLoop: for (let step
of steps
) {
712 this.board
[i
][j
] == V
.EMPTY
||
714 this.getColor(i
, j
) == 'a' &&
715 [V
.EGG
, V
.MUSHROOM
].includes(this.getPiece(i
, j
))
719 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
720 if (oneStep
) continue outerLoop
;
724 if (V
.OnBoard(i
, j
) && this.canTake([x
, y
], [i
, j
]))
725 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
730 getAllPotentialMoves() {
731 if (this.subTurn
== 1) return super.getAllPotentialMoves();
733 const L
= this.firstMove
.length
;
734 const fm
= this.firstMove
[L
-1];
735 switch (fm
.end
.effect
) {
738 start: { x: -1, y: -1 },
739 end: { x: -1, y: -1 },
745 (fm
.vanish
[0].p
== V
.ROOK
? V
.steps
[V
.BISHOP
] : V
.steps
[V
.ROOK
])
747 const [i
, j
] = [fm
.end
.x
+ step
[0], fm
.end
.y
+ step
[1]];
750 (this.board
[i
][j
] == V
.EMPTY
|| this.getColor(i
, j
) == 'a')
753 start: { x: -1, y: -1 },
760 p: (fm
.vanish
[0].p
== V
.ROOK
? V
.BANANA : V
.BOMB
)
765 if (this.board
[i
][j
] != V
.EMPTY
) {
767 new PiPo({ x: i
, y: j
, c: 'a', p: this.getPiece(i
, j
) }));
774 const [x
, y
] = [fm
.end
.x
, fm
.end
.y
];
775 for (let i
=0; i
<8; i
++) {
776 for (let j
=0; j
<8; j
++) {
777 const colIJ
= this.getColor(i
, j
);
781 this.board
[i
][j
] != V
.EMPTY
&&
784 const movedUnit
= new PiPo({
788 p: this.getPiece(i
, j
)
790 let mMove
= this.getBasicMove([x
, y
], [i
, j
]);
791 mMove
.appear
.push(movedUnit
);
799 const x
= V
.size
.x
+ (this.turn
== 'w' ? 0 : 1);
800 for (let y
= 0; y
< 8; y
++)
801 Array
.prototype.push
.apply(moves
, this.getReserveMoves([x
, y
]));
805 moves
= super.getPotentialMovesFrom([fm
.end
.x
, fm
.end
.y
]);
812 if (isNaN(square
[0])) return null;
813 if (this.subTurn
== 1) return null;
814 const L
= this.firstMove
.length
;
815 const fm
= this.firstMove
[L
-1];
816 if (fm
.end
.effect
!= 0) return null;
817 const [x
, y
] = [square
[0], square
[1]];
818 const deltaX
= Math
.abs(fm
.end
.x
- x
);
819 const deltaY
= Math
.abs(fm
.end
.y
- y
);
820 if (deltaX
== 0 && deltaY
== 0) {
823 start: { x: -1, y: -1 },
824 end: { x: -1, y: -1 },
830 (this.board
[x
][y
] == V
.EMPTY
|| this.getColor(x
, y
) == 'a') &&
832 (fm
.vanish
[0].p
== V
.ROOK
&& deltaX
== 1 && deltaY
== 1) ||
833 (fm
.vanish
[0].p
== V
.BISHOP
&& deltaX
+ deltaY
== 1)
837 start: { x: -1, y: -1 },
844 p: (fm
.vanish
[0].p
== V
.ROOK
? V
.BANANA : V
.BOMB
)
849 if (this.board
[x
][y
] != V
.EMPTY
) {
851 new PiPo({ x: x
, y: y
, c: 'a', p: this.getPiece(x
, y
) }));
859 move.flags
= JSON
.stringify(this.aggregateFlags());
860 this.epSquares
.push(this.getEpSquare(move));
861 V
.PlayOnBoard(this.board
, move);
862 move.turn
= [this.turn
, this.subTurn
];
863 if (move.end
.effect
!== undefined) {
864 this.firstMove
.push(move);
868 this.turn
= V
.GetOppCol(this.turn
);
876 if (move.end
.effect
== 2) this.reserve
= this.captured
;
877 else this.reserve
= null;
878 if (move.vanish
.length
== 2 && move.vanish
[1].c
!= 'a')
879 // Capture: update this.captured
880 this.captured
[move.vanish
[1].c
][move.vanish
[1].p
]++;
881 else if (move.vanish
.length
== 0) {
882 // A piece is back on board
883 this.captured
[move.appear
[0].c
][move.appear
[0].p
]++;
886 if (this.subTurn
== 1) {
889 move.vanish
[0].p
== V
.KING
&&
891 Math
.abs(move.end
.x
- move.start
.x
) >= 2 ||
892 Math
.abs(move.end
.y
- move.start
.y
) >= 2
895 this.powerFlags
[move.vanish
[0].c
][V
.KING
] = false;
898 move.vanish
[0].p
== V
.QUEEN
&&
899 this.getPiece(move.end
.x
, move.end
.y
) == V
.INVISIBLE_QUEEN
901 this.powerFlags
[move.vanish
[0].c
][V
.QUEEN
] = false;
903 const color
= move.vanish
[0].c
;
904 const oppCol
= V
.GetOppCol(color
);
905 if (!(Object
.keys(V
.IMMOBILIZE_DECODE
).includes(move.appear
[0].p
))) {
906 // Look for an immobilized piece of my color: it can now move
907 // Also make opponent invisible queen visible again, if any
908 for (let i
=0; i
<8; i
++) {
909 for (let j
=0; j
<8; j
++) {
910 if (this.board
[i
][j
] != V
.EMPTY
) {
911 const colIJ
= this.getColor(i
, j
);
912 const piece
= this.getPiece(i
, j
);
915 Object
.keys(V
.IMMOBILIZE_DECODE
).includes(piece
)
917 this.board
[i
][j
] = color
+ V
.IMMOBILIZE_DECODE
[piece
];
918 move.wasImmobilized
= [i
, j
];
922 piece
== V
.INVISIBLE_QUEEN
924 this.board
[i
][j
] = oppCol
+ V
.QUEEN
;
925 move.wasInvisible
= [i
, j
];
935 this.epSquares
.pop();
936 this.disaggregateFlags(JSON
.parse(move.flags
));
937 V
.UndoOnBoard(this.board
, move);
938 if (move.end
.effect
!== undefined) this.firstMove
.pop();
939 else this.movesCount
--;
940 if (this.subTurn
== 1) this.movesCount
--;
941 this.turn
= move.turn
[0];
942 this.subTurn
= move.turn
[1];
947 if (!!move.wasImmobilized
) {
948 const [i
, j
] = move.wasImmobilized
;
950 this.getColor(i
, j
) + V
.IMMOBILIZE_CODE
[this.getPiece(i
, j
)];
952 if (!!move.wasInvisible
) {
953 const [i
, j
] = move.wasInvisible
;
955 this.getColor(i
, j
) + V
.INVISIBLE_QUEEN
;
957 if (move.vanish
.length
== 2 && move.vanish
[1].c
!= 'a')
958 this.captured
[move.vanish
[1].c
][move.vanish
[1].p
]--;
959 else if (move.vanish
.length
== 0) {
960 // A piece is back on board
961 this.captured
[move.vanish
[1].c
][move.vanish
[1].p
]++;
964 if (move.vanish
.length
== 0) this.reserve
= this.captured
;
965 else this.reserve
= null;
973 // Find kings (not tracked in this variant)
974 let kingThere
= { w: false, b: false };
975 for (let i
=0; i
<8; i
++) {
976 for (let j
=0; j
<8; j
++) {
977 if (this.board
[i
][j
] != V
.EMPTY
&& this.getPiece(i
, j
) == V
.KING
)
978 kingThere
[this.getColor(i
, j
)] = true;
981 if (!kingThere
['w']) return "0-1";
982 if (!kingThere
['b']) return "1-0";
986 static GenRandInitFen(randomness
) {
988 SuicideRules
.GenRandInitFen(randomness
).slice(0, -1) +
989 // Add Peach + Mario flags, re-add en-passant + capture counts
1000 const moves
= this.getAllValidMoves();
1001 let move1
= moves
[randInt(moves
.length
)];
1003 let move2
= undefined;
1004 if (this.subTurn
== 2) {
1005 const moves2
= this.getAllValidMoves();
1006 move2
= moves2
[randInt(moves2
.length
)];
1009 if (!move2
) return move1
;
1010 return [move1
, move2
];
1014 // TODO: invisibility used => move notation Q??
1015 // Also, bonus should be clearly indicated + bomb/bananas locations
1016 // TODO: effect name + code to help move notation
1017 if (move.vanish
.length
== 0) {
1019 move.appear
[0].p
!= V
.PAWN
? move.appear
[0].p
.toUpperCase() : "";
1020 return piece
+ "@" + V
.CoordsToSquare(move.end
);
1022 return super.getNotation(move);