d6c683dcf3d06c6a8d447c816c90682a9d80c841
1 import ChessRules
from "/base_rules";
2 import GiveawayRules
from "/variants/Giveaway";
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";
8 export class ChakartRules
extends ChessRules
{
10 static get Options() {
15 variable: "randomness",
18 { label: "Deterministic", value: 0 },
19 { label: "Symmetric random", value: 1 },
20 { label: "Asymmetric random", value: 2 }
27 get pawnPromotions() {
28 return ['q', 'r', 'n', 'b', 'k'];
38 static get IMMOBILIZE_CODE() {
49 static get IMMOBILIZE_DECODE() {
60 static get INVISIBLE_QUEEN() {
64 // Fictive color 'a', bomb banana mushroom egg
69 return 'd'; //"Donkey"
74 static get MUSHROOM() {
78 genRandInitFen(seed
) {
79 const gr
= new GiveawayRules({mode: "suicide"}, true);
81 gr
.genRandInitFen(seed
).slice(0, -1) +
82 // Add Peach + Mario flags + capture counts
83 '{"flags": "1111", "ccount": "000000000000"}'
90 ? "w" + f
.toLowerCase()
91 : (['w', 'd', 'e', 'm'].includes(f
) ? "a" : "b") + f
96 // King can send shell? Queen can be invisible?
98 w: {k: false, q: false},
99 b: {k: false, q: false}
101 for (let c
of ['w', 'b']) {
102 for (let p
of ['k', 'q']) {
103 this.powerFlags
[c
][p
] =
104 fenflags
.charAt((c
== "w" ? 0 : 2) + (p
== 'k' ? 0 : 1)) == "1";
110 return this.powerFlags
;
113 disaggregateFlags(flags
) {
114 this.powerFlags
= flags
;
118 return super.getFen() + " " + this.getCapturedFen();
122 return ['w', 'b'].map(c
=> {
123 return ['k', 'q'].map(p
=> this.powerFlags
[c
][p
] ? "1" : "0").join("");
128 const res
= ['w', 'b'].map(c
=> {
129 Object
.values(this.captured
[c
])
131 return res
[0].concat(res
[1]).join("");
134 setOtherVariables(fenParsed
) {
135 super.setOtherVariables(fenParsed
);
136 // Initialize captured pieces' counts from FEN
137 const allCapts
= fenParsed
.captured
.split("").map(x
=> parseInt(x
, 10));
138 const pieces
= ['p', 'r', 'n', 'b', 'q', 'k'];
140 w: Array
.toObject(pieces
, allCapts
.slice(0, 6)),
141 b: Array
.toObject(pieces
, allCapts
.slice(6, 12))
143 this.reserve
= { w: {}, b: {} }; //to be replaced by this.captured
147 // For Toadette bonus
148 getDropMovesFrom([c
, p
]) {
149 if (typeof c
!= "string" || this.reserve
[c
][p
] == 0)
152 const start
= (c
== 'w' && p
== 'p' ? 1 : 0);
153 const end
= (color
== 'b' && p
== 'p' ? 7 : 8);
154 for (let i
= start
; i
< end
; i
++) {
155 for (let j
= 0; j
< this.size
.y
; j
++) {
156 const pieceIJ
= this.getPiece(i
, j
);
158 this.board
[i
][j
] == "" ||
159 this.getColor(i
, j
) == 'a' ||
160 pieceIJ
== V
.INVISIBLE_QUEEN
165 appear: [new PiPo({x: i
, y: j
, c: c
, p: p
})],
168 // A drop move may remove a bonus (or hidden queen!)
169 if (this.board
[i
][j
] != "")
170 m
.vanish
.push(new PiPo({x: i
, y: j
, c: 'a', p: pieceIJ
}));
178 // TODO: rethink from here:
181 // queen invisible move, king shell: special functions
183 // prevent pawns from capturing invisible queen (post)
186 //events : playPlusVisual after mouse up, playReceived (include animation) on opp move
187 // ==> if move.cont (banana...) self re-call playPlusVisual (rec ?)
189 // Moving something. Potential effects resolved after playing
190 getPotentialMovesFrom([x
, y
], bonus
) {
192 if (bonus
== "toadette")
193 return this.getDropMovesFrom([x
, y
]);
194 else if (bonus
== "kingboo") {
195 // Only allow to swap pieces
196 // TODO (end of move, as for toadette)
199 // Normal case (including bonus daisy)
200 switch (this.getPiece(x
, y
)) {
202 moves
= this.getPawnMovesFrom([x
, y
]); //apply promotions
205 moves
= this.getQueenMovesFrom([x
, y
]);
208 moves
= this.getKingMoves([x
, y
]);
211 moves
= super.getPotentialMovesFrom([x
, y
]);
216 // idée : on joue le coup, puis son effet est déterminé, puis la suite (si suite)
217 // est jouée automatiquement ou demande action utilisateur, etc jusqu'à coup terminal.
219 tryMoveFollowup(move) {
220 if (this.getColor(move.end
.x
, move.end
.y
) == 'a') {
221 // effect, or bonus/malus
222 const endType
= this.getPiece(m
.end
.x
, m
.end
.y
);
223 if (endType
== V
.EGG
)
224 this.applyRandomBonus(m
);
226 this.moveStack
.push(m
);
232 // aller dans direction, saut par dessus pièce adverse
233 // ou amie (tjours), new step si roi caval pion
239 const finalPieces
= V
.PawnSpecs
.promotions
;
240 const color
= this.turn
;
241 const lastRank
= (color
== "w" ? 0 : 7);
245 m
.appear
.length
> 0 &&
246 ['p', 's'].includes(m
.appear
[0].p
) &&
247 m
.appear
[0].x
== lastRank
249 for (let i
= 1; i
< finalPieces
.length
; i
++) {
250 const piece
= finalPieces
[i
];
251 let otherM
= JSON
.parse(JSON
.stringify(m
));
253 m
.appear
[0].p
== V
.PAWN
255 : V
.IMMOBILIZE_CODE
[finalPieces
[i
]];
258 // Finally alter m itself:
260 m
.appear
[0].p
== V
.PAWN
262 : V
.IMMOBILIZE_CODE
[finalPieces
[0]];
265 Array
.prototype.push
.apply(moves
, pMoves
);
269 const L
= this.effects
.length
;
270 switch (this.effects
[L
-1]) {
272 // Exchange position with any visible piece,
273 // except pawns if arriving on last rank.
274 const lastRank
= { 'w': 0, 'b': 7 };
275 const color
= this.turn
;
276 const allowLastRank
= (this.getPiece(x
, y
) != V
.PAWN
);
277 for (let i
=0; i
<8; i
++) {
278 for (let j
=0; j
<8; j
++) {
279 const colIJ
= this.getColor(i
, j
);
280 const pieceIJ
= this.getPiece(i
, j
);
282 (i
!= x
|| j
!= y
) &&
283 this.board
[i
][j
] != V
.EMPTY
&&
284 pieceIJ
!= V
.INVISIBLE_QUEEN
&&
288 (pieceIJ
!= V
.PAWN
|| x
!= lastRank
[colIJ
]) &&
289 (allowLastRank
|| i
!= lastRank
[color
])
291 const movedUnit
= new PiPo({
295 p: this.getPiece(i
, j
)
297 let mMove
= this.getBasicMove({ x: x
, y: y
}, [i
, j
]);
298 mMove
.appear
.push(movedUnit
);
306 // Resurrect a captured piece
307 if (x
>= V
.size
.x
) moves
= this.getReserveMoves([x
, y
]);
310 // Play again with any piece
311 moves
= super.getPotentialMovesFrom([x
, y
]);
318 // Helper for getBasicMove(): banana/bomb effect
319 getRandomSquare([x
, y
], steps
) {
320 const validSteps
= steps
.filter(s
=> this.onBoard(x
+ s
[0], y
+ s
[1]));
321 const step
= validSteps
[Random
.randInt(validSteps
.length
)];
322 return [x
+ step
[0], y
+ step
[1]];
325 // Apply mushroom, bomb or banana effect (hidden to the player).
326 // Determine egg effect, too, and apply its first part if possible.
327 getBasicMove_aux(psq1
, sq2
, tr
, initMove
) {
328 const [x1
, y1
] = [psq1
.x
, psq1
.y
];
329 const color1
= this.turn
;
330 const piece1
= (!!tr
? tr
.p : (psq1
.p
|| this.getPiece(x1
, y1
)));
331 const oppCol
= V
.GetOppCol(color1
);
337 // banana or bomb defines next square, or the move ends there
346 if (this.board
[x1
][y1
] != V
.EMPTY
) {
347 const initP1
= this.getPiece(x1
, y1
);
352 c: this.getColor(x1
, y1
),
356 if ([V
.BANANA
, V
.BOMB
].includes(initP1
)) {
357 const steps
= V
.steps
[initP1
== V
.BANANA
? V
.ROOK : V
.BISHOP
];
358 move.next
= this.getRandomSquare([x1
, y1
], steps
);
361 move.end
= { x: x1
, y: y1
};
364 const [x2
, y2
] = [sq2
[0], sq2
[1]];
365 // The move starts normally, on board:
366 let move = super.getBasicMove([x1
, y1
], [x2
, y2
], tr
);
367 if (!!tr
) move.promoteInto
= tr
.c
+ tr
.p
; //in case of (chomped...)
368 const L
= this.effects
.length
;
370 [V
.PAWN
, V
.KNIGHT
].includes(piece1
) &&
372 (this.subTurn
== 1 || this.effects
[L
-1] == "daisy")
376 const twoSquaresMove
= (Math
.abs(x2
- x1
) == 2);
377 const mushroomX
= x1
+ (twoSquaresMove
? (x2
- x1
) / 2 : 0);
386 if (this.getColor(mushroomX
, y1
) == 'a') {
392 p: this.getPiece(mushroomX
, y1
)
399 const deltaX
= Math
.abs(x2
- x1
);
400 const deltaY
= Math
.abs(y2
- y1
);
402 x1
+ (deltaX
== 2 ? (x2
- x1
) / 2 : 0),
403 y1
+ (deltaY
== 2 ? (y2
- y1
) / 2 : 0)
406 this.board
[eggSquare
[0]][eggSquare
[1]] != V
.EMPTY
&&
407 this.getColor(eggSquare
[0], eggSquare
[1]) != 'a'
420 if (this.getColor(eggSquare
[0], eggSquare
[1]) == 'a') {
426 p: this.getPiece(eggSquare
[0], eggSquare
[1])
434 // For (wa)luigi effect:
435 const changePieceColor
= (color
) => {
437 const oppLastRank
= (color
== 'w' ? 7 : 0);
438 for (let i
=0; i
<8; i
++) {
439 for (let j
=0; j
<8; j
++) {
440 const piece
= this.getPiece(i
, j
);
442 (i
!= move.vanish
[0].x
|| j
!= move.vanish
[0].y
) &&
443 this.board
[i
][j
] != V
.EMPTY
&&
444 piece
!= V
.INVISIBLE_QUEEN
&&
445 this.getColor(i
, j
) == color
447 if (piece
!= V
.KING
&& (piece
!= V
.PAWN
|| i
!= oppLastRank
))
448 pieces
.push({ x: i
, y: j
, p: piece
});
452 // Special case of the current piece (still at its initial position)
454 pieces
.push({ x: move.appear
[0].x
, y: move.appear
[0].y
, p: piece1
});
455 const cp
= pieces
[randInt(pieces
.length
)];
456 if (move.appear
[0].x
!= cp
.x
|| move.appear
[0].y
!= cp
.y
) {
466 else move.appear
.shift();
471 c: V
.GetOppCol(color
),
476 const applyEggEffect
= () => {
477 if (this.subTurn
== 2)
478 // No egg effects at subTurn 2
480 // 1) Determine the effect (some may be impossible)
481 let effects
= ["kingboo", "koopa", "chomp", "bowser", "daisy"];
482 if (Object
.values(this.captured
[color1
]).some(c
=> c
>= 1))
483 effects
.push("toadette");
484 const lastRank
= { 'w': 0, 'b': 7 };
486 this.board
.some((b
,i
) =>
491 (cell
[1] != V
.PAWN
|| i
!= lastRank
[color1
])
496 effects
.push("luigi");
501 (piece1
!= V
.PAWN
|| move.appear
[0].x
!= lastRank
[oppCol
])
503 this.board
.some((b
,i
) =>
508 (cell
[1] != V
.PAWN
|| i
!= lastRank
[oppCol
])
513 effects
.push("waluigi");
515 const effect
= effects
[randInt(effects
.length
)];
516 move.end
.effect
= effect
;
517 // 2) Apply it if possible
518 if (!(["kingboo", "toadette", "daisy"].includes(effect
))) {
522 // Maybe egg effect was applied after others,
523 // so just shift vanish array:
530 move.appear
[0].p
= V
.IMMOBILIZE_CODE
[piece1
];
533 changePieceColor(oppCol
);
536 changePieceColor(color1
);
541 const applyMushroomEffect
= () => {
542 if ([V
.PAWN
, V
.KING
, V
.KNIGHT
].includes(piece1
)) {
543 // Just make another similar step, if possible (non-capturing)
545 move.appear
[0].x
+ (x2
- x1
),
546 move.appear
[0].y
+ (y2
- y1
)
551 this.board
[i
][j
] == V
.EMPTY
||
552 this.getPiece(i
, j
) == V
.INVISIBLE_QUEEN
||
553 this.getColor(i
, j
) == 'a'
556 move.appear
[0].x
= i
;
557 move.appear
[0].y
= j
;
558 if (this.board
[i
][j
] != V
.EMPTY
) {
559 const object
= this.getPiece(i
, j
);
560 const color
= this.getColor(i
, j
);
572 const steps
= V
.steps
[object
== V
.BANANA
? V
.ROOK : V
.BISHOP
];
573 move.next
= this.getRandomSquare([i
, j
], steps
);
579 applyMushroomEffect();
586 // Queen, bishop or rook:
588 (x2
- x1
) / Math
.abs(x2
- x1
) || 0,
589 (y2
- y1
) / Math
.abs(y2
- y1
) || 0
591 const next
= [move.appear
[0].x
+ step
[0], move.appear
[0].y
+ step
[1]];
593 V
.OnBoard(next
[0], next
[1]) &&
594 this.board
[next
[0]][next
[1]] != V
.EMPTY
&&
595 this.getPiece(next
[0], next
[1]) != V
.INVISIBLE_QUEEN
&&
596 this.getColor(next
[0], next
[1]) != 'a'
598 const afterNext
= [next
[0] + step
[0], next
[1] + step
[1]];
599 if (V
.OnBoard(afterNext
[0], afterNext
[1])) {
600 const afterColor
= this.getColor(afterNext
[0], afterNext
[1]);
602 this.board
[afterNext
[0]][afterNext
[1]] == V
.EMPTY
||
605 move.appear
[0].x
= afterNext
[0];
606 move.appear
[0].y
= afterNext
[1];
607 if (this.board
[afterNext
[0]][afterNext
[1]] != V
.EMPTY
) {
608 // object = banana, bomb, mushroom or egg
609 const object
= this.getPiece(afterNext
[0], afterNext
[1]);
622 V
.steps
[object
== V
.BANANA
? V
.ROOK : V
.BISHOP
];
623 move.next
= this.getRandomSquare(
624 [afterNext
[0], afterNext
[1]], steps
);
630 applyMushroomEffect();
639 const color2
= this.getColor(x2
, y2
);
640 const piece2
= this.getPiece(x2
, y2
);
645 const steps
= V
.steps
[piece2
== V
.BANANA
? V
.ROOK : V
.BISHOP
];
646 move.next
= this.getRandomSquare([x2
, y2
], steps
);
649 applyMushroomEffect();
652 if (this.subTurn
== 1)
653 // No egg effect at subTurn 2
661 move.appear
.length
> 0 &&
662 [V
.ROOK
, V
.BISHOP
].includes(piece1
)
664 const finalSquare
= [move.appear
[0].x
, move.appear
[0].y
];
667 this.getColor(finalSquare
[0], finalSquare
[1]) != 'a' ||
668 this.getPiece(finalSquare
[0], finalSquare
[1]) != V
.EGG
671 V
.steps
[piece1
== V
.ROOK
? V
.BISHOP : V
.ROOK
].filter(s
=> {
672 const [i
, j
] = [finalSquare
[0] + s
[0], finalSquare
[1] + s
[1]];
675 // NOTE: do not place a bomb or banana on the invisible queen!
676 (this.board
[i
][j
] == V
.EMPTY
|| this.getColor(i
, j
) == 'a')
679 if (validSteps
.length
>= 1) {
680 const randIdx
= randInt(validSteps
.length
);
682 finalSquare
[0] + validSteps
[randIdx
][0],
683 finalSquare
[1] + validSteps
[randIdx
][1]
690 p: (piece1
== V
.ROOK
? V
.BANANA : V
.BOMB
)
693 if (this.board
[x
][y
] != V
.EMPTY
) {
695 new PiPo({ x: x
, y: y
, c: 'a', p: this.getPiece(x
, y
) }));
703 getBasicMove(psq1
, sq2
, tr
) {
705 if (Array
.isArray(psq1
)) psq1
= { x: psq1
[0], y: psq1
[1] };
706 let m
= this.getBasicMove_aux(psq1
, sq2
, tr
, "initMove");
708 // Last move ended on bomb or banana, direction change
709 V
.PlayOnBoard(this.board
, m
);
711 m
= this.getBasicMove_aux(
712 { x: m
.appear
[0].x
, y: m
.appear
[0].y
}, m
.next
);
714 for (let i
=moves
.length
-1; i
>=0; i
--) V
.UndoOnBoard(this.board
, moves
[i
]);
716 // Now merge moves into one
718 // start is wrong for Toadette moves --> it's fixed later
719 move.start
= { x: psq1
.x
, y: psq1
.y
};
720 move.end
= !!sq2
? { x: sq2
[0], y: sq2
[1] } : { x: psq1
.x
, y: psq1
.y
};
721 if (!!tr
) move.promoteInto
= moves
[0].promoteInto
;
722 let lm
= moves
[moves
.length
-1];
723 if (this.subTurn
== 1 && !!lm
.end
.effect
)
724 move.end
.effect
= lm
.end
.effect
;
725 if (moves
.length
== 1) {
726 move.appear
= moves
[0].appear
;
727 move.vanish
= moves
[0].vanish
;
730 // Keep first vanish and last appear (if any)
731 move.appear
= lm
.appear
;
732 move.vanish
= moves
[0].vanish
;
734 move.vanish
.length
>= 1 &&
735 move.appear
.length
>= 1 &&
736 move.vanish
[0].x
== move.appear
[0].x
&&
737 move.vanish
[0].y
== move.appear
[0].y
739 // Loopback on initial square:
743 for (let i
=1; i
< moves
.length
- 1; i
++) {
744 for (let v
of moves
[i
].vanish
) {
745 // Only vanishing objects, not appearing at init move
749 moves
[0].appear
.length
== 1 ||
750 moves
[0].appear
[1].x
!= v
.x
||
751 moves
[0].appear
[1].y
!= v
.y
758 // Final vanish is our piece, but others might be relevant
759 // (for some egg bonuses at least).
760 for (let i
=1; i
< lm
.vanish
.length
; i
++) {
762 lm
.vanish
[i
].c
!= 'a' ||
763 moves
[0].appear
.length
== 1 ||
764 moves
[0].appear
[1].x
!= lm
.vanish
[i
].x
||
765 moves
[0].appear
[1].y
!= lm
.vanish
[i
].y
767 move.vanish
.push(lm
.vanish
[i
]);
778 getPotentialPawnMoves([x
, y
]) {
779 const color
= this.turn
;
780 const oppCol
= C
.GetOppCol(color
);
781 const shiftX
= (color
== 'w' ? -1 : 1);
782 const firstRank
= (color
== "w" ? this.size
.x
- 1 : 0);
785 this.board
[x
+ shiftX
][y
] == "" ||
786 this.getColor(x
+ shiftX
, y
) == 'a' ||
787 this.getPiece(x
+ shiftX
, y
) == V
.INVISIBLE_QUEEN
791 this.addPawnMoves([x
, y
], [x
+ shiftX
, y
], moves
);
793 [firstRank
, firstRank
+ shiftX
].includes(x
) &&
795 this.board
[x
+ 2 * shiftX
][y
] == V
.EMPTY
||
796 this.getColor(x
+ 2 * shiftX
, y
) == 'a' ||
797 this.getPiece(x
+ 2 * shiftX
, y
) == V
.INVISIBLE_QUEEN
800 moves
.push(this.getBasicMove({ x: x
, y: y
}, [x
+ 2 * shiftX
, y
]));
803 for (let shiftY
of [-1, 1]) {
806 y
+ shiftY
< sizeY
&&
807 this.board
[x
+ shiftX
][y
+ shiftY
] != V
.EMPTY
&&
808 // Pawns cannot capture invisible queen this way!
809 this.getPiece(x
+ shiftX
, y
+ shiftY
) != V
.INVISIBLE_QUEEN
&&
810 ['a', oppCol
].includes(this.getColor(x
+ shiftX
, y
+ shiftY
))
812 this.addPawnMoves([x
, y
], [x
+ shiftX
, y
+ shiftY
], moves
);
818 getPotentialQueenMoves(sq
) {
819 const normalMoves
= super.getPotentialQueenMoves(sq
);
820 // If flag allows it, add 'invisible movements'
821 let invisibleMoves
= [];
822 if (this.powerFlags
[this.turn
][V
.QUEEN
]) {
823 normalMoves
.forEach(m
=> {
825 m
.appear
.length
== 1 &&
826 m
.vanish
.length
== 1 &&
827 // Only simple non-capturing moves:
830 let im
= JSON
.parse(JSON
.stringify(m
));
831 im
.appear
[0].p
= V
.INVISIBLE_QUEEN
;
832 im
.end
.noHighlight
= true;
833 invisibleMoves
.push(im
);
837 return normalMoves
.concat(invisibleMoves
);
840 getPotentialKingMoves([x
, y
]) {
841 let moves
= super.getPotentialKingMoves([x
, y
]);
842 const color
= this.turn
;
843 // If flag allows it, add 'remote shell captures'
844 if (this.powerFlags
[this.turn
][V
.KING
]) {
845 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]).forEach(step
=> {
846 let [i
, j
] = [x
+ step
[0], y
+ step
[1]];
850 this.board
[i
][j
] == V
.EMPTY
||
851 this.getPiece(i
, j
) == V
.INVISIBLE_QUEEN
||
853 this.getColor(i
, j
) == 'a' &&
854 [V
.EGG
, V
.MUSHROOM
].includes(this.getPiece(i
, j
))
861 if (V
.OnBoard(i
, j
)) {
862 const colIJ
= this.getColor(i
, j
);
863 if (colIJ
!= color
) {
864 // May just destroy a bomb or banana:
867 start: { x: x
, y: y
},
872 x: i
, y: j
, c: colIJ
, p: this.getPiece(i
, j
)
884 getSlideNJumpMoves([x
, y
], steps
, oneStep
) {
886 outerLoop: for (let step
of steps
) {
892 this.board
[i
][j
] == V
.EMPTY
||
893 this.getPiece(i
, j
) == V
.INVISIBLE_QUEEN
||
895 this.getColor(i
, j
) == 'a' &&
896 [V
.EGG
, V
.MUSHROOM
].includes(this.getPiece(i
, j
))
900 moves
.push(this.getBasicMove({ x: x
, y: y
}, [i
, j
]));
901 if (oneStep
) continue outerLoop
;
905 if (V
.OnBoard(i
, j
) && this.canTake([x
, y
], [i
, j
]))
906 moves
.push(this.getBasicMove({ x: x
, y: y
}, [i
, j
]));
911 getAllPotentialMoves() {
912 if (this.subTurn
== 1) return super.getAllPotentialMoves();
914 const color
= this.turn
;
915 const L
= this.effects
.length
;
916 switch (this.effects
[L
-1]) {
919 for (let i
=0; i
<8; i
++) {
920 for (let j
=0; j
<8; j
++) {
921 const colIJ
= this.getColor(i
, j
);
922 const pieceIJ
= this.getPiece(i
, j
);
925 this.board
[i
][j
] != V
.EMPTY
&&
927 pieceIJ
!= V
.INVISIBLE_QUEEN
929 allPieces
.push({ x: i
, y: j
, c: colIJ
, p: pieceIJ
});
933 for (let x
=0; x
<8; x
++) {
934 for (let y
=0; y
<8; y
++) {
935 if (this.getColor(i
, j
) == color
) {
936 // Add exchange with something
937 allPieces
.forEach(pp
=> {
938 if (pp
.x
!= i
|| pp
.y
!= j
) {
939 const movedUnit
= new PiPo({
945 let mMove
= this.getBasicMove({ x: x
, y: y
}, [pp
.x
, pp
.y
]);
946 mMove
.appear
.push(movedUnit
);
956 const x
= V
.size
.x
+ (this.turn
== 'w' ? 0 : 1);
957 for (let y
= 0; y
< 8; y
++)
958 Array
.prototype.push
.apply(moves
, this.getReserveMoves([x
, y
]));
962 moves
= super.getAllPotentialMoves();
977 /// if any of my pieces was immobilized, it's not anymore.
978 //if play set a piece immobilized, then mark it
980 if (move.effect
== "toadette")
981 this.reserve
= this.captured
;
983 this.reserve
= { w: {}, b: {} };;
984 const color
= this.turn
;
986 move.vanish
.length
== 2 &&
987 move.vanish
[1].c
!= 'a' &&
988 move.appear
.length
== 1 //avoid king Boo!
990 // Capture: update this.captured
991 let capturedPiece
= move.vanish
[1].p
;
992 if (capturedPiece
== V
.INVISIBLE_QUEEN
)
993 capturedPiece
= V
.QUEEN
;
994 else if (Object
.keys(V
.IMMOBILIZE_DECODE
).includes(capturedPiece
))
995 capturedPiece
= V
.IMMOBILIZE_DECODE
[capturedPiece
];
996 this.captured
[move.vanish
[1].c
][capturedPiece
]++;
998 else if (move.vanish
.length
== 0) {
999 if (move.appear
.length
== 0 || move.appear
[0].c
== 'a') return;
1000 // A piece is back on board
1001 this.captured
[move.appear
[0].c
][move.appear
[0].p
]--;
1003 if (move.appear
.length
== 0) {
1004 // Three cases: king "shell capture", Chomp or Koopa
1005 if (this.getPiece(move.start
.x
, move.start
.y
) == V
.KING
)
1006 // King remote capture:
1007 this.powerFlags
[color
][V
.KING
] = false;
1008 else if (move.end
.effect
== "chomp")
1009 this.captured
[color
][move.vanish
[0].p
]++;
1011 else if (move.appear
[0].p
== V
.INVISIBLE_QUEEN
)
1012 this.powerFlags
[move.appear
[0].c
][V
.QUEEN
] = false;
1013 if (this.subTurn
== 2) return;
1015 move.turn
[1] == 1 &&
1016 move.appear
.length
== 0 ||
1017 !(Object
.keys(V
.IMMOBILIZE_DECODE
).includes(move.appear
[0].p
))
1019 // Look for an immobilized piece of my color: it can now move
1020 for (let i
=0; i
<8; i
++) {
1021 for (let j
=0; j
<8; j
++) {
1022 if (this.board
[i
][j
] != V
.EMPTY
) {
1023 const piece
= this.getPiece(i
, j
);
1025 this.getColor(i
, j
) == color
&&
1026 Object
.keys(V
.IMMOBILIZE_DECODE
).includes(piece
)
1028 this.board
[i
][j
] = color
+ V
.IMMOBILIZE_DECODE
[piece
];
1029 move.wasImmobilized
= [i
, j
];
1035 // Also make opponent invisible queen visible again, if any
1036 const oppCol
= V
.GetOppCol(color
);
1037 for (let i
=0; i
<8; i
++) {
1038 for (let j
=0; j
<8; j
++) {
1040 this.board
[i
][j
] != V
.EMPTY
&&
1041 this.getColor(i
, j
) == oppCol
&&
1042 this.getPiece(i
, j
) == V
.INVISIBLE_QUEEN
1044 this.board
[i
][j
] = oppCol
+ V
.QUEEN
;
1045 move.wasInvisible
= [i
, j
];
1053 this.playOnBoard(move);
1054 if (["kingboo", "toadette", "daisy"].includes(move.effect
)) {
1055 this.effect
= move.effect
;
1059 this.turn
= C
.GetOppCol(this.turn
);
1065 filterValid(moves
) {
1069 playPlusVisual(move, r
) {
1071 this.playVisual(move, r
);
1074 // TODO: display bonus messages
1075 // TODO: si continuation, continuer, et sinon :
1076 this.afterPlay(this.moveStack
); //user method