"Keep antiking in check": "Keep antiking in check",
"Laws of attraction": "Laws of attraction",
"Lose all pieces": "Lose all pieces",
+ "Mate any piece": "Mate any piece",
"Move twice": "Move twice",
"Pawns move diagonally": "Pawns move diagonally",
"Reuse pieces": "Reuse pieces",
"Keep antiking in check": "Mantener el antirey en jaque",
"Laws of attraction": "Las leyes de las atracciones",
"Lose all pieces": "Perder todas las piezas",
+ "Mate any piece": "Matar cualquier pieza",
"Move twice": "Mover dos veces",
"Pawns move diagonally": "Peones se mueven en diagonal",
"Reuse pieces": "Reutilizar piezas",
"Keep antiking in check": "Gardez l'antiroi en échec",
"Laws of attraction": "Les lois de l'attraction",
"Lose all pieces": "Perdez toutes les pièces",
+ "Mate any piece": "Mater n'importe quelle pièce",
"Move twice": "Jouer deux coups",
"Pawns move diagonally": "Les pions vont en diagonale",
"Reuse pieces": "Réutiliser les pièces",
--- /dev/null
+p.boxed
+ | If a piece is attacked and cannot move out of attack, it is captured.
+
+p.
+ Any piece that is attacked, but which cannot escape capture by moving away,
+ capturing the attacking piece, or interposing the attacking piece is
+ considered to be mated, and is removed from the board.
+ Note that such a move does not need to be played: if a piece is attacked
+ but not mated, it is not removed.
+ Thus, kings and other pieces may remain under check.
+
+p.
+ Pieces cannot be taken in the normal way, only by the "mate-capture"
+ described above.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/p1pppppp/8/8/1P6/2N5/P1PPPPPP/RNBQKBNR:
+ figcaption After 1.b4 b5 2.Nc3X the b5 pawn is "mate-captured"
+
+p.
+ Note about moves notation: since captures do not occur on final squares,
+ an "X" mark is appended to the move to indicate a capture.
+ To keep notation short the potential list of captured squares is not written.
+
+h3 End of the game
+
+p The game ends when a king is "mate-captured".
+
+h3 Source
+
+p
+ a(href="https://www.chessvariants.com/difftaking.dir/allmate.html") Allmate chess
+ | on chessvariants.com.
--- /dev/null
+p.boxed
+ | Si una pieza es atacada y no puede escapar del ataque, se captura.
+
+p.
+ Cualquier pieza atacada que no pueda escapar de la captura moviéndose,
+ al capturar al atacante o al interponer una pieza se considera mate:
+ se elimina del juego.
+ Tenga en cuenta que tal movimiento no tiene que hacerse: cuando una pieza es
+ atacada pero sin mate, no se elimina.
+ Por lo tanto, los reyes y otras monedas pueden permanecer en jaque.
+
+p.
+ Las piezas no pueden capturar en el sentido habitual, solo a través de
+ "mate-captura" descrito anteriormente.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/p1pppppp/8/8/1P6/2N5/P1PPPPPP/RNBQKBNR:
+ figcaption Después de 1.b4 b5 2.Nc3X el peón b5 es "mate-capturado"
+
+p.
+ Nota sobre la notación de las jugadas: ya que las capturas no se realizan
+ en la casilla de llegada, se agrega una marca "X" al movimiento para indicar la captura.
+ Para evitar las notaciones demasiado largas, la lista potencial de casillas
+ de captura no está escrita.
+
+h3 Fin de la partida
+
+p El juego termina cuando un rey es "mate-capturado".
+
+h3 Fuente
+
+p
+ | La
+ a(href="https://www.chessvariants.com/difftaking.dir/allmate.html") variante Allmate
+ | en chessvariants.com.
--- /dev/null
+p.boxed
+ | Si une pièce est attaquée et ne peut se soustraire à l'attaque, elle est capturée.
+
+p.
+ Toute pièce attaquée ne pouvant échapper à la capture en se déplaçant,
+ en capturant l'attaquant ou en interposant une pièce est considérée matée :
+ elle est retirée du jeu.
+ Notez qu'un tel coup n'a pas à être joué : quand une pièce est attaquée mais
+ non matée, elle n'est pas supprimée.
+ Ainsi, les rois et autres pièces peuvent rester en échec.
+
+p.
+ Les pièces ne peuvent capturer au sens habituel, seulement via la "mat-capture"
+ décrite ci-dessus.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/p1pppppp/8/8/1P6/2N5/P1PPPPPP/RNBQKBNR:
+ figcaption Après 1.b4 b5 2.Nc3X le pion b5 est "mat-capturé"
+
+p.
+ Note sur la notation des coups: puisque les captures ne s'effectuent pas
+ sur la case d'arrivée, une marque "X" est ajoutée au coup pour indiquer la capture.
+ Afin d'éviter les notations à rallonge la liste potentielle des cases de
+ capture n'est pas écrite.
+
+h3 Fin de la partie
+
+p La partie s'achève quand un roi est "mat-capturé".
+
+h3 Source
+
+p
+ | La
+ a(href="https://www.chessvariants.com/difftaking.dir/allmate.html") variante Allmate
+ | sur chessvariants.com.
--- /dev/null
+import { ChessRules, PiPo, Move } from "@/base_rules";
+
+export const VariantRules = class AllmateRules extends ChessRules {
+ static get HasEnpassant() {
+ return false;
+ }
+
+ canTake(sq1, sq2) {
+ return false; //Captures handled differently
+ }
+
+ getCheckSquares() {
+ // No notion of check
+ return [];
+ }
+
+ static GenRandInitFen() {
+ return ChessRules.GenRandInitFen().replace(/ -$/, "");
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ let moves = super.getPotentialMovesFrom([x, y]);
+
+ // Augment moves with "mate-captures":
+ // TODO: this is coded in a highly inefficient way...
+ const color = this.turn;
+ const oppCol = V.GetOppCol(this.turn);
+ moves.forEach(m => {
+ this.play(m);
+
+ // 1) What is attacked?
+ let attacked = {};
+ for (let i=0; i<V.size.x; i++) {
+ for (let j=0; j<V.size.y; j++) {
+ if (this.getColor(i,j) == oppCol && this.isAttacked([i,j], [color]))
+ attacked[i+"_"+j] = [i,j];
+ }
+ }
+
+ // 2) Among attacked pieces, which cannot escape capture?
+ // Avoid "oppMoves = this.getAllValidMoves();" => infinite recursion
+ outerLoop: for (let i=0; i<V.size.x; i++) {
+ for (let j=0; j<V.size.y; j++) {
+ if (this.getColor(i,j) == oppCol) {
+ let oppMoves = [];
+ switch (this.getPiece(i, j)) {
+ case V.PAWN:
+ oppMoves = this.getPotentialPawnMoves([i, j]);
+ break;
+ case V.ROOK:
+ oppMoves = this.getPotentialRookMoves([i, j]);
+ break;
+ case V.KNIGHT:
+ oppMoves = this.getPotentialKnightMoves([i, j]);
+ break;
+ case V.BISHOP:
+ oppMoves = this.getPotentialBishopMoves([i, j]);
+ break;
+ case V.QUEEN:
+ oppMoves = this.getPotentialQueenMoves([i, j]);
+ break;
+ case V.KING:
+ oppMoves = this.getPotentialKingMoves([i, j]);
+ break;
+ }
+ for (let om of oppMoves) {
+ V.PlayOnBoard(this.board, om);
+ Object.values(attacked).forEach(sq => {
+ const origSq = [sq[0], sq[1]];
+ if (om.start.x == sq[0] && om.start.y == sq[1])
+ // Piece moved:
+ sq = [om.appear[0].x, om.appear[0].y];
+ if (!this.isAttacked(sq, [color]))
+ delete attacked[origSq[0]+"_"+origSq[1]];
+ });
+ V.UndoOnBoard(this.board, om);
+ if (Object.keys(attacked).length == 0)
+ // No need to explore more moves
+ break outerLoop;
+ }
+ }
+ }
+ }
+
+ // 3) Add mate-captures:
+ Object.values(attacked).forEach(sq => {
+ m.vanish.push(new PiPo({
+ x: sq[0],
+ y: sq[1],
+ c: oppCol,
+ p: this.getPiece(sq[0], sq[1])
+ }));
+ });
+
+ this.undo(m);
+ });
+
+ return moves;
+ }
+
+ // No "under check" conditions in castling
+ getCastleMoves([x, y]) {
+ const c = this.getColor(x, y);
+ if (x != (c == "w" ? V.size.x - 1 : 0) || y != this.INIT_COL_KING[c])
+ return []; //x isn't first rank, or king has moved (shortcut)
+
+ // Castling ?
+ const oppCol = V.GetOppCol(c);
+ let moves = [];
+ let i = 0;
+ // King, then rook:
+ const finalSquares = [
+ [2, 3],
+ [V.size.y - 2, V.size.y - 3]
+ ];
+ castlingCheck: for (
+ let castleSide = 0;
+ castleSide < 2;
+ castleSide++ //large, then small
+ ) {
+ if (!this.castleFlags[c][castleSide]) continue;
+ // If this code is reached, rooks and king are on initial position
+
+ // Nothing on the path of the king ? (and no checks)
+ const finDist = finalSquares[castleSide][0] - y;
+ let step = finDist / Math.max(1, Math.abs(finDist));
+ for (let i = y; i != finalSquares[castleSide][0]; i += step) {
+ if (
+ this.board[x][i] != V.EMPTY &&
+ // NOTE: next check is enough, because of chessboard constraints
+ (this.getColor(x, i) != c ||
+ ![V.KING, V.ROOK].includes(this.getPiece(x, i)))
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // Nothing on the path to the rook?
+ step = castleSide == 0 ? -1 : 1;
+ for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step) {
+ if (this.board[x][i] != V.EMPTY) continue castlingCheck;
+ }
+ const rookPos = this.INIT_COL_ROOK[c][castleSide];
+
+ // Nothing on final squares, except maybe king and castling rook?
+ for (i = 0; i < 2; i++) {
+ if (
+ this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
+ this.getPiece(x, finalSquares[castleSide][i]) != V.KING &&
+ finalSquares[castleSide][i] != rookPos
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // If this code is reached, castle is valid
+ moves.push(
+ new Move({
+ appear: [
+ new PiPo({ x: x, y: finalSquares[castleSide][0], p: V.KING, c: c }),
+ new PiPo({ x: x, y: finalSquares[castleSide][1], p: V.ROOK, c: c })
+ ],
+ vanish: [
+ new PiPo({ x: x, y: y, p: V.KING, c: c }),
+ new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c })
+ ],
+ end:
+ Math.abs(y - rookPos) <= 2
+ ? { x: x, y: rookPos }
+ : { x: x, y: y + 2 * (castleSide == 0 ? -1 : 1) }
+ })
+ );
+ }
+
+ return moves;
+ }
+
+ filterValid(moves) {
+ return moves;
+ }
+
+ updateVariables(move) {
+ super.updateVariables(move);
+ if (move.vanish.length == 2 && move.appear.length == 1) {
+ // Did opponent king disappeared?
+ if (move.vanish[1].p == V.KING)
+ this.kingPos[this.turn] = [-1, -1];
+ }
+ }
+
+ unupdateVariables(move) {
+ super.unupdateVariables(move);
+ if (move.vanish.length == 2 && move.appear.length == 1) {
+ // Did opponent king disappeared?
+ if (move.vanish[1].p == V.KING)
+ this.kingPos[move.vanish[1].c] = [move.vanish[1].x,move.vanish[1].y];
+ }
+ }
+
+ getCurrentScore() {
+ const color = this.turn;
+ const kp = this.kingPos[color];
+ if (kp[0] < 0)
+ // King disappeared
+ return color == "w" ? "0-1" : "1-0";
+ if (this.atLeastOneMove())
+ return "*";
+ // Kings still there, no moves:
+ return "1/2";
+ }
+
+ static get SEARCH_DEPTH() {
+ return 2;
+ }
+
+ getNotation(move) {
+ let notation = super.getNotation(move);
+ // Add a capture mark (not describing what is captured...):
+ if (move.vanish.length > 1 && move.appear[0].p != V.KING)
+ notation = notation.replace("x","") + "X";
+ return notation;
+ }
+};
updateVariables(move) {
super.updateVariables(move);
if (move.appear.length == 0) {
- //capture
+ // Capture
const firstRank = { w: 7, b: 0 };
for (let c of ["w", "b"]) {
// Did we explode king of color c ? (TODO: remove move earlier)
const color = this.turn;
const kp = this.kingPos[color];
if (kp[0] < 0)
- //king disappeared
+ // King disappeared
return color == "w" ? "0-1" : "1-0";
if (this.atLeastOneMove())
- // game not over
return "*";
if (!this.isAttacked(kp, [V.GetOppCol(color)])) return "1/2";
return color == "w" ? "0-1" : "1-0"; //checkmate
} else if (move.appear[0].p == V.KING)
notation = "K" + (move.vanish.length > 1 ? "x" : "") + finalSquare;
else notation = move.appear[0].p.toUpperCase() + finalSquare;
- if (move.vanish.length > 1 && move.appear[0].p != V.KING) notation += "X"; //capture mark (not describing what is captured...)
+ // Add a capture mark (not describing what is captured...):
+ if (move.vanish.length > 1 && move.appear[0].p != V.KING) notation += "X";
return notation;
}
};
return noCaptures.concat(this.getCastleMoves(sq));
}
+ // No "under check" verifications:
+ getCastleMoves([x, y]) {
+ const c = this.getColor(x, y);
+ if (x != (c == "w" ? V.size.x - 1 : 0) || y != this.INIT_COL_KING[c])
+ return []; //x isn't first rank, or king has moved (shortcut)
+
+ // Castling ?
+ const oppCol = V.GetOppCol(c);
+ let moves = [];
+ let i = 0;
+ // King, then rook:
+ const finalSquares = [
+ [2, 3],
+ [V.size.y - 2, V.size.y - 3]
+ ];
+ castlingCheck: for (
+ let castleSide = 0;
+ castleSide < 2;
+ castleSide++ //large, then small
+ ) {
+ if (!this.castleFlags[c][castleSide]) continue;
+ // If this code is reached, rooks and king are on initial position
+
+ const rookPos = this.INIT_COL_ROOK[c][castleSide];
+ if (this.getColor(x, rookPos) != c)
+ // Rook is here but changed color
+ continue;
+
+ // Nothing on the path of the king ?
+ const finDist = finalSquares[castleSide][0] - y;
+ let step = finDist / Math.max(1, Math.abs(finDist));
+ for (let i = y; i != finalSquares[castleSide][0]; i += step) {
+ if (
+ this.board[x][i] != V.EMPTY &&
+ // NOTE: next check is enough, because of chessboard constraints
+ (this.getColor(x, i) != c ||
+ ![V.KING, V.ROOK].includes(this.getPiece(x, i)))
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // Nothing on the path to the rook?
+ step = castleSide == 0 ? -1 : 1;
+ for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step) {
+ if (this.board[x][i] != V.EMPTY) continue castlingCheck;
+ }
+
+ // Nothing on final squares, except maybe king and castling rook?
+ for (i = 0; i < 2; i++) {
+ if (
+ this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
+ this.getPiece(x, finalSquares[castleSide][i]) != V.KING &&
+ finalSquares[castleSide][i] != rookPos
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // If this code is reached, castle is valid
+ moves.push(
+ new Move({
+ appear: [
+ new PiPo({ x: x, y: finalSquares[castleSide][0], p: V.KING, c: c }),
+ new PiPo({ x: x, y: finalSquares[castleSide][1], p: V.ROOK, c: c })
+ ],
+ vanish: [
+ new PiPo({ x: x, y: y, p: V.KING, c: c }),
+ new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c })
+ ],
+ end:
+ Math.abs(y - rookPos) <= 2
+ ? { x: x, y: rookPos }
+ : { x: x, y: y + 2 * (castleSide == 0 ? -1 : 1) }
+ })
+ );
+ }
+
+ return moves;
+ }
+
// TODO: appear/vanish description of a move is too verbose for Benedict.
// => Would need a new "flipped" array, to be passed in Game.vue...
getPotentialMovesFrom([x, y]) {
return moves;
}
- getPotentialPawnMoves([x, y]) {
- const color = this.getColor(x, y);
- let moves = [];
- const sizeY = V.size.y;
- const shift = color == "w" ? -1 : 1;
- const startRank = color == "w" ? sizeY - 2 : 1;
- const firstRank = color == "w" ? sizeY - 1 : 0;
- const lastRank = color == "w" ? 0 : sizeY - 1;
-
- if (x + shift != lastRank) {
- // Normal moves
- if (this.board[x + shift][y] == V.EMPTY) {
- moves.push(this.getBasicMove([x, y], [x + shift, y]));
- if (
- [startRank, firstRank].includes(x) &&
- this.board[x + 2 * shift][y] == V.EMPTY
- ) {
- // Two squares jump
- moves.push(this.getBasicMove([x, y], [x + 2 * shift, y]));
- }
- }
- }
- else {
- // Promotion
- let promotionPieces = [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN];
- promotionPieces.forEach(p => {
- // Normal move
- if (this.board[x + shift][y] == V.EMPTY)
- moves.push(
- this.getBasicMove([x, y], [x + shift, y], { c: color, p: p })
- );
- });
- }
-
- // No en passant here
+ canTake(sq1, sq2) {
+ return false; //captures handled separately
+ }
+ getPotentialPawnMoves([x, y]) {
+ let moves = super.getPotentialPawnMoves([x, y]);
// Add "zen" captures
Array.prototype.push.apply(moves, this.findCaptures([x, y]));
-
return moves;
}
insert or ignore into Variants (name,description) values
('Alice', 'Both sides of the mirror'),
+ ('Allmate', 'Mate any piece'),
('Antiking', 'Keep antiking in check'),
('Antimatter', 'Dangerous collisions'),
('Atomic', 'Explosive captures'),