-import ChessRules from "/base_rules";
-import GiveawayRules from "/variants/Giveaway";
+import ChessRules from "/base_rules.js";
+import GiveawayRules from "/variants/Giveaway/class.js";
import { ArrayFun } from "/utils/array.js";
import { Random } from "/utils/alea.js";
import PiPo from "/utils/PiPo.js";
import Move from "/utils/Move.js";
-export class ChakartRules extends ChessRules {
+export default class ChakartRules extends ChessRules {
static get Options() {
return {
}
genRandInitFen(seed) {
- const gr = new GiveawayRules({mode: "suicide"}, true);
+ const gr = new GiveawayRules(
+ {mode: "suicide", options: {}, genFenOnly: true});
return (
- gr.genRandInitFen(seed).slice(0, -1) +
+ gr.genRandInitFen(seed).slice(0, -17) +
// Add Peach + Mario flags + capture counts
- '{"flags":"1111", "ccount":"000000000000"}'
+ '{"flags":"1111","ccount":"000000000000"}'
);
}
}
getCapturedFen() {
- const res = ['w', 'b'].map(c => {
- Object.values(this.captured[c])
- });
+ const res = ['w', 'b'].map(c => Object.values(this.captured[c]));
return res[0].concat(res[1]).join("");
}
setOtherVariables(fenParsed) {
super.setOtherVariables(fenParsed);
// Initialize captured pieces' counts from FEN
- const allCapts = fenParsed.captured.split("").map(x => parseInt(x, 10));
+ const allCapts = fenParsed.ccount.split("").map(x => parseInt(x, 10));
const pieces = ['p', 'r', 'n', 'b', 'q', 'k'];
this.captured = {
- w: Array.toObject(pieces, allCapts.slice(0, 6)),
- b: Array.toObject(pieces, allCapts.slice(6, 12))
+ w: ArrayFun.toObject(pieces, allCapts.slice(0, 6)),
+ b: ArrayFun.toObject(pieces, allCapts.slice(6, 12))
};
this.reserve = { w: {}, b: {} }; //to be replaced by this.captured
this.moveStack = [];
+ this.egg = null;
}
// For Toadette bonus
return moves;
}
-// TODO: rethink from here:
-
-// allow pawns
- // queen invisible move, king shell: special functions
-
-// prevent pawns from capturing invisible queen (post)
-// post-process:
-
-//events : playPlusVisual after mouse up, playReceived (include animation) on opp move
-// ==> if move.cont (banana...) self re-call playPlusVisual (rec ?)
-
// Moving something. Potential effects resolved after playing
- getPotentialMovesFrom([x, y], bonus) {
+ getPotentialMovesFrom([x, y]) {
let moves = [];
- if (bonus == "toadette")
+ if (this.egg == "toadette")
return this.getDropMovesFrom([x, y]);
- else if (bonus == "kingboo") {
+ if (this.egg == "kingboo") {
const initPiece = this.getPiece(x, y);
const color = this.getColor(x, y);
const oppCol = C.GetOppCol(color);
- // Only allow to swap pieces (TODO: restrict for pawns)
+ // Only allow to swap pieces
for (let i=0; i<this.size.x; i++) {
for (let j=0; j<this.size.y; j++) {
- if ((i != x || j != y) && this.board[i][j] != "") {
- const pstart = new PiPo({x: x, y: y, p: initPiece, c: color});
- const pend =
+ const colIJ = this.getColor(i, j);
+ const pieceIJ = this.getPiece(i, j);
+ if (
+ (i != x || j != y) &&
+ ['w', 'b'].includes(colIJ) &&
+ // Next conditions = no pawn on last rank
+ (
+ initPiece != 'p' ||
+ (
+ (color != 'w' || i != 0) &&
+ (color != 'b' || i != this.size.x - 1)
+ )
+ )
+ &&
+ (
+ pieceIJ != 'p' ||
+ (
+ (colIJ != 'w' || x != 0) &&
+ (colIJ != 'b' || x != this.size.x - 1)
+ )
+ )
+ ) {
let m = this.getBasicMove([x, y], [i, j]);
m.appear.push(
new PiPo({x: x, y: y, p: this.getPiece(i, j), c: oppCol}));
switch (this.getPiece(x, y)) {
case 'p':
moves = this.getPawnMovesFrom([x, y]); //apply promotions
- // TODO: add mushroom on init square
break;
case 'q':
moves = this.getQueenMovesFrom([x, y]);
break;
- case 'k',
+ case 'k':
moves = this.getKingMovesFrom([x, y]);
break;
case 'n':
- moves = super.getPotentialMovesFrom([x, y]);
- // TODO: add egg on init square
+ moves = this.getKnightMovesFrom([x, y]);
break;
- default:
+ case 'b':
+ case 'r':
+ // explicitely listing types to avoid moving immobilized piece
moves = super.getPotentialMovesFrom([x, y]);
}
return moves;
this.getColor(x + shiftX, y) == 'a' ||
this.getPiece(x + shiftX, y) == V.INVISIBLE_QUEEN
) {
-
- // TODO:
- this.addPawnMoves([x, y], [x + shiftX, y], moves);
+ moves.push(this.getBasicMove([x, y], [x + shiftX, y]));
if (
[firstRank, firstRank + shiftX].includes(x) &&
(
- this.board[x + 2 * shiftX][y] == V.EMPTY ||
+ this.board[x + 2 * shiftX][y] == "" ||
this.getColor(x + 2 * shiftX, y) == 'a' ||
this.getPiece(x + 2 * shiftX, y) == V.INVISIBLE_QUEEN
)
) {
- moves.push(this.getBasicMove({ x: x, y: y }, [x + 2 * shiftX, y]));
+ moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
}
}
for (let shiftY of [-1, 1]) {
if (
y + shiftY >= 0 &&
- y + shiftY < sizeY &&
- this.board[x + shiftX][y + shiftY] != V.EMPTY &&
+ y + shiftY < this.size.y &&
+ this.board[x + shiftX][y + shiftY] != "" &&
// Pawns cannot capture invisible queen this way!
this.getPiece(x + shiftX, y + shiftY) != V.INVISIBLE_QUEEN &&
['a', oppCol].includes(this.getColor(x + shiftX, y + shiftY))
) {
- this.addPawnMoves([x, y], [x + shiftX, y + shiftY], moves);
+ moves.push(this.getBasicMove([x, y], [x + shiftX, y + shiftY]));
}
}
+ super.pawnPostProcess(moves, color, oppCol);
return moves;
}
getQueenMovesFrom(sq) {
- const normalMoves = super.getPotentialQueenMoves(sq);
+ const normalMoves = super.getPotentialMovesOf('q', sq);
// If flag allows it, add 'invisible movements'
let invisibleMoves = [];
- if (this.powerFlags[this.turn][V.QUEEN]) {
+ if (this.powerFlags[this.turn]['q']) {
normalMoves.forEach(m => {
if (
m.appear.length == 1 &&
}
getKingMovesFrom([x, y]) {
- let moves = super.getPotentialKingMoves([x, y]);
- const color = this.turn;
+ let moves = super.getPotentialMovesOf('k', [x, y]);
// If flag allows it, add 'remote shell captures'
- if (this.powerFlags[this.turn][V.KING]) {
- V.steps[V.ROOK].concat(V.steps[V.BISHOP]).forEach(step => {
+ if (this.powerFlags[this.turn]['k']) {
+ super.pieces()['k'].moves[0].steps.forEach(step => {
let [i, j] = [x + step[0], y + step[1]];
while (
- V.OnBoard(i, j) &&
+ this.onBoard(i, j) &&
(
- this.board[i][j] == V.EMPTY ||
+ this.board[i][j] == "" ||
this.getPiece(i, j) == V.INVISIBLE_QUEEN ||
(
this.getColor(i, j) == 'a' &&
i += step[0];
j += step[1];
}
- if (V.OnBoard(i, j)) {
+ if (this.onBoard(i, j)) {
const colIJ = this.getColor(i, j);
- if (colIJ != color) {
+ if (colIJ != this.turn) {
// May just destroy a bomb or banana:
moves.push(
new Move({
- start: { x: x, y: y},
- end: { x: i, y: j },
+ start: {x: x, y: y},
+ end: {x: i, y: j},
appear: [],
vanish: [
- new PiPo({
- x: i, y: j, c: colIJ, p: this.getPiece(i, j)
- })
+ new PiPo({x: i, y: j, c: colIJ, p: this.getPiece(i, j)})
]
})
);
return moves;
}
- // TODO: can merge prePlay into play() ==> no need to distinguish
+ getKnightMovesFrom([x, y]) {
+ // Add egg on initial square:
+ return super.getPotentialMovesOf('n', [x, y]).map(m => {
+ m.appear.push(new PiPo({p: "e", c: "a", x: x, y: y}));
+ return m;
+ });
+ }
+
/// if any of my pieces was immobilized, it's not anymore.
//if play set a piece immobilized, then mark it
- prePlay(move) {
- if (move.effect == "toadette")
+ play(move) {
+ if (move.effect == "toadette") {
this.reserve = this.captured;
- else
- this.reserve = { w: {}, b: {} };;
+ this.re_drawReserve([this.turn]);
+ }
+ else if (this.reserve) {
+ this.reserve = { w: {}, b: {} };
+ this.re_drawReserve([this.turn]);
+ }
const color = this.turn;
if (
move.vanish.length == 2 &&
this.captured[move.vanish[1].c][capturedPiece]++;
}
else if (move.vanish.length == 0) {
- if (move.appear.length == 0 || move.appear[0].c == 'a') return;
+ if (move.appear.length == 0 || move.appear[0].c == 'a')
+ return;
// A piece is back on board
this.captured[move.appear[0].c][move.appear[0].p]--;
}
}
}
}
- }
-
- play(move) {
- this.prePlay(move);
this.playOnBoard(move);
if (["kingboo", "toadette", "daisy"].includes(move.effect)) {
this.effect = move.effect;
this.movesCount++;
this.subTurn = 1;
}
+
+
+ if (move.egg)
+ this.displayBonus(move.egg);
+ else if (this.egg)
+ this.egg = null; //the egg is consumed
+ }
+
+ displayBonus(egg) {
+ alert(egg); //TODO: nicer display
}
filterValid(moves) {
return moves;
}
- // idée : on joue le coup, puis son effet est déterminé, puis la suite (si suite)
- // est jouée automatiquement ou demande action utilisateur, etc jusqu'à coup terminal.
tryMoveFollowup(move, cb) {
- if (this.getColor(move.end.x, move.end.y) == 'a') {
+ // Warning: at this stage, the move is played
+ if (move.vanish.length == 2 && move.vanish[1].c == 'a') {
// effect, or bonus/malus
- const endType = this.getPiece(m.end.x, m.end.y);
+ const endType = move.vanish[1].p;
switch (endType) {
case V.EGG:
this.applyRandomBonus(move, cb);
endType == V.BANANA
? [[1, 1], [1, -1], [-1, 1], [-1, -1]]
: [[1, 0], [-1, 0], [0, 1], [0, -1]]);
- const nextMove = this.getBasicMove([move.end.x, move.end.y], dest);
- cb(nextMove);
+ cb(this.getBasicMove([move.end.x, move.end.y], dest));
break;
}
- case V.MUSHROOM:
- // aller dans direction, saut par dessus pièce adverse
- // ou amie (tjours), new step si roi caval pion
+ case V.MUSHROOM: {
+ let step = [move.end.x - move.start.x, move.end.y - move.start.y];
+ if ([0, 1].some(i => step[i] >= 2 && step[1-i] != 1)) {
+ // Slider, multi-squares: normalize step
+ for (let j of [0, 1])
+ step[j] = step[j] / Math.abs(step[j]) || 0;
+ }
+ const nextSquare = [move.end.x + step[0], move.end.y + step[1]];
+ if (this.onBoard(nextSquare[0], nextSquare[1])) {
+ if (
+ this.board[nextSquare[0]][nextSquare[1]] != "" &&
+ this.getColor(nextSquare[0], nextSquare[1]) != 'a'
+ ) {
+ // (try to) jump
+ const afterSquare =
+ [nextSquare[0] + step[0], nextSquare[1] + step[1]];
+ if (
+ this.onBoard(afterSquare[0], afterSquare[1]) &&
+ this.getColor(afterSquare[0], afterSquare[1]) != this.turn
+ ) {
+ cb(this.getBasicMove([move.end.x, move.end.y], afterSquare));
+ }
+ }
+ else if (!['b', 'r', 'q'].includes(move.vanish[0].p))
+ // Take another step forward if not slider move
+ cb(this.getBasicMove([move.end.x, move.end.y], nextSquare));
+ }
break;
+ }
}
}
}
- applyRandomBonnus(move, cb) {
- // TODO: determine bonus/malus, and then
+ applyRandomBonus(move, cb) {
+ // TODO: determine bonus/malus, and then ...
+ // if toadette, daisy or kingboo : do not call cb
+ this.egg = "daisy"; //not calling cb in this case
+ this.displayBonus(this.egg);
+ move.egg = this.egg; //for play() by opponent
}
// Helper to apply banana/bomb effect
const step = validSteps[Random.randInt(validSteps.length)];
return [x + step[0], y + step[1]];
}
-// TODO: turn change indicator ?!
+
+ // Warning: if play() is called, then move.end changed.
playPlusVisual(move, r) {
this.moveStack.push(move);
this.play(move);
this.playVisual(move, r);
- if (move.bonus)
- alert(move.bonus); //TODO: nicer display
this.tryMoveFollowup(move, (nextMove) => {
if (nextMove)
this.playPlusVisual(nextMove, r);